1   /*
2    * Copyright (C) 2012 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.rest.client.IntegrationTestUtil;
19  import com.atlassian.jira.rest.client.IssueRestClient;
20  import com.atlassian.jira.rest.client.IterableMatcher;
21  import com.atlassian.jira.rest.client.NullProgressMonitor;
22  import com.atlassian.jira.rest.client.annotation.RestoreOnce;
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.ChangelogGroup;
26  import com.atlassian.jira.rest.client.domain.ChangelogItem;
27  import com.atlassian.jira.rest.client.domain.Comment;
28  import com.atlassian.jira.rest.client.domain.Issue;
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.Worklog;
35  import com.atlassian.jira.rest.client.domain.input.FieldInput;
36  import com.atlassian.jira.rest.client.domain.input.TransitionInput;
37  import com.atlassian.jira.rest.client.internal.json.TestConstants;
38  import com.google.common.collect.ImmutableList;
39  import com.google.common.collect.Iterables;
40  import org.joda.time.DateTime;
41  import org.joda.time.format.ISODateTimeFormat;
42  import org.junit.Test;
43  
44  import javax.ws.rs.core.Response;
45  import javax.ws.rs.core.UriBuilder;
46  import java.util.Collections;
47  import java.util.EnumSet;
48  import java.util.Iterator;
49  import java.util.List;
50  
51  import static com.atlassian.jira.rest.client.IntegrationTestUtil.USER1;
52  import static com.atlassian.jira.rest.client.IntegrationTestUtil.USER2;
53  import static com.atlassian.jira.rest.client.TestUtil.assertErrorCode;
54  import static org.junit.Assert.assertEquals;
55  import static org.junit.Assert.assertFalse;
56  import static org.junit.Assert.assertNotNull;
57  import static org.junit.Assert.assertNull;
58  import static org.junit.Assert.assertThat;
59  import static org.junit.Assert.assertTrue;
60  
61  /**
62   * Those tests mustn't change anything on server side, as jira is restored only once
63   */
64  @RestoreOnce(TestConstants.DEFAULT_JIRA_DUMP_FILE)
65  public class JerseyIssueRestClientReadOnlyTest extends AbstractJerseyRestClientTest {
66  
67  	// no timezone here, as JIRA does not store timezone information in its dump file
68  	private final DateTime dateTime = ISODateTimeFormat.dateTimeParser().parseDateTime("2010-08-04T17:46:45.454");
69  
70  	@Test
71  	public void testGetWatchers() throws Exception {
72  		final Issue issue = client.getIssueClient().getIssue("TST-1", new NullProgressMonitor());
73  		final Watchers watchers = client.getIssueClient().getWatchers(issue.getWatchers().getSelf(), new NullProgressMonitor());
74  		assertEquals(1, watchers.getNumWatchers());
75  		assertFalse(watchers.isWatching());
76  		assertThat(watchers.getUsers(), IterableMatcher.hasOnlyElements(USER1));
77  	}
78  
79  	@Test
80  	public void testGetWatcherForAnonymouslyAccessibleIssue() {
81  		setAnonymousMode();
82  		final Issue issue = client.getIssueClient().getIssue("ANNON-1", new NullProgressMonitor());
83  		final Watchers watchers = client.getIssueClient().getWatchers(issue.getWatchers().getSelf(), pm);
84  		assertEquals(1, watchers.getNumWatchers());
85  		assertFalse(watchers.isWatching());
86  		assertTrue("JRADEV-3594 bug!!!", Iterables.isEmpty(watchers.getUsers()));
87  		// to save time
88  		assertEquals(new TimeTracking(2700, 2400, null), issue.getTimeTracking());
89  	}
90  
91  	@Test
92  	public void testGetIssueWithAnonymouslyCreatedAttachment() {
93  		setAnonymousMode();
94  		final Issue issue = client.getIssueClient().getIssue("ANONEDIT-1", new NullProgressMonitor());
95  		final Iterator<Attachment> attachmentIterator = issue.getAttachments().iterator();
96  		assertTrue(attachmentIterator.hasNext());
97  		assertNull(attachmentIterator.next().getAuthor());
98  	}
99  
100 	@Test
101 	public void testGetIssueWithAnonymouslyCreatedWorklogEntry() {
102 		setAnonymousMode();
103 		final Issue issue = client.getIssueClient().getIssue("ANONEDIT-2", new NullProgressMonitor());
104 		final Iterator<Worklog> worklogIterator = issue.getWorklogs().iterator();
105 		assertTrue(worklogIterator.hasNext());
106 		assertNull(worklogIterator.next().getAuthor());
107 	}
108 
109 	// URIs are broken in 5.0 - https://jdog.atlassian.com/browse/JRADEV-7691
110 	private void assertEqualsNoUri(BasicUser expected, BasicUser actual) {
111 		assertEquals(expected.getName(), actual.getName());
112 		assertEquals(expected.getDisplayName(), actual.getDisplayName());
113 	}
114 
115 
116 	@Test
117 	public void testGetIssue() throws Exception {
118 		final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
119 		assertEquals("TST-1", issue.getKey());
120 		assertTrue(issue.getSelf().toString().startsWith(jiraUri.toString()));
121 		assertEqualsNoUri(IntegrationTestUtil.USER_ADMIN, issue.getReporter());
122 		assertEqualsNoUri(IntegrationTestUtil.USER_ADMIN, issue.getAssignee());
123 
124 		assertThat(issue.getLabels(), IterableMatcher.hasOnlyElements("a", "bcds"));
125 
126 		assertEquals(3, Iterables.size(issue.getComments()));
127 		final Iterable<String> expectedExpandos = isJira5xOrNewer()
128 				? ImmutableList.of("renderedFields", "names", "schema", "transitions", "operations", "editmeta", "changelog") : ImmutableList.of("html");
129 		assertThat(ImmutableList.copyOf(issue.getExpandos()), IterableMatcher.hasOnlyElements(expectedExpandos));
130 		assertEquals(new TimeTracking(null, 0, 190), issue.getTimeTracking());
131 		assertTrue(Iterables.size(issue.getFields()) > 0);
132 
133 		assertEquals(IntegrationTestUtil.START_PROGRESS_TRANSITION_ID, Iterables.size(issue.getAttachments()));
134 		final Iterable<Attachment> items = issue.getAttachments();
135 		assertNotNull(items);
136 		Attachment attachment1 = new Attachment(IntegrationTestUtil.concat(
137 				IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ? UriBuilder.fromUri(jiraUri).path("/rest/api/2/").build()
138 						: jiraRestRootUri, "/attachment/10040"),
139 				"dla Paw\u0142a.txt", IntegrationTestUtil.USER_ADMIN, dateTime, 643, "text/plain",
140 				IntegrationTestUtil.concat(jiraUri, "/secure/attachment/10040/dla+Paw%C5%82a.txt"), null);
141 
142 		assertEquals(attachment1, items.iterator().next());
143 
144 		// test for changelog
145 		assertNull(issue.getChangelog());
146 
147 		final Issue issueWithChangelog = client.getIssueClient().getIssue("TST-2", EnumSet.of(IssueRestClient.Expandos.CHANGELOG), pm);
148 		final Iterable<ChangelogGroup> changelog = issueWithChangelog.getChangelog();
149 		if (isJira5xOrNewer()) {
150 			assertNotNull(changelog);
151 			final ChangelogGroup chg1 = Iterables.get(changelog, 18);
152 			assertEquals("admin", chg1.getAuthor().getName());
153 			assertEquals("Administrator", chg1.getAuthor().getDisplayName());
154 			assertEquals(new DateTime(2010, 8, 17, 16, 40, 34, 924).toInstant(), chg1.getCreated().toInstant());
155 
156 			assertEquals(Collections
157 					.singletonList(new ChangelogItem(ChangelogItem.FieldType.JIRA, "status", "1", "Open", "3", "In Progress")), chg1
158 					.getItems());
159 
160 			final ChangelogGroup chg2 = Iterables.get(changelog, 20);
161 			assertEquals("admin", chg2.getAuthor().getName());
162 			assertEquals("Administrator", chg2.getAuthor().getDisplayName());
163 			assertEquals(new DateTime(2010, 8, 24, 16, 10, 23, 468).toInstant(), chg2.getCreated().toInstant());
164 
165 			final List<ChangelogItem> expected = ImmutableList.of(
166 					new ChangelogItem(ChangelogItem.FieldType.JIRA, "timeoriginalestimate", null, null, "0", "0"),
167 					new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "My Radio buttons", null, null, null, "Another"),
168 					new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "project3", null, null, "10000", "Test Project"),
169 					new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "My Number Field New", null, null, null, "1.45")
170 			);
171 			assertEquals(expected, chg2.getItems());
172 		}
173 	}
174 
175 	@Test
176 	public void testGetIssueWithNonTrivialComments() {
177 		final Issue issue = client.getIssueClient().getIssue("TST-2", pm);
178 		final Iterable<Comment> comments = issue.getComments();
179 		assertEquals(3, Iterables.size(comments));
180 		final Comment c1 = Iterables.get(comments, 0);
181 		assertEquals(Visibility.role("Administrators"), c1.getVisibility());
182 
183 		final Comment c3 = Iterables.get(comments, 2);
184 		assertEquals(Visibility.group("jira-users"), c3.getVisibility());
185 
186 	}
187 
188 	@Test
189 	public void testGetIssueWithNoViewWatchersPermission() {
190 		setUser1();
191 		assertTrue(client.getIssueClient().getIssue("TST-1", pm).getWatchers().isWatching());
192 
193 		setUser2();
194 		final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
195 		assertFalse(issue.getWatchers().isWatching());
196 		client.getIssueClient().watch(issue.getWatchers().getSelf(), pm);
197 		final Issue watchedIssue = client.getIssueClient().getIssue("TST-1", pm);
198 		assertTrue(watchedIssue.getWatchers().isWatching());
199 		assertEquals(2, watchedIssue.getWatchers().getNumWatchers());
200 
201 		// although there are 2 watchers, only one is listed with details - the caller itself, as the caller does not
202 		// have view watchers and voters permission
203 		assertThat(client.getIssueClient().getWatchers(watchedIssue.getWatchers().getSelf(), pm).getUsers(), IterableMatcher.hasOnlyElements(USER2));
204 	}
205 
206 	@Test
207 	public void testGetVoter() {
208 		final Issue issue = client.getIssueClient().getIssue("TST-1", pm);
209 		final Votes votes = client.getIssueClient().getVotes(issue.getVotes().getSelf(), pm);
210 		assertFalse(votes.hasVoted());
211 		assertThat(votes.getUsers(), IterableMatcher.hasOnlyElements(USER1));
212 	}
213 
214 	@Test
215 	public void testGetVotersWithoutViewIssuePermission() {
216 		final Issue issue = client.getIssueClient().getIssue("RST-1", pm);
217 		setUser2();
218 		final String optionalDot = isJira5xOrNewer() ? "." : "";
219 		assertErrorCode(Response.Status.FORBIDDEN, "You do not have the permission to see the specified issue" + optionalDot, new Runnable() {
220 			@Override
221 			public void run() {
222 				client.getIssueClient().getVotes(issue.getVotes().getSelf(), pm);
223 			}
224 		});
225 	}
226 
227 	@Test
228 	public void testGetVotersWithoutViewVotersPermission() {
229 		setUser2();
230 		assertNumVotesAndNoVotersDetails("TST-1", 1);
231 	}
232 
233 	@Test
234 	public void testGetVotersAnonymously() {
235 		setAnonymousMode();
236 		assertNumVotesAndNoVotersDetails("ANNON-1", 0);
237 	}
238 
239 
240 	private void assertNumVotesAndNoVotersDetails(final String issueKey, final int numVotes) {
241 		final Issue issue = client.getIssueClient().getIssue(issueKey, pm);
242 		assertEquals(numVotes, issue.getVotes().getVotes());
243 		assertFalse(issue.getVotes().hasVoted());
244 		final Votes votes = client.getIssueClient().getVotes(issue.getVotes().getSelf(), pm);
245 		assertFalse(votes.hasVoted());
246 		assertEquals(numVotes, votes.getVotes());
247 		assertTrue(Iterables.isEmpty(votes.getUsers()));
248 	}
249 
250 
251 	@Test
252 	public void testGetTransitions() throws Exception {
253 		final Issue issue = client.getIssueClient().getIssue("TST-1", new NullProgressMonitor());
254 		final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
255 		assertEquals(4, Iterables.size(transitions));
256 		assertTrue(Iterables.contains(transitions, new Transition("Start Progress", IntegrationTestUtil.START_PROGRESS_TRANSITION_ID, Collections.<Transition.Field>emptyList())));
257 	}
258 
259 	@Test
260 	public void testTransition() throws Exception {
261 		final Issue issue = client.getIssueClient().getIssue("TST-1", new NullProgressMonitor());
262 		final Iterable<Transition> transitions = client.getIssueClient().getTransitions(issue, pm);
263 		assertEquals(4, Iterables.size(transitions));
264 		final Transition startProgressTransition = new Transition("Start Progress", IntegrationTestUtil.START_PROGRESS_TRANSITION_ID, Collections.<Transition.Field>emptyList());
265 		assertTrue(Iterables.contains(transitions, startProgressTransition));
266 
267 		client.getIssueClient().transition(issue, new TransitionInput(IntegrationTestUtil.START_PROGRESS_TRANSITION_ID,
268 				Collections.<FieldInput>emptyList(), Comment.valueOf("My test comment")), new NullProgressMonitor()) ;
269 		final Issue transitionedIssue = client.getIssueClient().getIssue("TST-1", new NullProgressMonitor());
270 		assertEquals("In Progress", transitionedIssue.getStatus().getName());
271 		final Iterable<Transition> transitionsAfterTransition = client.getIssueClient().getTransitions(issue, pm);
272 		assertFalse(Iterables.contains(transitionsAfterTransition, startProgressTransition));
273 		final Transition stopProgressTransition = new Transition("Stop Progress", IntegrationTestUtil.STOP_PROGRESS_TRANSITION_ID, Collections.<Transition.Field>emptyList());
274 		assertTrue(Iterables.contains(transitionsAfterTransition, stopProgressTransition));
275 	}
276 
277 }