1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package it;
18
19 import com.atlassian.jira.nimblefunctests.annotation.JiraBuildNumberDependent;
20 import com.atlassian.jira.rest.client.IntegrationTestUtil;
21 import com.atlassian.jira.rest.client.TestUtil;
22 import com.atlassian.jira.rest.client.api.RestClientException;
23 import com.atlassian.jira.rest.client.api.SearchRestClient;
24 import com.atlassian.jira.rest.client.api.domain.BasicPriority;
25 import com.atlassian.jira.rest.client.api.domain.BasicProject;
26 import com.atlassian.jira.rest.client.api.domain.BasicVotes;
27 import com.atlassian.jira.rest.client.api.domain.BasicWatchers;
28 import com.atlassian.jira.rest.client.api.domain.Comment;
29 import com.atlassian.jira.rest.client.api.domain.EntityHelper;
30 import com.atlassian.jira.rest.client.api.domain.Issue;
31 import com.atlassian.jira.rest.client.api.domain.IssueLink;
32 import com.atlassian.jira.rest.client.api.domain.IssueLinkType;
33 import com.atlassian.jira.rest.client.api.domain.SearchResult;
34 import com.atlassian.jira.rest.client.api.domain.TimeTracking;
35 import com.atlassian.jira.rest.client.api.domain.Version;
36 import com.atlassian.jira.rest.client.api.domain.Worklog;
37 import com.atlassian.jira.rest.client.internal.json.TestConstants;
38 import com.atlassian.jira.rest.client.test.matchers.AddressableEntityMatchers;
39 import com.atlassian.jira.rest.client.test.matchers.NamedEntityMatchers;
40 import com.google.common.collect.ImmutableSet;
41 import com.google.common.collect.Iterables;
42 import com.google.common.collect.Sets;
43 import org.hamcrest.collection.IsIterableContainingInOrder;
44 import org.junit.Before;
45 import org.junit.Test;
46
47 import javax.ws.rs.core.Response;
48 import java.lang.reflect.InvocationTargetException;
49 import java.util.Set;
50
51 import static com.atlassian.jira.nimblefunctests.annotation.LongCondition.LESS_THAN;
52 import static com.atlassian.jira.rest.client.IntegrationTestUtil.resolveURI;
53 import static com.atlassian.jira.rest.client.TestUtil.assertEmptyIterable;
54 import static com.atlassian.jira.rest.client.TestUtil.toDateTime;
55 import static com.atlassian.jira.rest.client.internal.ServerVersionConstants.BN_JIRA_6_1;
56 import static org.hamcrest.Matchers.allOf;
57 import static org.hamcrest.Matchers.anyOf;
58 import static org.hamcrest.Matchers.hasProperty;
59 import static org.hamcrest.Matchers.is;
60 import static org.hamcrest.Matchers.notNullValue;
61 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
62 import static org.junit.Assert.assertEquals;
63 import static org.junit.Assert.assertNull;
64 import static org.junit.Assert.assertThat;
65
66 public class AsynchronousSearchRestClientTest extends AbstractAsynchronousRestClientTest {
67
68 public static final Set<String> REQUIRED_ISSUE_FIELDS = ImmutableSet.of("summary", "issuetype", "created", "updated",
69 "project", "status");
70
71 private static boolean alreadyRestored;
72
73 @Before
74 public void setup() {
75 if (!alreadyRestored) {
76 IntegrationTestUtil.restoreAppropriateJiraData(TestConstants.DEFAULT_JIRA_DUMP_FILE, administration);
77 alreadyRestored = true;
78 }
79 }
80
81 @Test
82 public void testJqlSearch() {
83 final SearchResult searchResultForNull = client.getSearchClient().searchJql(null).claim();
84 assertEquals(11, searchResultForNull.getTotal());
85
86 final SearchResult searchResultForReporterWseliga = client.getSearchClient().searchJql("reporter=wseliga").claim();
87 assertEquals(1, searchResultForReporterWseliga.getTotal());
88 }
89
90 @Test
91 public void testJqlSearchWithStartAt() {
92 final int maxResults = 3;
93
94
95 final SearchResult searchResultFrom0 = client.getSearchClient().searchJql(null, maxResults, 0, null).claim();
96 final Issue secondIssueFromFirstSearch = Iterables.get(searchResultFrom0.getIssues(), 1);
97
98
99 final SearchResult searchResultFrom1 = client.getSearchClient().searchJql(null, maxResults, 1, null).claim();
100 final Issue firstIssueFromSecondSearch = Iterables.get(searchResultFrom1.getIssues(), 0);
101
102 assertEquals(secondIssueFromFirstSearch, firstIssueFromSecondSearch);
103 }
104
105 @Test
106 public void testJqlSearchWithNullStartAtShouldUseDefault0ForStartAtAndPreserveMaxResults() {
107 final int maxResults = 21;
108 final SearchResult searchResult = client.getSearchClient().searchJql(null, maxResults, null, null).claim();
109 assertEquals(0, searchResult.getStartIndex());
110 assertEquals(maxResults, searchResult.getMaxResults());
111 }
112
113 @Test
114 public void testJqlSearchWithNullMaxResultsShouldUseDefault50ForMaxResultsAndPreserveStartAt() {
115 final int startAt = 7;
116 final SearchResult searchResult = client.getSearchClient().searchJql(null, null, startAt, null).claim();
117 assertEquals(50, searchResult.getMaxResults());
118 assertEquals(startAt, searchResult.getStartIndex());
119 }
120
121 @Test
122 public void testJqlSearchWithNullStartAtAndMaxResultsShouldUseAsDefault0ForStartIndexAnd50ForMaxResults() {
123 final SearchResult searchResult = client.getSearchClient().searchJql(null, null, null, null).claim();
124 assertEquals(50, searchResult.getMaxResults());
125 assertEquals(0, searchResult.getStartIndex());
126 }
127
128 @Test
129 public void testJqlSearchAsAnonymous() {
130 setAnonymousMode();
131 final SearchResult searchResultForNull = client.getSearchClient().searchJql(null).claim();
132 assertEquals(3, searchResultForNull.getTotal());
133
134 final SearchResult searchResultForReporterWseliga = client.getSearchClient().searchJql("reporter=wseliga").claim();
135 assertEquals(0, searchResultForReporterWseliga.getTotal());
136 }
137
138 @Test
139 public void testJqlSearchWithPaging() {
140 final SearchResult searchResultForNull = client.getSearchClient().searchJql(null, 3, 3, null).claim();
141 assertEquals(11, searchResultForNull.getTotal());
142 assertEquals(3, Iterables.size(searchResultForNull.getIssues()));
143 assertEquals(3, searchResultForNull.getStartIndex());
144 assertEquals(3, searchResultForNull.getMaxResults());
145
146 final SearchResult search2 = client.getSearchClient().searchJql("assignee is not EMPTY", 2, 1, null).claim();
147 assertEquals(11, search2.getTotal());
148 assertEquals(2, Iterables.size(search2.getIssues()));
149 assertEquals("TST-6", Iterables.get(search2.getIssues(), 0).getKey());
150 assertEquals("TST-5", Iterables.get(search2.getIssues(), 1).getKey());
151 assertEquals(1, search2.getStartIndex());
152 assertEquals(2, search2.getMaxResults());
153
154 setUser1();
155 final SearchResult search3 = client.getSearchClient().searchJql("assignee is not EMPTY", 10, 5, null).claim();
156 assertEquals(10, search3.getTotal());
157 assertEquals(5, Iterables.size(search3.getIssues()));
158 assertEquals(5, search3.getStartIndex());
159 assertEquals(10, search3.getMaxResults());
160 }
161
162 @Test
163 public void testVeryLongJqlWhichWillBePost() {
164 final String longJql = generateVeryLongJql() + " or summary is not empty";
165 final SearchResult searchResultForNull = client.getSearchClient().searchJql(longJql, 3, 6, null).claim();
166 assertEquals(11, searchResultForNull.getTotal());
167 assertEquals(3, Iterables.size(searchResultForNull.getIssues()));
168 assertEquals(6, searchResultForNull.getStartIndex());
169 assertEquals(3, searchResultForNull.getMaxResults());
170 }
171
172 private String generateVeryLongJql() {
173 final String coreJql = "(reporter is not empty OR reporter is empty)";
174 StringBuilder sb = new StringBuilder(coreJql);
175 for (int i = 0; i < 500; i++) {
176 sb.append(" and ").append(coreJql);
177 }
178 return sb.toString();
179 }
180
181 @Test
182 public void testJqlSearchUnescapedCharacter() {
183 TestUtil.assertErrorCode(Response.Status.BAD_REQUEST, new Runnable() {
184 @Override
185 public void run() {
186 client.getSearchClient().searchJql("reporter=a/user/with/slash").claim();
187 }
188 });
189 }
190
191 @JiraBuildNumberDependent(value = BN_JIRA_6_1, condition = LESS_THAN)
192 @Test
193 public void jqlSearchShouldReturnIssueWithDetailsBefore6_1() throws InvocationTargetException, IllegalAccessException {
194 jqlSearchShouldReturnIssueWithDetails("rest/api/2/project/TST");
195 }
196
197 @JiraBuildNumberDependent(value = BN_JIRA_6_1)
198 @Test
199 public void jqlSearchShouldReturnIssueWithDetails() throws InvocationTargetException, IllegalAccessException {
200 jqlSearchShouldReturnIssueWithDetails("rest/api/2/project/10000");
201 }
202
203 private void jqlSearchShouldReturnIssueWithDetails(String projectSelf) {
204 final SearchResult searchResult = client.getSearchClient().searchJql("reporter=wseliga").claim();
205 final Issue issue = Iterables.getOnlyElement(searchResult.getIssues());
206
207 assertEquals("TST-7", issue.getKey());
208 assertEquals(Long.valueOf(10040), issue.getId());
209 assertEquals(resolveURI("rest/api/latest/issue/10040"), issue.getSelf());
210 assertEquals("A task where someone will vote", issue.getSummary());
211 assertNull(issue.getDescription());
212 assertEquals(new BasicPriority(resolveURI("rest/api/2/priority/3"), 3L, "Major"), issue.getPriority());
213 assertThat(issue.getStatus(), allOf(
214 hasProperty("self", is(resolveURI("rest/api/2/status/1"))),
215 hasProperty("id", is(1L)),
216 hasProperty("name", is("Open")),
217 hasProperty("description", is("The issue is open and ready for the assignee to start work on it.")),
218 anyOf(
219 hasProperty("iconUrl", is(resolveURI("images/icons/statuses/open.png"))),
220 hasProperty("iconUrl", is(resolveURI("images/icons/status_open.gif")))
221 )));
222 assertEmptyIterable(issue.getComments());
223 assertEmptyIterable(issue.getComponents());
224 assertEmptyIterable(issue.getWorklogs());
225 assertEmptyIterable(issue.getSubtasks());
226 assertEmptyIterable(issue.getIssueLinks());
227 assertEmptyIterable(issue.getFixVersions());
228 assertEmptyIterable(issue.getAffectedVersions());
229 assertEmptyIterable(issue.getLabels());
230 assertNull(issue.getDueDate());
231 assertNull(issue.getTimeTracking());
232 assertNull(issue.getResolution());
233 assertNull(issue.getChangelog());
234 assertNull(issue.getAttachments());
235
236 assertEquals(toDateTime("2010-09-22T18:06:32.000"), issue.getUpdateDate());
237 assertEquals(toDateTime("2010-09-22T18:06:32.000"), issue.getCreationDate());
238 assertEquals(IntegrationTestUtil.USER1_FULL, issue.getReporter());
239 assertEquals(IntegrationTestUtil.USER_ADMIN_FULL, issue.getAssignee());
240 assertEquals(new BasicProject(resolveURI(projectSelf), "TST", 10000L, "Test Project"), issue.getProject());
241 assertEquals(new BasicVotes(resolveURI("rest/api/2/issue/TST-7/votes"), 0, false), issue.getVotes());
242 assertEquals(new BasicWatchers(resolveURI("rest/api/2/issue/TST-7/watchers"), false, 0), issue.getWatchers());
243 assertThat(issue.getIssueType(), notNullValue());
244 assertThat(issue.getIssueType().getSelf(), is(resolveURI("rest/api/2/issuetype/3")));
245 assertThat(issue.getIssueType().getId(), is(3L));
246 assertThat(issue.getIssueType().getName(), is("Task"));
247 assertThat(issue.getIssueType().isSubtask(), is(false));
248 assertThat(issue.getIssueType().getDescription(), is("A task that needs to be done."));
249 assertThat(issue.getIssueType().getIconUri(), anyOf(
250 is(resolveURI("images/icons/issuetypes/task.png")),
251 is(resolveURI("images/icons/task.gif")),
252 is(resolveURI("secure/viewavatar?size=xsmall&avatarId=10178&avatarType=issuetype"))
253 ));
254 }
255
256 @Test
257 public void jqlSearchWithAllFieldsRequestedShouldReturnIssueWithAllFields() throws Exception {
258 jqlSearchWithAllFieldsImpl("key=TST-2");
259 }
260
261 @Test
262 public void jqlSearchUsingPostWithAllFieldsRequestedShouldReturnIssueWithAllFields() throws Exception {
263 jqlSearchWithAllFieldsImpl(generateVeryLongJql() + "and key=TST-2");
264 }
265
266 private void jqlSearchWithAllFieldsImpl(String jql) {
267 final ImmutableSet<String> fields = ImmutableSet.of("*all");
268 final SearchResult searchResult = client.getSearchClient().searchJql(jql, null, null, fields).claim();
269 final Issue issue = Iterables.getOnlyElement(searchResult.getIssues());
270
271 assertEquals("TST-2", issue.getKey());
272 assertEquals("Testing attachem2", issue.getSummary());
273 assertEquals(new TimeTracking(0, 0, 145), issue.getTimeTracking());
274 assertThat(issue.getComponents(), NamedEntityMatchers.entitiesWithNames("Component A", "Component B"));
275
276
277 final Iterable<Comment> comments = issue.getComments();
278 assertEquals(3, Iterables.size(comments));
279 assertEquals("a comment viewable only by jira-users", Iterables.getLast(comments).getBody());
280
281
282 final Iterable<Worklog> worklogs = issue.getWorklogs();
283 assertThat(worklogs, AddressableEntityMatchers.entitiesWithSelf(
284 resolveURI("rest/api/2/issue/10010/worklog/10010"),
285 resolveURI("rest/api/2/issue/10010/worklog/10011"),
286 resolveURI("rest/api/2/issue/10010/worklog/10012"),
287 resolveURI("rest/api/2/issue/10010/worklog/10020"),
288 resolveURI("rest/api/2/issue/10010/worklog/10021")
289 ));
290
291 final Worklog actualWorklog = Iterables.getLast(worklogs);
292 final Worklog expectedWorklog = new Worklog(resolveURI("rest/api/2/issue/10010/worklog/10021"),
293 resolveURI("rest/api/latest/issue/10010"), IntegrationTestUtil.USER_ADMIN, IntegrationTestUtil.USER_ADMIN,
294 "Another work for 7 min", toDateTime("2010-08-27T15:00:02.104"), toDateTime("2010-08-27T15:00:02.104"),
295 toDateTime("2010-08-27T14:59:00.000"), 7, null);
296 assertEquals(expectedWorklog, actualWorklog);
297
298
299 assertThat(issue.getIssueLinks(), IsIterableContainingInOrder.contains(
300 new IssueLink("TST-1", resolveURI("rest/api/2/issue/10000"), new IssueLinkType("Duplicate", "duplicates", IssueLinkType.Direction.OUTBOUND)),
301 new IssueLink("TST-1", resolveURI("rest/api/2/issue/10000"), new IssueLinkType("Duplicate", "is duplicated by", IssueLinkType.Direction.INBOUND))
302 ));
303
304
305 final Version actualFixVersion = Iterables.getOnlyElement(issue.getFixVersions());
306 final Version expectedFixVersion = new Version(resolveURI("rest/api/2/version/10000"), 10000L, "1.1", "Some version", false, false, toDateTime("2010-08-25T00:00:00.000"));
307 assertEquals(expectedFixVersion, actualFixVersion);
308
309
310 assertThat(issue.getAffectedVersions(), IsIterableContainingInOrder.contains(
311 new Version(resolveURI("rest/api/2/version/10001"), 10001L, "1", "initial version", false, false, null),
312 new Version(resolveURI("rest/api/2/version/10000"), 10000L, "1.1", "Some version", false, false, toDateTime("2010-08-25T00:00:00.000"))
313 ));
314
315
316 assertNull(issue.getDueDate());
317 assertEquals(toDateTime("2010-08-30T10:49:33.000"), issue.getUpdateDate());
318 assertEquals(toDateTime("2010-07-26T13:29:18.000"), issue.getCreationDate());
319
320
321 final Iterable<String> attachmentsNames = EntityHelper.toFileNamesList(issue.getAttachments());
322 assertThat(attachmentsNames, containsInAnyOrder("10000_thumb_snipe.jpg", "Admal pompa ciepła.pdf",
323 "apache-tomcat-5.5.30.zip", "jira_logo.gif", "snipe.png", "transparent-png.png"));
324 }
325
326 @Test
327 public void jqlSearchShouldReturnIssueWithLabelsAndDueDate() throws Exception {
328 final SearchResult searchResult = client.getSearchClient().searchJql("key=TST-1").claim();
329 final Issue issue = Iterables.getOnlyElement(searchResult.getIssues());
330 assertEquals("TST-1", issue.getKey());
331 assertThat(issue.getLabels(), containsInAnyOrder("a", "bcds"));
332 assertEquals(toDateTime("2010-07-05T00:00:00.000"), issue.getDueDate());
333 }
334
335 @Test
336 public void jqlSearchWithMinimalFieldSetShouldReturnParseableIssues() throws Exception {
337 final SearchRestClient searchClient = client.getSearchClient();
338 final SearchResult searchResult = searchClient.searchJql("key=TST-1", null, null, REQUIRED_ISSUE_FIELDS).claim();
339 final Issue issue = Iterables.getOnlyElement(searchResult.getIssues());
340 assertEquals("TST-1", issue.getKey());
341 assertEquals("My sample test", issue.getSummary());
342 assertEquals("Bug", issue.getIssueType().getName());
343 assertEquals(toDateTime("2010-07-23T12:16:56.000"), issue.getCreationDate());
344 assertEquals(toDateTime("2010-08-17T16:36:29.000"), issue.getUpdateDate());
345 assertEquals("Test Project", issue.getProject().getName());
346 assertEquals(Long.valueOf(10000), issue.getId());
347 assertEquals("Open", issue.getStatus().getName());
348
349
350 assertEmptyIterable(issue.getLabels());
351 final Issue fullIssue = client.getIssueClient().getIssue(issue.getKey()).claim();
352 assertThat(fullIssue.getLabels(), containsInAnyOrder("a", "bcds"));
353 }
354
355
356
357
358
359 @Test
360 public void jqlSearchWithoutOneOfRequiredFieldsShouldCauseParserFailure() {
361 final SearchRestClient searchClient = client.getSearchClient();
362
363 for (final String missingField : REQUIRED_ISSUE_FIELDS) {
364 final Set<String> fieldsToRetrieve = Sets.difference(REQUIRED_ISSUE_FIELDS, Sets.newHashSet(missingField));
365
366 try {
367 searchClient.searchJql(null, 1, 0, fieldsToRetrieve).claim();
368 throw new java.lang.AssertionError(String.format(
369 "The above statement should throw exception. fieldsToRetrieve = %s, fields = %s, requiredFields = %s",
370 missingField, fieldsToRetrieve, REQUIRED_ISSUE_FIELDS));
371 } catch (RestClientException e) {
372 final String expectedMessage = String.format(
373 "org.codehaus.jettison.json.JSONException: JSONObject[\"%s\"] not found.", missingField);
374 assertEquals(expectedMessage, e.getMessage());
375 }
376 }
377 }
378 }