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.functest.framework.UserProfile;
20 import com.atlassian.jira.nimblefunctests.annotation.JiraBuildNumberDependent;
21 import com.atlassian.jira.nimblefunctests.annotation.Restore;
22 import com.atlassian.jira.rest.client.Callback;
23 import com.atlassian.jira.rest.client.IntegrationTestUtil;
24 import com.atlassian.jira.rest.client.IssueRestClient;
25 import com.atlassian.jira.rest.client.NullProgressMonitor;
26 import com.atlassian.jira.rest.client.TestUtil;
27 import com.atlassian.jira.rest.client.domain.Attachment;
28 import com.atlassian.jira.rest.client.domain.BasicUser;
29 import com.atlassian.jira.rest.client.domain.Comment;
30 import com.atlassian.jira.rest.client.domain.Issue;
31 import com.atlassian.jira.rest.client.domain.IssueLink;
32 import com.atlassian.jira.rest.client.domain.IssueLinkType;
33 import com.atlassian.jira.rest.client.domain.Transition;
34 import com.atlassian.jira.rest.client.domain.Worklog;
35 import com.atlassian.jira.rest.client.domain.input.AttachmentInput;
36 import com.atlassian.jira.rest.client.domain.input.FieldInput;
37 import com.atlassian.jira.rest.client.domain.input.LinkIssuesInput;
38 import com.atlassian.jira.rest.client.domain.input.TransitionInput;
39 import com.atlassian.jira.rest.client.internal.ServerVersionConstants;
40 import com.atlassian.jira.rest.client.internal.json.TestConstants;
41 import com.google.common.base.Function;
42 import com.google.common.base.Predicate;
43 import com.google.common.collect.Iterables;
44 import org.apache.commons.io.IOUtils;
45 import org.joda.time.DateTime;
46 import org.junit.Assert;
47 import org.junit.Test;
48
49 import javax.annotation.Nullable;
50 import javax.ws.rs.core.Response;
51 import java.io.ByteArrayInputStream;
52 import java.io.File;
53 import java.io.FileInputStream;
54 import java.io.FileWriter;
55 import java.io.IOException;
56 import java.lang.reflect.InvocationTargetException;
57 import java.lang.reflect.Method;
58 import java.text.NumberFormat;
59 import java.util.Arrays;
60 import java.util.Locale;
61 import java.util.regex.Matcher;
62 import java.util.regex.Pattern;
63
64 import static com.atlassian.jira.rest.client.IntegrationTestUtil.NUMERIC_CUSTOMFIELD_ID;
65 import static com.atlassian.jira.rest.client.IntegrationTestUtil.NUMERIC_CUSTOMFIELD_TYPE;
66 import static com.atlassian.jira.rest.client.IntegrationTestUtil.NUMERIC_CUSTOMFIELD_TYPE_V5;
67 import static com.atlassian.jira.rest.client.IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER;
68 import static com.atlassian.jira.rest.client.IntegrationTestUtil.USER1;
69 import static com.atlassian.jira.rest.client.IntegrationTestUtil.USER_ADMIN;
70 import static com.atlassian.jira.rest.client.IntegrationTestUtil.resolveURI;
71 import static com.atlassian.jira.rest.client.TestUtil.assertErrorCode;
72 import static com.atlassian.jira.rest.client.internal.ServerVersionConstants.BN_JIRA_4_3;
73 import static com.atlassian.jira.rest.client.internal.json.TestConstants.ADMIN_PASSWORD;
74 import static com.atlassian.jira.rest.client.internal.json.TestConstants.ADMIN_USERNAME;
75 import static com.atlassian.jira.rest.client.internal.json.TestConstants.USER1_USERNAME;
76 import static com.atlassian.jira.rest.client.internal.json.TestConstants.USER2_USERNAME;
77 import static org.hamcrest.Matchers.not;
78 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
79 import static org.hamcrest.core.IsCollectionContaining.hasItem;
80 import static org.junit.Assert.*;
81
82
83
84 @SuppressWarnings("ConstantConditions")
85 @Restore(TestConstants.DEFAULT_JIRA_DUMP_FILE)
86 public class JerseyIssueRestClientTest extends AbstractJerseyRestClientTest {
87
88 @Test
89 public void testTransitionWithNumericCustomFieldPolishLocale() throws Exception {
90 final double newValue = 123.45;
91 final FieldInput fieldInput;
92 if (IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER) {
93 fieldInput = new FieldInput(NUMERIC_CUSTOMFIELD_ID, newValue);
94 } else {
95 fieldInput = new FieldInput(NUMERIC_CUSTOMFIELD_ID, NumberFormat.getNumberInstance(new Locale("pl")).format(newValue));
96 }
97 assertTransitionWithNumericCustomField(fieldInput, newValue);
98 }
99
100 @Test
101 public void testTransitionWithNumericCustomFieldEnglishLocale() throws Exception {
102 setUser1();
103 final double newValue = 123.45;
104 final FieldInput fieldInput = new FieldInput(NUMERIC_CUSTOMFIELD_ID,
105 NumberFormat.getNumberInstance(new Locale("pl")).format(newValue));
106
107 assertErrorCode(Response.Status.BAD_REQUEST, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER
108 ? "Operation value must be a number" : ("'" + fieldInput.getValue() + "' is an invalid number"), new Runnable() {
109 @Override
110 public void run() {
111 assertTransitionWithNumericCustomField(fieldInput, newValue);
112 }
113 });
114
115 final FieldInput fieldInput2 = new FieldInput(NUMERIC_CUSTOMFIELD_ID, newValue);
116 assertTransitionWithNumericCustomField(fieldInput2, newValue);
117
118 }
119
120
121 private void assertTransitionWithNumericCustomField(FieldInput fieldInput, Double expectedValue) {
122 final Issue issue = client.getIssueClient().getIssue("TST-1", new NullProgressMonitor());
123 assertNull(issue.getField(NUMERIC_CUSTOMFIELD_ID).getValue());
124 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
125
126 final Transition transitionFound = TestUtil.getTransitionByName(transitions, "Estimate");
127 assertNotNull(transitionFound);
128 assertTrue(Iterables.contains(transitionFound.getFields(),
129 new Transition.Field(NUMERIC_CUSTOMFIELD_ID, false, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ? NUMERIC_CUSTOMFIELD_TYPE_V5 : NUMERIC_CUSTOMFIELD_TYPE)));
130 client.getIssueClient().transition(issue, new TransitionInput(transitionFound.getId(), Arrays.asList(fieldInput),
131 Comment.valueOf("My test comment")), new NullProgressMonitor());
132 final Issue changedIssue = client.getIssueClient().getIssue("TST-1", pm);
133 assertTrue(changedIssue.getField(NUMERIC_CUSTOMFIELD_ID).getValue().equals(expectedValue));
134 }
135
136 @Test
137 public void testTransitionWithNumericCustomFieldAndInteger() throws Exception {
138 final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
139 assertNull(issue.getField(NUMERIC_CUSTOMFIELD_ID).getValue());
140 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
141 Transition transitionFound = TestUtil.getTransitionByName(transitions, "Estimate");
142
143 assertNotNull(transitionFound);
144 assertTrue(Iterables.contains(transitionFound.getFields(),
145 new Transition.Field(NUMERIC_CUSTOMFIELD_ID, false, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ? NUMERIC_CUSTOMFIELD_TYPE_V5 : NUMERIC_CUSTOMFIELD_TYPE)));
146 final double newValue = 123;
147 final FieldInput fieldInput = new FieldInput(NUMERIC_CUSTOMFIELD_ID, newValue);
148 client.getIssueClient().transition(issue.getTransitionsUri(), new TransitionInput(transitionFound.getId(), Arrays.asList(fieldInput),
149 Comment.valueOf("My test comment")), pm);
150 final Issue changedIssue = client.getIssueClient().getIssue("TST-1", pm);
151 assertEquals(newValue, changedIssue.getField(NUMERIC_CUSTOMFIELD_ID).getValue());
152 }
153
154 @Test
155 public void testTransitionWithInvalidNumericField() throws Exception {
156 final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
157 assertNull(issue.getField(NUMERIC_CUSTOMFIELD_ID).getValue());
158 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
159 final Transition transitionFound = TestUtil.getTransitionByName(transitions, "Estimate");
160
161 assertNotNull(transitionFound);
162 assertTrue(Iterables.contains(transitionFound.getFields(),
163 new Transition.Field(NUMERIC_CUSTOMFIELD_ID, false, TESTING_JIRA_5_OR_NEWER ? NUMERIC_CUSTOMFIELD_TYPE_V5 : NUMERIC_CUSTOMFIELD_TYPE)));
164 final FieldInput fieldInput = new FieldInput(NUMERIC_CUSTOMFIELD_ID, "]432jl");
165
166
167 assertErrorCode(Response.Status.BAD_REQUEST, TESTING_JIRA_5_OR_NEWER
168 ? "Operation value must be a number" : "']432jl' nie jest prawid\u0142ow\u0105 liczb\u0105", new Runnable() {
169 @Override
170 public void run() {
171 client.getIssueClient().transition(issue, new TransitionInput(transitionFound.getId(), Arrays.asList(fieldInput),
172 Comment.valueOf("My test comment")), pm);
173 }
174 });
175 }
176
177 @Test
178 public void testTransitionWithNoRoleOrGroup() {
179 Comment comment = Comment.valueOf("My text which I am just adding " + new DateTime());
180 testTransitionImpl(comment);
181 }
182
183 @Test
184 public void testTransitionWithRoleLevel() {
185 Comment comment = Comment.createWithRoleLevel("My text which I am just adding " + new DateTime(), "Users");
186 testTransitionImpl(comment);
187 }
188
189 @Test
190 public void testTransitionWithGroupLevel() {
191 Comment comment = Comment.createWithGroupLevel("My text which I am just adding " + new DateTime(), "jira-users");
192 testTransitionImpl(comment);
193 }
194
195 @Test
196 public void testTransitionWithInvalidRole() {
197 final Comment comment = Comment.createWithRoleLevel("My text which I am just adding " + new DateTime(), "some-fake-role");
198 if (IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER) {
199 assertInvalidCommentInput(comment, "Invalid role level specified.");
200 } else {
201 assertInvalidCommentInput(comment, "Invalid role [some-fake-role]");
202 }
203 }
204
205 @Test
206 public void testTransitionWithInvalidGroup() {
207 final Comment comment = Comment.createWithGroupLevel("My text which I am just adding " + new DateTime(), "some-fake-group");
208 assertInvalidCommentInput(comment, "Group: some-fake-group does not exist.");
209 }
210
211 private void assertInvalidCommentInput(final Comment comment, String expectedErrorMsg) {
212 final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
213 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
214 final Transition transitionFound = TestUtil.getTransitionByName(transitions, "Estimate");
215 final String errorMsg = doesJiraServeCorrectlyErrorMessagesForBadRequestWhileTransitioningIssue()
216 ? expectedErrorMsg : null;
217 assertErrorCode(Response.Status.BAD_REQUEST, errorMsg, new Runnable() {
218 @Override
219 public void run() {
220 client.getIssueClient().transition(issue, new TransitionInput(transitionFound.getId(), comment), pm);
221 }
222 });
223 }
224
225 private void testTransitionImpl(Comment comment) {
226 final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
227 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
228 Transition transitionFound = TestUtil.getTransitionByName(transitions, "Estimate");
229 DateTime now = new DateTime();
230 client.getIssueClient().transition(issue, new TransitionInput(transitionFound.getId(), comment), pm);
231
232 final Issue changedIssue = client.getIssueClient().getIssue("TST-1", pm);
233 final Comment lastComment = Iterables.getLast(changedIssue.getComments());
234 assertEquals(comment.getBody(), lastComment.getBody());
235 assertEquals(USER_ADMIN, lastComment.getAuthor());
236 assertEquals(USER_ADMIN, lastComment.getUpdateAuthor());
237 assertEquals(lastComment.getCreationDate(), lastComment.getUpdateDate());
238 assertTrue(lastComment.getCreationDate().isAfter(now) || lastComment.getCreationDate().isEqual(now));
239 assertEquals(comment.getVisibility(), lastComment.getVisibility());
240 }
241
242 @Test
243 public void testVoteUnvote() {
244 final Issue issue1 = client.getIssueClient().getIssue("TST-1", pm);
245 assertFalse(issue1.getVotes().hasVoted());
246 assertEquals(1, issue1.getVotes().getVotes());
247 final String expectedMessage = isJira5xOrNewer()
248 ? "You cannot vote for an issue you have reported."
249 : "Nie mo\u017cesz g\u0142osowa\u0107 na zadanie kt\u00f3re utworzy\u0142e\u015b.";
250
251
252 assertErrorCode(Response.Status.NOT_FOUND, expectedMessage, new Runnable() {
253 @Override
254 public void run() {
255 client.getIssueClient().vote(issue1.getVotesUri(), pm);
256 }
257 });
258
259
260 final String issueKey = "TST-7";
261 Issue issue = client.getIssueClient().getIssue(issueKey, pm);
262 assertFalse(issue.getVotes().hasVoted());
263 assertEquals(0, issue.getVotes().getVotes());
264
265 client.getIssueClient().vote(issue.getVotesUri(), pm);
266 issue = client.getIssueClient().getIssue(issueKey, pm);
267 assertTrue(issue.getVotes().hasVoted());
268 assertEquals(1, issue.getVotes().getVotes());
269
270 client.getIssueClient().unvote(issue.getVotesUri(), pm);
271 issue = client.getIssueClient().getIssue(issueKey, pm);
272 assertFalse(issue.getVotes().hasVoted());
273 assertEquals(0, issue.getVotes().getVotes());
274
275 setUser2();
276 issue = client.getIssueClient().getIssue(issueKey, pm);
277 assertFalse(issue.getVotes().hasVoted());
278 assertEquals(0, issue.getVotes().getVotes());
279 final Issue finalIssue = issue;
280 assertErrorCode(Response.Status.NOT_FOUND, "Cannot remove a vote for an issue that the user has not already voted for.",
281 new Runnable() {
282 @Override
283 public void run() {
284 client.getIssueClient().unvote(finalIssue.getVotesUri(), pm);
285 }
286 });
287
288
289 issue = client.getIssueClient().getIssue(issueKey, pm);
290 assertFalse(issue.getVotes().hasVoted());
291 assertEquals(0, issue.getVotes().getVotes());
292 client.getIssueClient().vote(issue.getVotesUri(), pm);
293 issue = client.getIssueClient().getIssue(issueKey, pm);
294 assertTrue(issue.getVotes().hasVoted());
295 assertEquals(1, issue.getVotes().getVotes());
296
297 setClient(ADMIN_USERNAME, ADMIN_PASSWORD);
298 client.getIssueClient().vote(issue.getVotesUri(), pm);
299 issue = client.getIssueClient().getIssue(issueKey, pm);
300 assertTrue(issue.getVotes().hasVoted());
301 assertEquals(2, issue.getVotes().getVotes());
302 }
303
304 @Test
305 public void testWatchUnwatch() {
306 final IssueRestClient issueClient = client.getIssueClient();
307 final Issue issue1 = issueClient.getIssue("TST-1", pm);
308
309 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), not(hasItem(USER_ADMIN)));
310
311 issueClient.watch(issue1.getWatchers().getSelf(), pm);
312 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), hasItem(USER_ADMIN));
313
314 issueClient.unwatch(issue1.getWatchers().getSelf(), pm);
315 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), not(hasItem(USER_ADMIN)));
316
317 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), hasItem(USER1));
318 issueClient.removeWatcher(issue1.getWatchers().getSelf(), USER1.getName(), pm);
319 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), not(hasItem(USER1)));
320 issueClient.addWatcher(issue1.getWatchers().getSelf(), USER1.getName(), pm);
321 Assert.assertThat(issueClient.getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), hasItem(USER1));
322 }
323
324 @Test
325 public void testRemoveWatcherUnauthorized() {
326 final IssueRestClient issueClient = client.getIssueClient();
327 final Issue issue1 = issueClient.getIssue("TST-1", pm);
328 issueClient.watch(issue1.getWatchers().getSelf(), pm);
329
330 setUser1();
331 final IssueRestClient issueClient2 = client.getIssueClient();
332 assertErrorCode(Response.Status.UNAUTHORIZED,
333 "User 'wseliga' is not allowed to remove watchers from issue 'TST-1'", new Runnable() {
334 @Override
335 public void run() {
336 issueClient2.removeWatcher(issue1.getWatchers().getSelf(), ADMIN_USERNAME, pm);
337 }
338 });
339 }
340
341
342 @Test
343 public void testWatchAlreadyWatched() {
344 setUser1();
345 final IssueRestClient issueClient = client.getIssueClient();
346 final Issue issue = issueClient.getIssue("TST-1", pm);
347 Assert.assertThat(client.getIssueClient().getWatchers(issue.getWatchers().getSelf(), pm).getUsers(), hasItem(USER1));
348
349 issueClient.watch(issue.getWatchers().getSelf(), pm);
350 Assert.assertThat(client.getIssueClient().getWatchers(issue.getWatchers().getSelf(), pm).getUsers(), hasItem(USER1));
351 }
352
353 @Test
354 public void testAddWatcherUnauthorized() {
355 final IssueRestClient issueClient = client.getIssueClient();
356 final Issue issue1 = issueClient.getIssue("TST-1", pm);
357 issueClient.addWatcher(issue1.getWatchers().getSelf(), USER1_USERNAME, pm);
358 assertThat(client.getIssueClient().getWatchers(issue1.getWatchers().getSelf(), pm).getUsers(), hasItem(USER1));
359
360 setUser1();
361 assertTrue(client.getIssueClient().getIssue("TST-1", pm).getWatchers().isWatching());
362 String expectedErrorMsg = isJraDev3516Fixed() ? ("User '" + USER1_USERNAME
363 + "' is not allowed to add watchers to issue 'TST-1'") : null;
364 assertErrorCode(Response.Status.UNAUTHORIZED, expectedErrorMsg, new Runnable() {
365 @Override
366 public void run() {
367 client.getIssueClient().addWatcher(issue1.getWatchers().getSelf(), ADMIN_USERNAME, pm);
368 }
369 });
370 }
371
372 private boolean isJraDev3516Fixed() {
373 return client.getMetadataClient().getServerInfo(pm).getBuildNumber() >= BN_JIRA_4_3;
374 }
375
376 @Test
377 public void testAddWatcherWhoDoesNotHaveViewIssuePermissions() {
378 final IssueRestClient issueClient = client.getIssueClient();
379 final String issueKey = "RST-1";
380 final Issue issue1 = issueClient.getIssue(issueKey, pm);
381 final String expectedErrorMessage;
382
383 if (isJira5xOrNewer()) {
384 expectedErrorMessage = "The user \"" + USER2_USERNAME +"\" does not have permission to view this issue."
385 + " This user will not be added to the watch list.";
386 }
387 else if (isJira4x3OrNewer()) {
388 expectedErrorMessage = "User '" + ADMIN_USERNAME + "' is not allowed to add watchers to issue '" + issueKey + "'";
389 }
390 else {
391 expectedErrorMessage = "com.sun.jersey.api.client.UniformInterfaceException: Client response status: 401";
392 }
393
394 assertErrorCode(Response.Status.UNAUTHORIZED, expectedErrorMessage,
395 new Runnable() {
396 @Override
397 public void run() {
398 issueClient.addWatcher(issue1.getWatchers().getSelf(), USER2_USERNAME, pm);
399 }
400 });
401 }
402
403 @JiraBuildNumberDependent(BN_JIRA_4_3)
404 @Test
405 public void testLinkIssuesWithRoleLevel() {
406 testLinkIssuesImpl(Comment.createWithRoleLevel("A comment about linking", "Administrators"));
407 }
408
409 @JiraBuildNumberDependent(BN_JIRA_4_3)
410 @Test
411 public void testLinkIssuesWithGroupLevel() {
412 testLinkIssuesImpl(Comment.createWithGroupLevel("A comment about linking", "jira-administrators"));
413 }
414
415 @JiraBuildNumberDependent(BN_JIRA_4_3)
416 @Test
417 public void testLinkIssuesWithSimpleComment() {
418 testLinkIssuesImpl(Comment.valueOf("A comment about linking"));
419 }
420
421 @JiraBuildNumberDependent(BN_JIRA_4_3)
422 @Test
423 public void testLinkIssuesWithoutComment() {
424 testLinkIssuesImpl(null);
425 }
426
427 @JiraBuildNumberDependent(BN_JIRA_4_3)
428 @Test
429 public void testLinkIssuesWithInvalidParams() {
430 assertErrorCode(Response.Status.NOT_FOUND,
431 IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ? "Issue Does Not Exist" : "The issue no longer exists.", new Runnable() {
432 @Override
433 public void run() {
434 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "FAKEKEY-1", "Duplicate", null), pm);
435 }
436 });
437
438 assertErrorCode(Response.Status.NOT_FOUND, "No issue link type with name 'NonExistingLinkType' found.", new Runnable() {
439 @Override
440 public void run() {
441 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "TST-6", "NonExistingLinkType", null), pm);
442 }
443 });
444
445 setUser1();
446 final String optionalDot = isJira5xOrNewer() ? "." : "";
447 assertErrorCode(Response.Status.NOT_FOUND, "You do not have the permission to see the specified issue" + optionalDot, new Runnable() {
448 @Override
449 public void run() {
450 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "RST-1", "Duplicate", null), pm);
451 }
452 });
453 assertErrorCode(Response.Status.BAD_REQUEST, "Failed to create comment for issue 'TST-6'\nYou are currently not a member of the project role: Administrators.", new Runnable() {
454 @Override
455 public void run() {
456 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "TST-6", "Duplicate",
457 Comment.createWithRoleLevel("my body", "Administrators")), pm);
458 }
459 });
460 assertErrorCode(Response.Status.BAD_REQUEST, "You are currently not a member of the group: jira-administrators.", new Runnable() {
461 @Override
462 public void run() {
463 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "TST-6", "Duplicate",
464 Comment.createWithGroupLevel("my body", "jira-administrators")), pm);
465 }
466 });
467 assertErrorCode(Response.Status.BAD_REQUEST, "Group: somefakegroup does not exist.", new Runnable() {
468 @Override
469 public void run() {
470 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "TST-6", "Duplicate",
471 Comment.createWithGroupLevel("my body", "somefakegroup")), pm);
472 }
473 });
474
475
476 setUser2();
477 assertErrorCode(Response.Status.UNAUTHORIZED, "No Link Issue Permission for issue 'TST-7'", new Runnable() {
478 @Override
479 public void run() {
480 client.getIssueClient().linkIssue(new LinkIssuesInput("TST-7", "TST-6", "Duplicate", null), pm);
481 }
482 });
483
484 }
485
486
487 private void testLinkIssuesImpl(@Nullable Comment commentInput) {
488 final IssueRestClient issueClient = client.getIssueClient();
489 final Issue originalIssue = issueClient.getIssue("TST-7", pm);
490 int origNumComments = Iterables.size(originalIssue.getComments());
491 assertFalse(originalIssue.getIssueLinks().iterator().hasNext());
492
493 issueClient.linkIssue(new LinkIssuesInput("TST-7", "TST-6", "Duplicate", commentInput), pm);
494
495 final Issue linkedIssue = issueClient.getIssue("TST-7", pm);
496 assertEquals(1, Iterables.size(linkedIssue.getIssueLinks()));
497 final IssueLink addedLink = linkedIssue.getIssueLinks().iterator().next();
498 assertEquals("Duplicate", addedLink.getIssueLinkType().getName());
499 assertEquals("TST-6", addedLink.getTargetIssueKey());
500 assertEquals(IssueLinkType.Direction.OUTBOUND, addedLink.getIssueLinkType().getDirection());
501
502 final int expectedNumComments = commentInput != null ? origNumComments + 1 : origNumComments;
503 assertEquals(expectedNumComments, Iterables.size(linkedIssue.getComments()));
504 if (commentInput != null) {
505 final Comment comment = linkedIssue.getComments().iterator().next();
506 assertEquals(commentInput.getBody(), comment.getBody());
507 assertEquals(USER_ADMIN, comment.getAuthor());
508 assertEquals(commentInput.getVisibility(), comment.getVisibility());
509 } else {
510 assertFalse(linkedIssue.getComments().iterator().hasNext());
511 }
512
513
514 final Issue targetIssue = issueClient.getIssue("TST-6", pm);
515 final IssueLink targetLink = targetIssue.getIssueLinks().iterator().next();
516 assertEquals(IssueLinkType.Direction.INBOUND, targetLink.getIssueLinkType().getDirection());
517 assertEquals("Duplicate", targetLink.getIssueLinkType().getName());
518 }
519
520 private boolean doesJiraSupportAddingAttachment() {
521 return client.getMetadataClient().getServerInfo(pm).getBuildNumber() >= BN_JIRA_4_3;
522 }
523
524 private boolean doesJiraServeCorrectlyErrorMessagesForBadRequestWhileTransitioningIssue() {
525 return client.getMetadataClient().getServerInfo(pm).getBuildNumber() >= BN_JIRA_4_3;
526 }
527
528 @Test
529 public void testAddAttachment() throws IOException {
530 if (!doesJiraSupportAddingAttachment()) {
531 return;
532 }
533 final IssueRestClient issueClient = client.getIssueClient();
534 final Issue issue = issueClient.getIssue("TST-3", pm);
535 assertFalse(issue.getAttachments().iterator().hasNext());
536
537 String str = "Wojtek";
538 final String filename1 = "my-test-file";
539 issueClient.addAttachment(pm, issue.getAttachmentsUri(), new ByteArrayInputStream(str.getBytes("UTF-8")), filename1);
540 final String filename2 = "my-picture.png";
541 issueClient.addAttachment(pm, issue.getAttachmentsUri(), JerseyIssueRestClientTest.class.getResourceAsStream("/attachment-test/transparent-png.png"), filename2);
542
543 final Issue issueWithAttachments = issueClient.getIssue("TST-3", pm);
544 final Iterable<Attachment> attachments = issueWithAttachments.getAttachments();
545 assertEquals(2, Iterables.size(attachments));
546 final Iterable<String> attachmentsNames = Iterables.transform(attachments, new Function<Attachment, String>() {
547 @Override
548 public String apply(@Nullable Attachment from) {
549 return from.getFilename();
550 }
551 });
552 assertThat(attachmentsNames, containsInAnyOrder(filename1, filename2));
553 final Attachment pictureAttachment = Iterables.find(attachments, new Predicate<Attachment>() {
554 @Override
555 public boolean apply(@Nullable Attachment input) {
556 return filename2.equals(input.getFilename());
557 }
558 });
559
560
561
562 assertTrue(
563 IOUtils.contentEquals(JerseyIssueRestClientTest.class.getResourceAsStream("/attachment-test/transparent-png.png"),
564 issueClient.getAttachment(pm, pictureAttachment.getContentUri())));
565 }
566
567 @Test
568 public void testAddAttachments() throws IOException {
569 if (!doesJiraSupportAddingAttachment()) {
570 return;
571 }
572 final IssueRestClient issueClient = client.getIssueClient();
573 final Issue issue = issueClient.getIssue("TST-4", pm);
574 assertFalse(issue.getAttachments().iterator().hasNext());
575
576 final AttachmentInput[] attachmentInputs = new AttachmentInput[3];
577 for (int i = 1; i <= 3; i++) {
578 attachmentInputs[i - 1] = new AttachmentInput("my-test-file-" + i + ".txt", new ByteArrayInputStream(("content-of-the-file-" + i).getBytes("UTF-8")));
579 }
580 issueClient.addAttachments(pm, issue.getAttachmentsUri(), attachmentInputs);
581
582 final Issue issueWithAttachments = issueClient.getIssue("TST-4", pm);
583 final Iterable<Attachment> attachments = issueWithAttachments.getAttachments();
584 assertEquals(3, Iterables.size(attachments));
585 Pattern pattern = Pattern.compile("my-test-file-(\\d)\\.txt");
586 for (Attachment attachment : attachments) {
587 assertTrue(pattern.matcher(attachment.getFilename()).matches());
588 final Matcher matcher = pattern.matcher(attachment.getFilename());
589 matcher.find();
590 final String interfix = matcher.group(1);
591 assertTrue(IOUtils.contentEquals(new ByteArrayInputStream(("content-of-the-file-" + interfix).getBytes("UTF-8")),
592 issueClient.getAttachment(pm, attachment.getContentUri())));
593
594 }
595 }
596
597 @Test
598 public void testAddFileAttachments() throws IOException {
599 if (!doesJiraSupportAddingAttachment()) {
600 return;
601 }
602 final IssueRestClient issueClient = client.getIssueClient();
603 final Issue issue = issueClient.getIssue("TST-5", pm);
604 assertFalse(issue.getAttachments().iterator().hasNext());
605
606 final File tempFile = File.createTempFile("jim-integration-test", ".txt");
607 tempFile.deleteOnExit();
608 FileWriter writer = new FileWriter(tempFile);
609 writer.write("This is the content of my file which I am going to upload to JIRA for testing.");
610 writer.close();
611 issueClient.addAttachments(pm, issue.getAttachmentsUri(), tempFile);
612
613 final Issue issueWithAttachments = issueClient.getIssue("TST-5", pm);
614 final Iterable<Attachment> attachments = issueWithAttachments.getAttachments();
615 assertEquals(1, Iterables.size(attachments));
616 assertTrue(IOUtils.contentEquals(new FileInputStream(tempFile),
617 issueClient.getAttachment(pm, attachments.iterator().next().getContentUri())));
618 }
619
620 private void setUserLanguageToEnUk() {
621 changeUserLanguageByValueOrName("en_UK", "angielski (UK)");
622 }
623
624 private void changeUserLanguageByValueOrName(String value, String name) {
625 final UserProfile userProfile = navigation.userProfile();
626 boolean fallbackToChangeByValue = false;
627 try {
628 Method changeUserLanguageByValue = userProfile.getClass().getMethod("changeUserLanguageByValue", String.class);
629 changeUserLanguageByValue.invoke(userProfile, value);
630 } catch (NoSuchMethodException e) {
631
632 fallbackToChangeByValue = true;
633 } catch (InvocationTargetException e) {
634 fallbackToChangeByValue = true;
635 } catch (IllegalAccessException e) {
636 fallbackToChangeByValue = true;
637 }
638
639 if (fallbackToChangeByValue) {
640 userProfile.changeUserLanguage(name);
641 }
642 }
643
644 private void addUserThenExecuteCallbackAndRemoveUser(String username, Callback executeAsNewUser) {
645 setUserLanguageToEnUk();
646 administration.usersAndGroups().addUser(username, username, username, username + "@localhost");
647 navigation.login(username);
648 executeAsNewUser.execute();
649 navigation.login("admin");
650 administration.usersAndGroups().deleteUser(username);
651 }
652
653 @Test
654 public void testFetchingIssueWithWorklogWhenAuthorIsDeleted() {
655 final String issueKey = "ANONEDIT-1";
656 final String testUser = "testusertoremove";
657
658 addUserThenExecuteCallbackAndRemoveUser(testUser, new Callback() {
659 @Override
660 public void execute() {
661 navigation.issue().logWork(issueKey, "3m");
662 }
663 });
664
665
666 final Issue issue = client.getIssueClient().getIssue(issueKey, pm);
667 final Worklog worklog = issue.getWorklogs().iterator().next();
668 assertNotNull(worklog);
669 final BasicUser author = worklog.getAuthor();
670 assertNotNull(author);
671 assertTrue(author.isSelfUriIncomplete());
672 }
673
674
675 @JiraBuildNumberDependent(ServerVersionConstants.BN_JIRA_4_4)
676 @Test
677 public void testFetchingIssueWithCommentWhenAuthorIsDeleted() {
678 final String issueKey = "ANONEDIT-1";
679 final String testUser = "testusertoremove";
680
681 addUserThenExecuteCallbackAndRemoveUser(testUser, new Callback() {
682 @Override
683 public void execute() {
684 navigation.issue().addComment(issueKey, "Comment");
685 }
686 });
687
688
689 final Issue issue = client.getIssueClient().getIssue(issueKey, pm);
690 final Comment comment = issue.getComments().iterator().next();
691 assertNotNull(comment);
692 final BasicUser author = comment.getAuthor();
693 assertNotNull(author);
694 assertEquals(resolveURI("rest/api/" + (isJira5xOrNewer() ? "2" : "latest") + "/user?username=" + testUser), author.getSelf());
695 }
696
697 @Test
698 public void testFetchingUnassignedIssue() {
699 administration.generalConfiguration().setAllowUnassignedIssues(true);
700 assertEquals(USER_ADMIN, client.getIssueClient().getIssue("TST-5", pm).getAssignee());
701
702 setUserLanguageToEnUk();
703 navigation.issue().unassignIssue("TST-5", "unassigning issue");
704
705
706
707
708 assertNull(client.getIssueClient().getIssue("TST-5", pm).getAssignee());
709 }
710
711 @Test
712 public void testFetchingIssueWithAnonymousComment() {
713 setUserLanguageToEnUk();
714 administration.permissionSchemes().scheme("Anonymous Permission Scheme").grantPermissionToGroup(15, "");
715 assertEquals(USER_ADMIN, client.getIssueClient().getIssue("TST-5", pm).getAssignee());
716 navigation.logout();
717 navigation.issue().addComment("ANNON-1", "my nice comment");
718 final Issue issue = client.getIssueClient().getIssue("ANNON-1", pm);
719 assertEquals(1, Iterables.size(issue.getComments()));
720 final Comment comment = issue.getComments().iterator().next();
721 assertEquals("my nice comment", comment.getBody());
722 if (isJira5xOrNewer()) {
723 assertNotNull(comment.getId());
724 }
725 else {
726 assertNull(comment.getId());
727 }
728 assertNull(comment.getAuthor());
729 assertNull(comment.getUpdateAuthor());
730
731 }
732
733 }