1   /*
2    * Copyright (C) 2011 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  
17  package it;
18  
19  import com.atlassian.jira.rest.client.IterableMatcher;
20  import com.atlassian.jira.rest.client.TestUtil;
21  import com.atlassian.jira.rest.client.domain.Issue;
22  import com.atlassian.jira.rest.client.domain.Version;
23  import com.atlassian.jira.rest.client.domain.VersionRelatedIssuesCount;
24  import com.atlassian.jira.rest.client.domain.input.VersionInput;
25  import com.atlassian.jira.rest.client.domain.input.VersionInputBuilder;
26  import com.atlassian.jira.rest.client.domain.input.VersionPosition;
27  import com.google.common.base.Function;
28  import com.google.common.base.Predicate;
29  import com.google.common.collect.Iterables;
30  import com.google.common.collect.Lists;
31  import org.junit.Test;
32  
33  import javax.annotation.Nullable;
34  import javax.ws.rs.core.Response;
35  import java.net.URI;
36  
37  import static com.atlassian.jira.rest.client.TestUtil.getLastPathSegment;
38  import static org.junit.Assert.assertThat;
39  
40  public class JerseyVersionRestClientTest extends AbstractRestoringJiraStateJerseyRestClientTest {
41  
42  	@Test
43  	public void testCreateAndUpdateVersion() throws Exception {
44  		if (!isJira4x4OrNewer()) {
45  			return;
46  		}
47  
48  		assertThat(Iterables.transform(client.getProjectClient().getProject("TST", pm).getVersions(),
49  				new VersionToNameMapper()), IterableMatcher.hasOnlyElements("1.1", "1"));
50  
51  		final VersionInput versionInput = VersionInput.create("TST", "My newly created version", "A description\nwith\new line", null, false, false);
52  		final Version version = client.getVersionRestClient().createVersion(versionInput, pm);
53  		assertEquals(versionInput, version);
54  		assertThat(Iterables.transform(client.getProjectClient().getProject("TST", pm).getVersions(), new VersionToNameMapper()),
55  				IterableMatcher.hasOnlyElements("1.1", "1", versionInput.getName()));
56  
57  		TestUtil.assertErrorCode(Response.Status.BAD_REQUEST, "A version with this name already exists in this project.", new Runnable() {
58  			@Override
59  			public void run() {
60  				client.getVersionRestClient().createVersion(versionInput, pm);
61  			}
62  		});
63  
64  
65  		final VersionInput versionInput2 = VersionInput.create("TST", "My newly created version2", "A description\nwith\new line", null, false, false);
66  		setAnonymousMode();
67  		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, new Runnable() {
68  			@Override
69  			public void run() {
70  				client.getVersionRestClient().createVersion(versionInput2, pm);
71  			}
72  		});
73  
74  		setUser2();
75  		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "Project with key 'TST' either does not exist or you do not have permission to create versions in it.", new Runnable() {
76  			@Override
77  			public void run() {
78  				client.getVersionRestClient().createVersion(versionInput2, pm);
79  			}
80  		});
81  
82  		// now version updates
83  		setAdmin();
84  		final VersionInput newVersionInput = new VersionInputBuilder(versionInput.getProjectKey(), version)
85  				.setDescription("my updated description").setReleased(true).setName("my updated name").build();
86  		client.getVersionRestClient().updateVersion(version.getSelf(), newVersionInput, pm);
87  		final Version modifiedVersion = client.getVersionRestClient().updateVersion(version.getSelf(), newVersionInput, pm);
88  		assertEquals(newVersionInput, modifiedVersion);
89  
90  		final VersionInput duplicateVersionInput = new VersionInputBuilder("TST", modifiedVersion).setName("1.1").build();
91  		TestUtil.assertErrorCode(Response.Status.BAD_REQUEST, "A version with this name already exists in this project.", new Runnable() {
92  			@Override
93  			public void run() {
94  				client.getVersionRestClient().updateVersion(modifiedVersion.getSelf(), duplicateVersionInput, pm);
95  			}
96  		});
97  
98  		setAnonymousMode();
99  		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, new Runnable() {
100 			@Override
101 			public void run() {
102 				client.getVersionRestClient().updateVersion(modifiedVersion.getSelf(), newVersionInput, pm);
103 			}
104 		});
105 
106 		setAdmin();
107 		final Version restrictedVersion = client.getVersionRestClient().createVersion(new VersionInputBuilder("RST").setName("My version").build(), pm);
108 		final VersionInput restrictedVersionInput = new VersionInputBuilder("RST", restrictedVersion).setDescription("another description").build();
109 		setUser2();
110 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "You must have browse project rights in order to view versions.", new Runnable() {
111 			@Override
112 			public void run() {
113 				client.getVersionRestClient().updateVersion(restrictedVersion.getSelf(), restrictedVersionInput, pm);
114 			}
115 		});
116 
117 	}
118 
119 	private void assertEquals(VersionInput versionInput, Version version) {
120 		assertEquals(version.getName(), versionInput.getName());
121 		assertEquals(version.getDescription(), versionInput.getDescription());
122 		assertEquals(version.getReleaseDate(), versionInput.getReleaseDate());
123 		assertEquals(version.isArchived(), versionInput.isArchived());
124 		assertEquals(version.isReleased(), versionInput.isReleased());
125 	}
126 
127 
128 	private static class VersionToNameMapper implements Function<Version, String> {
129 		@Override
130 		public String apply(Version from) {
131 			return from.getName();
132 		}
133 	}
134 
135 	@Test
136 	public void testGetAndRemoveVersion() {
137 		if (!isJira4x4OrNewer()) {
138 			return;
139 		}
140 		final Iterable<Version> versionsInTheBeggining = client.getProjectClient().getProject("TST", pm).getVersions();
141 		final VersionInput versionInput = VersionInput.create("TST", "My newly created version", "A description\nwith\new line", null, false, false);
142 		final Version version = client.getVersionRestClient().createVersion(versionInput, pm);
143 		assertEquals(version, client.getVersionRestClient().getVersion(version.getSelf(), pm));
144 
145 		setAnonymousMode();
146 		// weird - inconsistent with PUT/POST
147 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "You must have browse project rights in order to view versions.", new Runnable() {
148 			@Override
149 			public void run() {
150 				client.getVersionRestClient().getVersion(version.getSelf(), pm);
151 			}
152 		});
153 
154 		setAdmin();
155 		TestUtil.assertErrorCodeWithRegexp(Response.Status.NOT_FOUND, "Could not find version for id .*", new Runnable() {
156 			@Override
157 			public void run() {
158 				client.getVersionRestClient().getVersion(TestUtil.toUri(version.getSelf().toString() + "9"), pm);
159 			}
160 		});
161 
162 		setUser1();
163 		assertEquals(version, client.getVersionRestClient().getVersion(version.getSelf(), pm));
164 
165 		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, "The user wseliga does not have permission to complete this operation.", new Runnable() {
166 			@Override
167 			public void run() {
168 				client.getVersionRestClient().removeVersion(version.getSelf(), null, null, pm);
169 			}
170 		});
171 
172 		setAdmin();
173 		client.getVersionRestClient().removeVersion(version.getSelf(), null, null, pm);
174 		TestUtil.assertErrorCodeWithRegexp(Response.Status.NOT_FOUND, "Could not find version for id .*", new Runnable() {
175 			@Override
176 			public void run() {
177 				client.getVersionRestClient().getVersion(version.getSelf(), pm);
178 			}
179 		});
180 
181 		assertThat(client.getProjectClient().getProject("TST", pm).getVersions(), IterableMatcher.hasOnlyElements(versionsInTheBeggining));
182 		for (Version ver : versionsInTheBeggining) {
183 			client.getVersionRestClient().removeVersion(ver.getSelf(), null, null, pm);
184 		}
185 		assertThat(client.getProjectClient().getProject("TST", pm).getVersions(), IterableMatcher.<Version>isEmpty());
186 
187 	}
188 
189 
190 	@Test
191 	public void testDeleteAndMoveVersion() {
192 		if (!isJira4x4OrNewer()) {
193 			return;
194 		}
195 		final Issue issue = client.getIssueClient().getIssue("TST-2", pm);
196 		assertThat(Iterables.transform(issue.getFixVersions(), new VersionToNameMapper()), IterableMatcher.hasOnlyElements("1.1"));
197 		assertThat(Iterables.transform(issue.getAffectedVersions(), new VersionToNameMapper()), IterableMatcher.hasOnlyElements("1", "1.1"));
198 
199 		final Version version1 = Iterables.find(client.getProjectClient().getProject("TST", pm).getVersions(), new Predicate<Version>() {
200 			@Override
201 			public boolean apply(Version input) {
202 				return "1".equals(input.getName());
203 			}
204 		});
205 
206 		final Version version = Iterables.getOnlyElement(issue.getFixVersions());
207 		final URI fakeVersionUri = TestUtil.toUri("http://localhost/version/3432");
208 		final URI fakeVersionUri2 = TestUtil.toUri("http://localhost/version/34323");
209 		// @todo expected error code should be rather NOT FOUND in all cases below - see JRA-25045
210 		assertInvalidMoveToVersion(version.getSelf(), fakeVersionUri, null, "The fix version with id " +
211 				getLastPathSegment(fakeVersionUri) + " does not exist.", Response.Status.BAD_REQUEST);
212 		// @todo fix when bug JRA-25044 is fixed
213 		assertInvalidMoveToVersion(version.getSelf(), TestUtil.toUri("http://localhost/version/fdsa34323"), null,
214 				"Could not find version for id '-1'", Response.Status.NOT_FOUND);
215 		assertInvalidMoveToVersion(version.getSelf(), null, fakeVersionUri2, "The affects version with id " +
216 				getLastPathSegment(fakeVersionUri2) + " does not exist.", Response.Status.BAD_REQUEST);
217 		assertInvalidMoveToVersion(version.getSelf(), fakeVersionUri, fakeVersionUri2, "The affects version with id " +
218 				getLastPathSegment(fakeVersionUri2) + " does not exist.", Response.Status.BAD_REQUEST);
219 
220 		assertEquals(1, client.getVersionRestClient().getNumUnresolvedIssues(version.getSelf(), pm));
221 		assertEquals(new VersionRelatedIssuesCount(version.getSelf(), 1, 1), client.getVersionRestClient().getVersionRelatedIssuesCount(version.getSelf(), pm));
222 		assertEquals(new VersionRelatedIssuesCount(version.getSelf(), 1, 1), client.getVersionRestClient().getVersionRelatedIssuesCount(version.getSelf(), pm));
223 
224 		// now removing the first version
225 		client.getVersionRestClient().removeVersion(version.getSelf(), version1.getSelf(), version1.getSelf(), pm);
226 		final Issue issueAfterVerRemoval = client.getIssueClient().getIssue("TST-2", pm);
227 		assertThat(Iterables.transform(issueAfterVerRemoval.getFixVersions(), new VersionToNameMapper()), IterableMatcher.hasOnlyElements("1"));
228 		assertThat(Iterables.transform(issueAfterVerRemoval.getAffectedVersions(), new VersionToNameMapper()), IterableMatcher.hasOnlyElements("1"));
229 		assertThat(Iterables.transform(client.getProjectClient().getProject("TST", pm).getVersions(), new VersionToNameMapper()),
230 				IterableMatcher.hasOnlyElements("1"));
231 
232 		TestUtil.assertErrorCode(Response.Status.BAD_REQUEST, "You cannot move the issues to the version being deleted.", new Runnable() {
233 			@Override
234 			public void run() {
235 				client.getVersionRestClient().removeVersion(version1.getSelf(), version1.getSelf(), version1.getSelf(), pm);
236 			}
237 		});
238 
239 		// now removing the other version
240 		client.getVersionRestClient().removeVersion(version1.getSelf(), null, null, pm);
241 		final Issue issueAfter2VerRemoval = client.getIssueClient().getIssue("TST-2", pm);
242 		assertThat(Iterables.transform(issueAfter2VerRemoval.getFixVersions(), new VersionToNameMapper()), IterableMatcher.<String>isEmpty());
243 		assertThat(Iterables.transform(issueAfter2VerRemoval.getAffectedVersions(), new VersionToNameMapper()), IterableMatcher.<String>isEmpty());
244 	}
245 
246 	private void assertInvalidMoveToVersion(final URI versionUri, @Nullable final URI moveFixIssuesToVersionUri,
247 			@Nullable final URI moveAffectedIssuesToVersionUri, final String expectedErrorMsg, final Response.Status status) {
248 		TestUtil.assertErrorCode(status, expectedErrorMsg, new Runnable() {
249 			@Override
250 			public void run() {
251 				client.getVersionRestClient().removeVersion(versionUri, moveFixIssuesToVersionUri, moveAffectedIssuesToVersionUri, pm);
252 			}
253 		});
254 	}
255 
256 	@Test
257 	public void testMoveVersion() {
258 		if (!isJira4x4OrNewer()) {
259 			return;
260 		}
261 		final Version v3 = client.getVersionRestClient().createVersion(VersionInput.create("TST", "my added version", "a description", null, false, false), pm);
262 		assertProjectHasOrderedVersions("TST", "1", "1.1", v3.getName());
263 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.FIRST, pm);
264 		assertProjectHasOrderedVersions("TST", v3.getName(), "1", "1.1");
265 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.LAST, pm);
266 		assertProjectHasOrderedVersions("TST", "1", "1.1", v3.getName());
267 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.EARLIER, pm);
268 		assertProjectHasOrderedVersions("TST", "1", v3.getName(), "1.1");
269 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.EARLIER, pm);
270 		assertProjectHasOrderedVersions("TST", v3.getName(), "1", "1.1");
271 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.LATER, pm);
272 		assertProjectHasOrderedVersions("TST", "1", v3.getName(), "1.1");
273 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.LATER, pm);
274 		assertProjectHasOrderedVersions("TST", "1", "1.1", v3.getName());
275 		// later for the last version means nothing - but also no error
276 		client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.LATER, pm);
277 		assertProjectHasOrderedVersions("TST", "1", "1.1", v3.getName());
278 
279 		setUser1();
280 		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, "You must have global or project administrator rights in order to modify versions.", new Runnable() {
281 			@Override
282 			public void run() {
283 				client.getVersionRestClient().moveVersion(v3.getSelf(), VersionPosition.FIRST, pm);
284 			}
285 		});
286 
287 	}
288 
289 	@Test
290 	public void testMoveVersionAfter() {
291 		if (!isJira4x4OrNewer()) {
292 			return;
293 		}
294 		final Version v3 = client.getVersionRestClient().createVersion(VersionInput.create("TST", "my added version", "a description", null, false, false), pm);
295 		final Version v4 = client.getVersionRestClient().createVersion(VersionInput.create("TST", "my added version2", "a description2", null, true, false), pm);
296 		final Version v1 = Iterables.get(client.getProjectClient().getProject("TST", pm).getVersions(), 0);
297 		final String v1n = v1.getName();
298 		final String v3n = v3.getName();
299 		final String v4n = v4.getName();
300 		assertProjectHasOrderedVersions("TST", v1n, "1.1", v3n, v4n);
301 		client.getVersionRestClient().moveVersionAfter(v3.getSelf(), v4.getSelf(), pm);
302 		assertProjectHasOrderedVersions("TST", v1n, "1.1", v4n, v3n);
303 		client.getVersionRestClient().moveVersionAfter(v3.getSelf(), v1.getSelf(), pm);
304 		assertProjectHasOrderedVersions("TST", v1n, v3n, "1.1", v4n);
305 		client.getVersionRestClient().moveVersionAfter(v1.getSelf(), v4.getSelf(), pm);
306 		assertProjectHasOrderedVersions("TST", v3n, "1.1", v4n, v1n);
307 
308 		setUser1();
309 		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, "You must have global or project administrator rights in order to modify versions.", new Runnable() {
310 			@Override
311 			public void run() {
312 				client.getVersionRestClient().moveVersionAfter(v3.getSelf(), v4.getSelf(), pm);
313 			}
314 		});
315 
316 		setAnonymousMode();
317 		TestUtil.assertErrorCode(Response.Status.UNAUTHORIZED, new Runnable() {
318 			@Override
319 			public void run() {
320 				client.getVersionRestClient().moveVersionAfter(v3.getSelf(), v4.getSelf(), pm);
321 			}
322 		});
323 	}
324 
325 
326 	private void assertProjectHasOrderedVersions(String projectKey, String... expectedVersions) {
327 		assertEquals(Lists.newArrayList(expectedVersions), Lists.newArrayList(Iterables.transform(client.getProjectClient().getProject(projectKey, pm).getVersions(), new VersionToNameMapper())));
328 	}
329 }