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