PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/jira-project/jira-components/jira-plugins/jira-issue-link-confluence-plugin/src/test/java/com/atlassian/jira/plugin/link/confluence/service/rest/TestConfluenceRestServiceImpl.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 258 lines | 216 code | 37 blank | 5 comment | 0 complexity | 5ac9d7d7d987306f85a3eb1513fb566e MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.plugin.link.confluence.service.rest;
  2. import com.atlassian.applinks.api.ApplicationId;
  3. import com.atlassian.applinks.api.ApplicationLink;
  4. import com.atlassian.applinks.api.ApplicationLinkRequest;
  5. import com.atlassian.applinks.api.ApplicationLinkRequestFactory;
  6. import com.atlassian.applinks.api.ApplicationLinkResponseHandler;
  7. import com.atlassian.applinks.api.CredentialsRequiredException;
  8. import com.atlassian.applinks.api.event.ApplicationLinksIDChangedEvent;
  9. import com.atlassian.cache.memory.MemoryCacheManager;
  10. import com.atlassian.jira.plugin.link.applinks.RemoteResponse;
  11. import com.atlassian.jira.plugin.link.confluence.ConfluencePage;
  12. import com.atlassian.jira.plugin.link.confluence.ConfluenceSearchResult;
  13. import com.atlassian.jira.plugin.link.confluence.ConfluenceSpace;
  14. import com.atlassian.jira.plugin.link.confluence.service.rpc.ConfluenceRpcService;
  15. import com.atlassian.jira.util.SimpleErrorCollection;
  16. import com.atlassian.sal.api.net.Request;
  17. import com.atlassian.sal.api.net.Response;
  18. import com.atlassian.sal.api.net.ResponseException;
  19. import com.google.common.collect.Lists;
  20. import org.junit.After;
  21. import org.junit.Before;
  22. import org.junit.Ignore;
  23. import org.junit.Rule;
  24. import org.junit.Test;
  25. import org.junit.rules.MethodRule;
  26. import org.mockito.Mock;
  27. import org.mockito.junit.MockitoJUnit;
  28. import java.net.URLEncoder;
  29. import java.util.List;
  30. import java.util.UUID;
  31. import static org.hamcrest.MatcherAssert.assertThat;
  32. import static org.hamcrest.Matchers.hasItem;
  33. import static org.hamcrest.Matchers.is;
  34. import static org.hamcrest.Matchers.not;
  35. import static org.hamcrest.Matchers.nullValue;
  36. import static org.mockito.Matchers.any;
  37. import static org.mockito.Matchers.anyString;
  38. import static org.mockito.Mockito.mock;
  39. import static org.mockito.Mockito.times;
  40. import static org.mockito.Mockito.verify;
  41. import static org.mockito.Mockito.verifyNoMoreInteractions;
  42. import static org.mockito.Mockito.when;
  43. public class TestConfluenceRestServiceImpl {
  44. @Rule public MethodRule mockitoRule = MockitoJUnit.rule();
  45. @Mock private ApplicationLinkRequestFactory requestFactory;
  46. @Mock private ApplicationLinkRequest request;
  47. @Mock private ConfluenceRpcService confluenceRpcService;
  48. @Mock private ApplicationLink modernConfluenceInstance;
  49. @Mock private ApplicationLink olderThanConf59Instance;
  50. private final ApplicationId conf5_9_id = new ApplicationId(UUID.randomUUID().toString());
  51. private final ApplicationId conf5_6_id = new ApplicationId(UUID.randomUUID().toString());
  52. private final MemoryCacheManager cacheManager = new MemoryCacheManager();
  53. private ConfluenceRestServiceImpl confluenceRestService;
  54. private static final ConfluencePage PRIVATE_PAGE = new ConfluencePage("restricted-id", "secret-page", "http://example.com/confluence/display/SECRET/super+secret+page");
  55. private static final ConfluencePage PAGE_ENTITY = new ConfluencePage("page-id", "some-page", "http://example.com/confluence/display/KB/some+page");
  56. private static final ConfluencePage BLOG_ENTITY = new ConfluencePage("blog-id", "some-blog", "http://example.com/confluence/display/KB/2017/01/25/some+blog");
  57. private static final List<ConfluenceSpace> FILLED_SPACE_LIST = Lists.newArrayList(
  58. new ConfluenceSpace("DEMO", "Demo space", "global", "/display/DEMO"),
  59. new ConfluenceSpace("EXAMPLE", "<An> example <script>space", "global", "display/EXAMPLE"),
  60. new ConfluenceSpace("~nihao", "\u4f60\u597d", "personal", "display/~nihao")
  61. );
  62. private static final String FILLED_SEARCH_QUERY = "some";
  63. private static final String FILLED_SPACE_KEY = "fsk";
  64. private static final List<ConfluenceSearchResult> FILLED_SEARCH_RESULTS = Lists.newArrayList(
  65. new ConfluenceSearchResult(PAGE_ENTITY.getPageId(), "page", PAGE_ENTITY.getTitle(), "this is @@@hl@@@some@@@endhl@@@ kind of page...", PAGE_ENTITY.getUrl()),
  66. new ConfluenceSearchResult("12345", "page", "Another page", "@@@hl@@@some@@@endhl@@@ other page", "http://example.com/confluence/display/viewpage.action?pageId=12345")
  67. );
  68. @Before
  69. public void setup() throws CredentialsRequiredException {
  70. confluenceRestService = new ConfluenceRestServiceImpl(confluenceRpcService, cacheManager);
  71. when(modernConfluenceInstance.getId()).thenReturn(conf5_9_id);
  72. when(modernConfluenceInstance.createAuthenticatedRequestFactory()).thenReturn(requestFactory);
  73. when(olderThanConf59Instance.getId()).thenReturn(conf5_6_id);
  74. when(olderThanConf59Instance.createAuthenticatedRequestFactory()).thenReturn(requestFactory);
  75. when(requestFactory.createRequest(any(Request.MethodType.class), anyString()))
  76. .thenReturn(request);
  77. }
  78. @After
  79. public void teardown() {
  80. confluenceRestService.clearCache();
  81. }
  82. @Test
  83. public void getNormalPage() throws Exception {
  84. requestReturns(validResponseOf(PAGE_ENTITY));
  85. RemoteResponse<ConfluencePage> response = confluenceRestService.getPage(modernConfluenceInstance, PAGE_ENTITY.getPageId());
  86. assertThat(response.hasErrors(), is(false));
  87. assertThat(response.getEntity(), is(PAGE_ENTITY));
  88. }
  89. @Test
  90. public void getBlogPost() throws Exception {
  91. requestReturns(validResponseOf(BLOG_ENTITY));
  92. RemoteResponse<ConfluencePage> response = confluenceRestService.getPage(modernConfluenceInstance, BLOG_ENTITY.getPageId());
  93. assertThat(response.hasErrors(), is(false));
  94. assertThat(response.getEntity(), is(BLOG_ENTITY));
  95. }
  96. @Test
  97. public void getNonExistentPage() throws Exception {
  98. requestReturns(error("Not found"));
  99. RemoteResponse<ConfluencePage> response = confluenceRestService.getPage(modernConfluenceInstance, "nonexistent");
  100. assertThat(response.getEntity(), nullValue(ConfluencePage.class));
  101. assertThat(response.hasErrors(), is(true));
  102. assertThat(response.getErrors().getErrorMessages(), hasItem("Not found"));
  103. }
  104. @Test
  105. @Ignore("RAID-351 - It currently delegates to the XMLRPC API, which isn't stubbed here")
  106. public void getSpaces() throws Exception {
  107. requestReturns(validResponseOf(FILLED_SPACE_LIST));
  108. RemoteResponse<List<ConfluenceSpace>> response = confluenceRestService.getSpaces(modernConfluenceInstance);
  109. assertThat(response.hasErrors(), is(false));
  110. assertThat(response.getEntity(), is(not(nullValue())));
  111. assertThat(response.getEntity(), is(FILLED_SPACE_LIST));
  112. }
  113. @Test
  114. // TODO RAID-351: 9/2/17 remove when getSpaces is un-ignored
  115. public void getSpacesDelegatesToXmlRpc() throws Exception {
  116. confluenceRestService.getSpaces(olderThanConf59Instance);
  117. verify(confluenceRpcService).getSpaces(olderThanConf59Instance);
  118. }
  119. @Test
  120. public void searchConstructsAppropriateQueryURL() throws Exception {
  121. requestReturns(validResponseOf(FILLED_SEARCH_RESULTS));
  122. confluenceRestService.search(modernConfluenceInstance, FILLED_SEARCH_QUERY, 12, null);
  123. final String expectedUrl = String.format("rest/api/search?cql=%s&limit=12&expand=body", cqlFor(FILLED_SEARCH_QUERY));
  124. verify(requestFactory).createRequest(Request.MethodType.GET, expectedUrl);
  125. }
  126. @Test
  127. public void searchWithinSpaceConstructsAppropriateQueryURL() throws Exception {
  128. requestReturns(validResponseOf(FILLED_SEARCH_RESULTS));
  129. confluenceRestService.search(modernConfluenceInstance, FILLED_SEARCH_QUERY, 5, FILLED_SPACE_KEY);
  130. final String expectedUrl = String.format("rest/api/search?cql=%s&limit=5&expand=body&cqlcontext=%s",
  131. cqlFor(FILLED_SEARCH_QUERY, FILLED_SPACE_KEY),
  132. URLEncoder.encode("{\"spaceKey\":\"" + FILLED_SPACE_KEY + "\"}", "UTF-8"));
  133. verify(requestFactory).createRequest(Request.MethodType.GET, expectedUrl);
  134. }
  135. @Test
  136. public void searchWithInvalidSpaceValueConstructsAppropriateQueryURL() throws Exception {
  137. requestReturns(validResponseOf(FILLED_SEARCH_RESULTS));
  138. final String query = "a test of empty space key";
  139. final String expectedUrl = String.format("rest/api/search?cql=%s&limit=5&expand=body", cqlFor(query));
  140. confluenceRestService.search(modernConfluenceInstance, query, 5, " ");
  141. verify(requestFactory).createRequest(Request.MethodType.GET, expectedUrl);
  142. }
  143. @Test
  144. public void searchReturnsResultsForValidConf_5_9() throws Exception {
  145. requestReturns(validResponseOf(FILLED_SEARCH_RESULTS));
  146. RemoteResponse<List<ConfluenceSearchResult>> response = confluenceRestService.search(modernConfluenceInstance, FILLED_SEARCH_QUERY, 5, null);
  147. assertThat(response.hasErrors(), is(false));
  148. assertThat(response.getEntity(), is(not(nullValue())));
  149. assertThat(response.getEntity(), is(FILLED_SEARCH_RESULTS));
  150. }
  151. @Test
  152. public void searchDelegatesToRpcForOlderConfVersions() throws Exception {
  153. final Response mockResponse = mock(Response.class);
  154. when(mockResponse.getStatusCode()).thenReturn(404);
  155. requestReturns(error(mockResponse, "The requested Confluence content could not be found"));
  156. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, "spacekey");
  157. verify(confluenceRpcService).search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, "spacekey");
  158. }
  159. @Test
  160. public void searchWillNotAttemptSubsequentRestCallsOnConfVersionsThatDontHaveRest() throws Exception {
  161. final Response mockResponse = mock(Response.class);
  162. when(mockResponse.getStatusCode()).thenReturn(404);
  163. requestReturns(error(mockResponse, "The requested Confluence content could not be found"));
  164. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, null);
  165. verify(request, times(1)).execute(any(ConfluenceRestSearchResponseHandler.class));
  166. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, null);
  167. verifyNoMoreInteractions(request);
  168. }
  169. @Test
  170. public void searchWillAttemptSubsequentRestCallsOnConfVersionsIfCachesAreCleared() throws Exception {
  171. final Response mockResponse = mock(Response.class);
  172. when(mockResponse.getStatusCode()).thenReturn(404);
  173. requestReturns(error(mockResponse, "The requested Confluence content could not be found"));
  174. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, null);
  175. verify(request, times(1)).execute(any(ConfluenceRestSearchResponseHandler.class));
  176. // The confluence instance gets updated, maybe changes the ID, maybe doesn't.
  177. confluenceRestService.onAppLinkIdChangeEvent(new ApplicationLinksIDChangedEvent(olderThanConf59Instance, conf5_6_id));
  178. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, null);
  179. verify(request, times(2)).execute(any(ConfluenceRestSearchResponseHandler.class));
  180. }
  181. @Test
  182. public void searchWillAttemptRestCallsOnDifferentConfVersions() throws Exception {
  183. final Response olderConfResponse = mock(Response.class);
  184. when(olderConfResponse.getStatusCode()).thenReturn(404);
  185. requestReturns(error(olderConfResponse, "The requested Confluence content could not be found"));
  186. confluenceRestService.search(olderThanConf59Instance, FILLED_SEARCH_QUERY, 5, null);
  187. verify(request, times(1)).execute(any(ConfluenceRestSearchResponseHandler.class));
  188. requestReturns(validResponseOf(FILLED_SEARCH_RESULTS));
  189. confluenceRestService.search(modernConfluenceInstance, FILLED_SEARCH_QUERY, 5, null);
  190. verify(request, times(2)).execute(any(ConfluenceRestSearchResponseHandler.class));
  191. }
  192. //
  193. // Test helpers
  194. //
  195. private void requestReturns(Object response) throws ResponseException {
  196. when(request.execute(any(ApplicationLinkResponseHandler.class))).thenReturn(response);
  197. }
  198. private Object validResponseOf(ConfluencePage page) {
  199. return new RemoteResponse<>(page, mock(Response.class));
  200. }
  201. private Object validResponseOf(List things) {
  202. return new RemoteResponse<>(things, mock(Response.class));
  203. }
  204. private Object error(String message) {
  205. return error(mock(Response.class), message);
  206. }
  207. private Object error(Response response, String message) {
  208. final SimpleErrorCollection errors = new SimpleErrorCollection();
  209. errors.addErrorMessage(message);
  210. return new RemoteResponse<ConfluencePage>(null, errors, response);
  211. }
  212. private String cqlFor(String textQuery) throws Exception {
  213. return cqlWithDefaultIgnores(String.format("text ~ \"%s\"", textQuery));
  214. }
  215. private String cqlFor(String textQuery, String spaceKey) throws Exception {
  216. return cqlWithDefaultIgnores(String.format("text ~ \"%s\" AND space = \"%s\"", textQuery, spaceKey));
  217. }
  218. private String cqlWithDefaultIgnores(String cqlQuery) throws Exception {
  219. return URLEncoder.encode(cqlQuery + " AND type NOT IN (attachment,comment)", "UTF-8");
  220. }
  221. }