View Javadoc

1   /*
2    * Copyright (C) 2012-2014 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * Those tests mustn't change anything on server side, as jira is restored only once
82   */
83  @SuppressWarnings("ConstantConditions") // To ignore "May produce NPE" warnings
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      // no timezone here, as JIRA does not store timezone information in its dump file
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         // to save time
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     // URIs are broken in 5.0 - https://jdog.atlassian.com/browse/JRADEV-7691
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         // here is anyOf matcher because "versionedRepresentations" was introduced in the middle of v6.4
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         // test for changelog
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             // there is not guarantee for the order of the items
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 }