1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package it;
17
18 import com.atlassian.jira.nimblefunctests.annotation.JiraBuildNumberDependent;
19 import com.atlassian.jira.rest.client.IntegrationTestUtil;
20 import com.atlassian.jira.rest.client.api.GetCreateIssueMetadataOptionsBuilder;
21 import com.atlassian.jira.rest.client.api.domain.Attachment;
22 import com.atlassian.jira.rest.client.api.domain.BasicUser;
23 import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
24 import com.atlassian.jira.rest.client.api.domain.ChangelogItem;
25 import com.atlassian.jira.rest.client.api.domain.CimIssueType;
26 import com.atlassian.jira.rest.client.api.domain.CimProject;
27 import com.atlassian.jira.rest.client.api.domain.Comment;
28 import com.atlassian.jira.rest.client.api.domain.FieldType;
29 import com.atlassian.jira.rest.client.api.domain.Issue;
30 import com.atlassian.jira.rest.client.api.domain.OperationLink;
31 import com.atlassian.jira.rest.client.api.domain.Operations;
32 import com.atlassian.jira.rest.client.api.domain.TimeTracking;
33 import com.atlassian.jira.rest.client.api.domain.Transition;
34 import com.atlassian.jira.rest.client.api.domain.Visibility;
35 import com.atlassian.jira.rest.client.api.domain.Votes;
36 import com.atlassian.jira.rest.client.api.domain.Watchers;
37 import com.atlassian.jira.rest.client.api.domain.Worklog;
38 import com.atlassian.jira.rest.client.internal.json.TestConstants;
39 import com.google.common.base.Predicate;
40 import com.google.common.collect.Iterables;
41 import com.google.common.collect.Lists;
42 import org.hamcrest.Matcher;
43 import org.joda.time.DateTime;
44 import org.joda.time.format.ISODateTimeFormat;
45 import org.junit.Before;
46 import org.junit.Test;
47
48 import javax.ws.rs.core.Response;
49 import javax.ws.rs.core.UriBuilder;
50 import java.net.URISyntaxException;
51 import java.util.Collections;
52 import java.util.EnumSet;
53 import java.util.Iterator;
54
55 import static com.atlassian.jira.rest.client.IntegrationTestUtil.USER1;
56 import static com.atlassian.jira.rest.client.IntegrationTestUtil.getUserUri;
57 import static com.atlassian.jira.rest.client.TestUtil.assertErrorCode;
58 import static com.atlassian.jira.rest.client.api.IssueRestClient.Expandos.CHANGELOG;
59 import static com.atlassian.jira.rest.client.api.IssueRestClient.Expandos.OPERATIONS;
60 import static com.atlassian.jira.rest.client.internal.ServerVersionConstants.BN_JIRA_5;
61 import static com.google.common.collect.Iterables.size;
62 import static com.google.common.collect.Iterables.toArray;
63 import static java.util.Collections.singletonList;
64 import static org.hamcrest.Matchers.allOf;
65 import static org.hamcrest.Matchers.anyOf;
66 import static org.hamcrest.Matchers.equalTo;
67 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
68 import static org.hamcrest.Matchers.hasProperty;
69 import static org.hamcrest.Matchers.instanceOf;
70 import static org.hamcrest.Matchers.is;
71 import static org.hamcrest.Matchers.notNullValue;
72 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
73 import static org.junit.Assert.assertEquals;
74 import static org.junit.Assert.assertFalse;
75 import static org.junit.Assert.assertNotNull;
76 import static org.junit.Assert.assertNull;
77 import static org.junit.Assert.assertThat;
78 import static org.junit.Assert.assertTrue;
79
80
81
82
83 @SuppressWarnings("ConstantConditions")
84 public class AsynchronousIssueRestClientReadOnlyTest extends AbstractAsynchronousRestClientTest {
85
86 private static final String REMOVED_USER_NAME = "removed_user";
87 private static final String ISSUE_KEY_WITH_REMOVED_USER_DATA = "ANONEDIT-1";
88
89
90 private final DateTime dateTime = ISODateTimeFormat.dateTimeParser().parseDateTime("2010-08-04T17:46:45.454");
91
92 private static boolean alreadyRestored;
93
94 @Before
95 public void setup() {
96 if (!alreadyRestored) {
97 IntegrationTestUtil.restoreAppropriateJiraData(TestConstants.JIRA_DUMP_WITH_COMMENT_AND_WORKLOG_FROM_REMOVED_USER_FILE, administration);
98 alreadyRestored = true;
99 }
100 }
101
102 @Test
103 public void testGetWatchers() throws Exception {
104 final Issue issue = client.getIssueClient().getIssue("TST-1").claim();
105 final Watchers watchers = client.getIssueClient().getWatchers(issue.getWatchers().getSelf()).claim();
106 assertEquals(1, watchers.getNumWatchers());
107 assertFalse(watchers.isWatching());
108 assertThat(watchers.getUsers(), containsInAnyOrder(USER1));
109 }
110
111 @Test
112 public void testGetWatcherForAnonymouslyAccessibleIssue() {
113 setAnonymousMode();
114 final Issue issue = client.getIssueClient().getIssue("ANNON-1").claim();
115 final Watchers watchers = client.getIssueClient().getWatchers(issue.getWatchers().getSelf()).claim();
116 assertEquals(1, watchers.getNumWatchers());
117 assertFalse(watchers.isWatching());
118 assertTrue("JRADEV-3594 bug!!!", Iterables.isEmpty(watchers.getUsers()));
119
120 assertEquals(new TimeTracking(2700, 2400, null), issue.getTimeTracking());
121 }
122
123 @Test
124 public void testGetIssueWithAnonymouslyCreatedAttachment() {
125 setAnonymousMode();
126 final Issue issue = client.getIssueClient().getIssue("ANONEDIT-1").claim();
127 final Iterator<Attachment> attachmentIterator = issue.getAttachments().iterator();
128 assertTrue(attachmentIterator.hasNext());
129 assertNull(attachmentIterator.next().getAuthor());
130 }
131
132 @Test
133 public void testGetIssueWithAnonymouslyCreatedWorklogEntry() {
134 setAnonymousMode();
135 final Issue issue = client.getIssueClient().getIssue("ANONEDIT-2").claim();
136 final Iterator<Worklog> worklogIterator = issue.getWorklogs().iterator();
137 assertTrue(worklogIterator.hasNext());
138 assertNull(worklogIterator.next().getAuthor());
139 }
140
141
142 private void assertEqualsNoUri(BasicUser expected, BasicUser actual) {
143 assertEquals(expected.getName(), actual.getName());
144 assertEquals(expected.getDisplayName(), actual.getDisplayName());
145 }
146
147
148 @Test
149 @SuppressWarnings("unchecked")
150 public void testGetIssue() throws Exception {
151 final Issue issue = client.getIssueClient().getIssue("TST-1").claim();
152 assertEquals("TST-1", issue.getKey());
153 assertEquals(Long.valueOf(10000), issue.getId());
154 assertTrue(issue.getSelf().toString().startsWith(jiraUri.toString()));
155 assertEqualsNoUri(IntegrationTestUtil.USER_ADMIN, issue.getReporter());
156 assertEqualsNoUri(IntegrationTestUtil.USER_ADMIN, issue.getAssignee());
157
158 assertThat(issue.getLabels(), containsInAnyOrder("a", "bcds"));
159
160 assertEquals(3, size(issue.getComments()));
161
162 final String[] expandosForJira5 = {"renderedFields", "names", "schema", "transitions", "operations", "editmeta", "changelog"};
163 final String[] expandosForJira6_4 = toArray(Lists.asList("versionedRepresentations", expandosForJira5), String.class);
164
165
166 assertThat(issue.getExpandos(), anyOf(containsInAnyOrder(expandosForJira5), containsInAnyOrder(expandosForJira6_4)));
167 assertEquals(new TimeTracking(null, 0, 190), issue.getTimeTracking());
168 assertTrue(size(issue.getFields()) > 0);
169
170 assertEquals(IntegrationTestUtil.START_PROGRESS_TRANSITION_ID, size(issue.getAttachments()));
171 final Iterable<Attachment> items = issue.getAttachments();
172 assertNotNull(items);
173 Attachment attachment1 = new Attachment(IntegrationTestUtil.concat(
174 IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ? UriBuilder.fromUri(jiraUri).path("/rest/api/2/").build()
175 : jiraRestRootUri, "/attachment/10040"),
176 "dla Paw\u0142a.txt", IntegrationTestUtil.USER_ADMIN, dateTime, 643, "text/plain",
177 IntegrationTestUtil.concat(jiraUri, "/secure/attachment/10040/dla+Paw%C5%82a.txt"), null);
178
179 assertEquals(attachment1, items.iterator().next());
180
181
182 assertNull(issue.getChangelog());
183
184 final Issue issueWithChangelogAndOperations = client.getIssueClient().getIssue("TST-2", EnumSet.of(CHANGELOG, OPERATIONS))
185 .claim();
186 final Iterable<ChangelogGroup> changelog = issueWithChangelogAndOperations.getChangelog();
187 if (isJira5xOrNewer()) {
188 assertNotNull(changelog);
189 final ChangelogGroup chg1 = Iterables.get(changelog, 18);
190 assertEquals("admin", chg1.getAuthor().getName());
191 assertEquals("Administrator", chg1.getAuthor().getDisplayName());
192 assertEquals(new DateTime(2010, 8, 17, 16, 40, 34, 924).toInstant(), chg1.getCreated().toInstant());
193
194 assertEquals(singletonList(new ChangelogItem(FieldType.JIRA, "status", "1", "Open", "3", "In Progress")), chg1
195 .getItems());
196
197 final ChangelogGroup chg2 = Iterables.get(changelog, 20);
198 assertEquals("admin", chg2.getAuthor().getName());
199 assertEquals("Administrator", chg2.getAuthor().getDisplayName());
200 assertEquals(new DateTime(2010, 8, 24, 16, 10, 23, 468).toInstant(), chg2.getCreated().toInstant());
201
202
203 Matcher<Iterable<? extends ChangelogItem>> historyItemsMatcher = containsInAnyOrder(
204 new ChangelogItem(FieldType.JIRA, "timeoriginalestimate", null, null, "0", "0"),
205 new ChangelogItem(FieldType.CUSTOM, "My Radio buttons", null, null, null, "Another"),
206 new ChangelogItem(FieldType.CUSTOM, "project3", null, null, "10000", "Test Project"),
207 new ChangelogItem(FieldType.CUSTOM, "My Number Field New", null, null, null, "1.45")
208 );
209 assertThat(chg2.getItems(), historyItemsMatcher);
210 }
211 final Operations operations = issueWithChangelogAndOperations.getOperations();
212 if (isJira5xOrNewer()) {
213 assertThat(operations, notNullValue());
214 assertThat(operations.getOperationById("log-work"), allOf(
215 instanceOf(OperationLink.class),
216 hasProperty("id", is("log-work"))
217 )
218 );
219 }
220 }
221
222 @Test
223 public void testGetIssueWithNonTrivialComments() {
224 final Issue issue = client.getIssueClient().getIssue("TST-2").claim();
225 final Iterable<Comment> comments = issue.getComments();
226 assertEquals(3, size(comments));
227 final Comment c1 = Iterables.get(comments, 0);
228 assertEquals(Visibility.role("Administrators"), c1.getVisibility());
229
230 final Comment c3 = Iterables.get(comments, 2);
231 assertEquals(Visibility.group("jira-users"), c3.getVisibility());
232
233 }
234
235 @Test
236 public void testGetVoter() {
237 final Issue issue = client.getIssueClient().getIssue("TST-1").claim();
238 final Votes votes = client.getIssueClient().getVotes(issue.getVotes().getSelf()).claim();
239 assertFalse(votes.hasVoted());
240 assertThat(votes.getUsers(), containsInAnyOrder(USER1));
241 }
242
243 @Test
244 public void testGetVotersWithoutViewIssuePermission() {
245 final Issue issue = client.getIssueClient().getIssue("RST-1").claim();
246 setUser2();
247 final String optionalDot = isJira5xOrNewer() ? "." : "";
248 assertErrorCode(Response.Status.FORBIDDEN,
249 "You do not have the permission to see the specified issue" + optionalDot, new Runnable() {
250 @Override
251 public void run() {
252 client.getIssueClient().getVotes(issue.getVotes().getSelf()).claim();
253 }
254 });
255 }
256
257 @Test
258 public void testGetVotersWithoutViewVotersPermission() {
259 setUser2();
260 assertNumVotesAndNoVotersDetails("TST-1", 1);
261 }
262
263 @Test
264 public void testGetVotersAnonymously() {
265 setAnonymousMode();
266 assertNumVotesAndNoVotersDetails("ANNON-1", 0);
267 }
268
269
270 private void assertNumVotesAndNoVotersDetails(final String issueKey, final int numVotes) {
271 final Issue issue = client.getIssueClient().getIssue(issueKey).claim();
272 assertEquals(numVotes, issue.getVotes().getVotes());
273 assertFalse(issue.getVotes().hasVoted());
274 final Votes votes = client.getIssueClient().getVotes(issue.getVotes().getSelf()).claim();
275 assertFalse(votes.hasVoted());
276 assertEquals(numVotes, votes.getVotes());
277 assertTrue(Iterables.isEmpty(votes.getUsers()));
278 }
279
280
281 @Test
282 public void testGetTransitions() throws Exception {
283 final Issue issue = client.getIssueClient().getIssue("TST-1").claim();
284 final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue).claim();
285 assertEquals(4, size(transitions));
286 assertTrue(Iterables
287 .contains(transitions, new Transition("Start Progress", IntegrationTestUtil.START_PROGRESS_TRANSITION_ID, Collections
288 .<Transition.Field>emptyList())));
289 }
290
291 @JiraBuildNumberDependent(BN_JIRA_5)
292 @Test
293 public void testGetCreateIssueMetadata() throws URISyntaxException {
294 final Iterable<CimProject> metadataProjects = client
295 .getIssueClient()
296 .getCreateIssueMetadata(new GetCreateIssueMetadataOptionsBuilder().withExpandedIssueTypesFields().build())
297 .claim();
298
299 assertEquals(4, size(metadataProjects));
300
301 final CimProject project = Iterables.find(metadataProjects, new Predicate<CimProject>() {
302 @Override
303 public boolean apply(CimProject input) {
304 return "ANONEDIT".equals(input.getKey());
305 }
306 });
307
308 assertEquals(project.getName(), "Anonymous Editable Project");
309
310 for (CimIssueType issueType : project.getIssueTypes()) {
311 assertFalse(String.format("Issue type ('%s') fields are not empty!", issueType.getName()), issueType.getFields()
312 .isEmpty());
313 }
314 }
315
316 @JiraBuildNumberDependent(BN_JIRA_5)
317 @Test
318 public void testGetCreateIssueMetadataWithFieldsNotExpanded() throws URISyntaxException {
319 final Iterable<CimProject> metadataProjects = client
320 .getIssueClient()
321 .getCreateIssueMetadata(null).claim();
322
323 assertEquals(4, size(metadataProjects));
324
325 final CimProject project = Iterables.find(metadataProjects, new Predicate<CimProject>() {
326 @Override
327 public boolean apply(CimProject input) {
328 return "ANONEDIT".equals(input.getKey());
329 }
330 });
331
332 assertEquals(project.getName(), "Anonymous Editable Project");
333 assertThat(size(project.getIssueTypes()), greaterThanOrEqualTo(5));
334
335 for (CimIssueType issueType : project.getIssueTypes()) {
336 assertTrue(issueType.getFields().isEmpty());
337 }
338 }
339
340 @JiraBuildNumberDependent(BN_JIRA_5)
341 @Test
342 public void testGetCreateIssueMetadataWithProjectKeyFilter() throws URISyntaxException {
343 final Iterable<CimProject> metadataProjects = client.getIssueClient()
344 .getCreateIssueMetadata(new GetCreateIssueMetadataOptionsBuilder()
345 .withProjectKeys("ANONEDIT", "TST")
346 .withExpandedIssueTypesFields()
347 .build())
348 .claim();
349
350 assertEquals(2, size(metadataProjects));
351
352 final CimProject project = Iterables.find(metadataProjects, new Predicate<CimProject>() {
353 @Override
354 public boolean apply(CimProject input) {
355 return "TST".equals(input.getKey());
356 }
357 });
358
359 assertEquals(project.getName(), "Test Project");
360 assertThat(size(project.getIssueTypes()), greaterThanOrEqualTo(5));
361
362 for (CimIssueType issueType : project.getIssueTypes()) {
363 assertFalse(issueType.getFields().isEmpty());
364 }
365 }
366
367 @Test
368 public void testFetchingIssueWithWorklogWhenAuthorIsDeleted() {
369 final Issue issue = client.getIssueClient().getIssue(ISSUE_KEY_WITH_REMOVED_USER_DATA).claim();
370 final Worklog worklog = issue.getWorklogs().iterator().next();
371 assertNotNull(worklog);
372 final BasicUser author = worklog.getAuthor();
373 assertNotNull(author);
374 assertThat(author.getName(), equalTo(REMOVED_USER_NAME));
375 assertTrue("expected incomplete self uri", author.isSelfUriIncomplete());
376 }
377
378 @Test
379 public void testFetchingIssueWithCommentWhenAuthorIsDeleted() {
380 final Issue issue = client.getIssueClient().getIssue(ISSUE_KEY_WITH_REMOVED_USER_DATA).claim();
381 final Comment comment = issue.getComments().iterator().next();
382 assertNotNull(comment);
383 final BasicUser author = comment.getAuthor();
384 assertNotNull(author);
385 assertEquals(getUserUri(REMOVED_USER_NAME), author.getSelf());
386 }
387 }