1   /*
2    * Copyright (C) 2010 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.BasicComponentNameExtractionFunction;
20  import com.atlassian.jira.rest.client.IntegrationTestUtil;
21  import com.atlassian.jira.rest.client.IterableMatcher;
22  import com.atlassian.jira.rest.client.TestUtil;
23  import com.atlassian.jira.rest.client.domain.AssigneeType;
24  import com.atlassian.jira.rest.client.domain.BasicComponent;
25  import com.atlassian.jira.rest.client.domain.Component;
26  import com.atlassian.jira.rest.client.domain.input.ComponentInput;
27  import com.atlassian.jira.rest.client.internal.ServerVersionConstants;
28  import com.atlassian.jira.rest.client.internal.json.TestConstants;
29  import com.google.common.base.Predicate;
30  import com.google.common.collect.Iterables;
31  import org.junit.Test;
32  
33  import javax.ws.rs.core.Response;
34  
35  import static org.junit.Assert.assertThat;
36  
37  public class JerseyComponentRestClientTest extends AbstractRestoringJiraStateJerseyRestClientTest {
38  
39  	@Test
40  	public void testGetComponent() throws Exception {
41  		final BasicComponent basicComponent = Iterables.find(client.getProjectClient().getProject("TST", pm).getComponents(),
42  				new Predicate<BasicComponent>() {
43  					@Override
44  					public boolean apply(BasicComponent input) {
45  						return "Component A".equals(input.getName());
46  					}
47  				});
48  		final Component component = client.getComponentClient().getComponent(basicComponent.getSelf(), pm);
49  		assertEquals("Component A", component.getName());
50  		assertEquals("this is some description of component A", component.getDescription());
51  		assertEquals(IntegrationTestUtil.USER_ADMIN_LATEST, component.getLead());
52  	}
53  
54  	@Test
55  	public void testGetInvalidComponent() throws Exception {
56  		final BasicComponent basicComponent = Iterables.get(client.getProjectClient().getProject("TST", pm).getComponents(), 0);
57  		final String uriForUnexistingComponent = basicComponent.getSelf().toString() + "1234";
58  		TestUtil.assertErrorCode(Response.Status.NOT_FOUND,  "The component with id "
59  				+ TestUtil.getLastPathSegment(basicComponent.getSelf()) + "1234 does not exist.", new Runnable() {
60  			@Override
61  			public void run() {
62  				client.getComponentClient().getComponent(TestUtil.toUri(uriForUnexistingComponent), pm);
63  			}
64  		});
65  	}
66  
67  	@Test
68  	public void testGetComponentFromRestrictedProject() throws Exception {
69  		final BasicComponent basicComponent = Iterables.getOnlyElement(client.getProjectClient().getProject("RST", pm).getComponents());
70  		assertEquals("One Great Component", client.getComponentClient().getComponent(basicComponent.getSelf(), pm).getName());
71  
72  		// now as unauthorized user
73  		setClient(TestConstants.USER2_USERNAME, TestConstants.USER2_PASSWORD);
74  		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ?
75  				      	"The component with id 10010 does not exist." : "The user user does not have permission to complete this operation.", new Runnable() {
76  			@Override
77  			public void run() {
78  				client.getComponentClient().getComponent(basicComponent.getSelf(), pm).getName();
79  			}
80  		});
81  
82  		setAnonymousMode();
83  		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ?
84  				      	"The component with id 10010 does not exist." : "This user does not have permission to complete this operation.", new Runnable() {
85  			@Override
86  			public void run() {
87  				client.getComponentClient().getComponent(basicComponent.getSelf(), pm).getName();
88  			}
89  		});
90  	}
91  
92  	@Test
93  	public void testCreateAndRemoveComponent() {
94  		if (!isJira4x4OrNewer()) {
95  			return;
96  		}
97  		final Iterable<BasicComponent> components = client.getProjectClient().getProject("TST", pm).getComponents();
98  		assertEquals(2, Iterables.size(components));
99  		final BasicComponent basicComponent = Iterables.get(components, 0);
100 		final BasicComponent basicComponent2 = Iterables.get(components, 1);
101 		final String componentName = "my component";
102 		final ComponentInput componentInput = new ComponentInput(componentName, "a description", null, null);
103 		final Component component = client.getComponentClient().createComponent("TST", componentInput, pm);
104 		assertEquals(componentInput.getName(), component.getName());
105 		assertEquals(componentInput.getDescription(), component.getDescription());
106 		assertNull(component.getLead());
107 		assertProjectHasComponents(basicComponent.getName(), basicComponent2.getName(), componentName);
108 
109 		client.getComponentClient().removeComponent(basicComponent.getSelf(), null, pm);
110 		assertProjectHasComponents(basicComponent2.getName(), componentName);
111 		client.getComponentClient().removeComponent(basicComponent2.getSelf(), null, pm);
112 		assertProjectHasComponents(componentName);
113 		client.getComponentClient().removeComponent(component.getSelf(), null, pm);
114 		assertProjectHasComponents();
115 
116 	}
117 
118 	@Test
119 	public void testCreateAndRemoveComponentAsUnauthorizedUsers() {
120 		if (!isJira4x4OrNewer()) {
121 			return;
122 		}
123 		final Iterable<BasicComponent> components = client.getProjectClient().getProject("TST", pm).getComponents();
124 		assertEquals(2, Iterables.size(components));
125 		final BasicComponent basicComponent = Iterables.get(components, 0);
126 		final BasicComponent basicComponent2 = Iterables.get(components, 1);
127 
128 		final ComponentInput componentInput = new ComponentInput("my component", "a description", null, null);
129 		setUser1();
130 
131 		final Response.Status expectedForbiddenErrorCode = (doesJiraReturnCorrectErrorCodeForForbiddenOperation()) ? Response.Status.FORBIDDEN : Response.Status.UNAUTHORIZED;
132 		TestUtil.assertErrorCode(expectedForbiddenErrorCode, "The user wseliga does not have permission to complete this operation.", new Runnable() {
133 			@Override
134 			public void run() {
135 				client.getComponentClient().removeComponent(basicComponent.getSelf(), null, pm);
136 			}
137 		});
138 		TestUtil.assertErrorCode(expectedForbiddenErrorCode, "You cannot edit the configuration of this project.", new Runnable() {
139 			@Override
140 			public void run() {
141 				client.getComponentClient().createComponent("TST", componentInput, pm);
142 			}
143 		});
144 
145 		setAnonymousMode();
146 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ?
147 				      	"The component with id 10000 does not exist." : "This user does not have permission to complete this operation.", new Runnable() {
148 			@Override
149 			public void run() {
150 				client.getComponentClient().removeComponent(basicComponent.getSelf(), null, pm);
151 			}
152 		});
153 
154 		if (IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER) {
155 			TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "No project could be found with key 'TST'.", new Runnable() {
156 				@Override
157 				public void run() {
158 					client.getComponentClient().createComponent("TST", componentInput, pm);
159 				}
160 			});
161 		} else {
162 			// IMO for anonymous access still Response.Status.UNAUTHORIZED should be returned - JRADEV-7671
163 			TestUtil.assertErrorCode(expectedForbiddenErrorCode, "You cannot edit the configuration of this project.", new Runnable() {
164 				@Override
165 				public void run() {
166 					client.getComponentClient().createComponent("TST", componentInput, pm);
167 				}
168 			});
169 		}
170 
171 
172 		setAdmin();
173 		// now let's try to add a component with colliding name
174 		final ComponentInput dupeComponentInput = new ComponentInput(basicComponent.getName(), "a description", null, null);
175 		TestUtil.assertErrorCode(Response.Status.BAD_REQUEST, "A component with the name Component A already exists in this project.", new Runnable() {
176 			@Override
177 			public void run() {
178 				client.getComponentClient().createComponent("TST", dupeComponentInput, pm);
179 			}
180 		});
181 
182 		// now let's try to add a component for a non existing project
183 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "No project could be found with key 'FAKE'.", new Runnable() {
184 			@Override
185 			public void run() {
186 				client.getComponentClient().createComponent("FAKE", componentInput, pm);
187 			}
188 		});
189 
190 	}
191 
192 
193 	@SuppressWarnings({"ConstantConditions"})
194 	@Test
195 	public void testCreateComponentWithLead() {
196 		if (!isJira4x4OrNewer()) {
197 			return;
198 		}
199 		final ComponentInput componentInput = new ComponentInput("my component name", "a description", "admin", AssigneeType.COMPONENT_LEAD);
200 		final Component component = client.getComponentClient().createComponent("TST", componentInput, pm);
201 		assertNotNull(component.getAssigneeInfo());
202 		assertEquals(IntegrationTestUtil.USER_ADMIN_LATEST, component.getAssigneeInfo().getAssignee());
203 		assertEquals(AssigneeType.COMPONENT_LEAD, component.getAssigneeInfo().getAssigneeType());
204 		assertTrue(component.getAssigneeInfo().isAssigneeTypeValid());
205 		assertEquals(IntegrationTestUtil.USER_ADMIN_LATEST, component.getAssigneeInfo().getRealAssignee());
206 		assertEquals(AssigneeType.COMPONENT_LEAD, component.getAssigneeInfo().getRealAssigneeType());
207 
208 		final ComponentInput componentInput2 = new ComponentInput("my component name2", "a description", IntegrationTestUtil.USER1.getName(), AssigneeType.UNASSIGNED);
209 		final Component component2 = client.getComponentClient().createComponent("TST", componentInput2, pm);
210 		assertNotNull(component2.getAssigneeInfo());
211 		assertNull(component2.getAssigneeInfo().getAssignee());
212 		assertEquals(AssigneeType.UNASSIGNED, component2.getAssigneeInfo().getAssigneeType());
213 		assertFalse(component2.getAssigneeInfo().isAssigneeTypeValid());
214 		assertEquals(IntegrationTestUtil.USER_ADMIN_LATEST, component2.getAssigneeInfo().getRealAssignee());
215 		assertEquals(AssigneeType.PROJECT_DEFAULT, component2.getAssigneeInfo().getRealAssigneeType());
216 	}
217 
218 
219 	@Test
220 	public void testUpdateComponent() {
221 		if (!isJira4x4OrNewer()) {
222 			return;
223 		}
224 		final BasicComponent basicComponent = Iterables.get(client.getProjectClient().getProject("TST", pm).getComponents(), 0);
225 		final Component component = client.getComponentClient().getComponent(basicComponent.getSelf(), pm);
226 		final String newName = basicComponent.getName() + "updated";
227 		Component adjustedComponent = new Component(component.getSelf(), newName, component.getDescription(), component.getLead(), component.getAssigneeInfo());
228 
229 		Component updatedComponent = client.getComponentClient().updateComponent(basicComponent.getSelf(), new ComponentInput(newName, null, null, null), pm);
230 		assertEquals(adjustedComponent, updatedComponent);
231 		assertEquals(adjustedComponent, client.getComponentClient().getComponent(basicComponent.getSelf(), pm));
232 
233 		final String newDescription = "updated description";
234 		adjustedComponent = new Component(component.getSelf(), newName, newDescription, IntegrationTestUtil.USER1_LATEST, component.getAssigneeInfo());
235 		updatedComponent = client.getComponentClient().updateComponent(basicComponent.getSelf(), new ComponentInput(null, newDescription, IntegrationTestUtil.USER1.getName(), null), pm);
236 		assertEquals(adjustedComponent, updatedComponent);
237 
238 		final Component.AssigneeInfo ai = component.getAssigneeInfo();
239 		adjustedComponent = new Component(component.getSelf(), newName, newDescription, IntegrationTestUtil.USER1_LATEST,
240 				new Component.AssigneeInfo(IntegrationTestUtil.USER1_LATEST, AssigneeType.COMPONENT_LEAD, IntegrationTestUtil.USER1_LATEST, AssigneeType.COMPONENT_LEAD, true));
241 
242 		updatedComponent = client.getComponentClient().updateComponent(basicComponent.getSelf(), new ComponentInput(null, newDescription, IntegrationTestUtil.USER1.getName(), AssigneeType.COMPONENT_LEAD), pm);
243 		assertEquals(adjustedComponent, updatedComponent);
244 
245 
246 		// now with non-assignable assignee (thus we are inheriting assignee from project settings and component-level settings are ignored)
247 		adjustedComponent = new Component(component.getSelf(), newName, newDescription, IntegrationTestUtil.USER2_LATEST,
248 				new Component.AssigneeInfo(IntegrationTestUtil.USER2_LATEST, AssigneeType.COMPONENT_LEAD, IntegrationTestUtil.USER_ADMIN_LATEST, AssigneeType.PROJECT_DEFAULT, false));
249 
250 		updatedComponent = client.getComponentClient().updateComponent(basicComponent.getSelf(), new ComponentInput(null, newDescription, IntegrationTestUtil.USER2.getName(), AssigneeType.COMPONENT_LEAD), pm);
251 		assertEquals(adjustedComponent, updatedComponent);
252 
253 	}
254 
255 
256 	@Test
257 	public void testGetComponentRelatedIssuesCount() {
258 		if (!isJira4x4OrNewer()) {
259 			return;
260 		}
261 		final BasicComponent bc = Iterables.find(client.getProjectClient().getProject("TST", pm).getComponents(), new Predicate<BasicComponent>() {
262 			@Override
263 			public boolean apply(BasicComponent input) {
264 				return "Component A".equals(input.getName());
265 			}
266 		});
267 		assertEquals(1, client.getComponentClient().getComponentRelatedIssuesCount(bc.getSelf(), pm));
268 		final ComponentInput componentInput = new ComponentInput("my component name", "a description", "admin", AssigneeType.COMPONENT_LEAD);
269 		final Component component = client.getComponentClient().createComponent("TST", componentInput, pm);
270 		assertEquals(0, client.getComponentClient().getComponentRelatedIssuesCount(component.getSelf(), pm));
271 
272 		client.getComponentClient().removeComponent(bc.getSelf(), component.getSelf(), pm);
273 		assertEquals(1, client.getComponentClient().getComponentRelatedIssuesCount(component.getSelf(), pm));
274 
275 		// smelly error code/message returned here - JRA-25062
276 		setAnonymousMode();
277 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ?
278 				      	"The component with id 10000 does not exist." : "This user does not have permission to complete this operation.", new Runnable() {
279 			@Override
280 			public void run() {
281 				client.getComponentClient().getComponentRelatedIssuesCount(component.getSelf(), pm);
282 			}
283 		});
284 
285 		setAdmin();
286 		final BasicComponent restrictedComponent = Iterables.getOnlyElement(client.getProjectClient().getProject("RST", pm).getComponents());
287 		setUser1();
288 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, IntegrationTestUtil.TESTING_JIRA_5_OR_NEWER ?
289 				      	"The component with id 10010 does not exist." : "The user wseliga does not have permission to complete this operation.", new Runnable() {
290 			@Override
291 			public void run() {
292 				client.getComponentClient().getComponentRelatedIssuesCount(restrictedComponent.getSelf(), pm);
293 			}
294 		});
295 
296 		setAdmin();
297 		TestUtil.assertErrorCode(Response.Status.NOT_FOUND, "The component with id " + TestUtil.getLastPathSegment(restrictedComponent.getSelf())
298 				+ "999 does not exist.", new Runnable() {
299 			@Override
300 			public void run() {
301 				client.getComponentClient().getComponentRelatedIssuesCount(TestUtil.toUri(restrictedComponent.getSelf() + "999"), pm);
302 			}
303 		});
304 
305 	}
306 
307 
308 	boolean doesJiraReturnCorrectErrorCodeForForbiddenOperation() {
309 		return client.getMetadataClient().getServerInfo(pm).getBuildNumber() >= ServerVersionConstants.BN_JIRA_5;
310 	}
311 
312 
313 	private void assertProjectHasComponents(String ...names) {
314 		assertThat(Iterables.transform(client.getProjectClient().getProject("TST", pm).getComponents(),
315 				new BasicComponentNameExtractionFunction()), IterableMatcher.hasOnlyElements(names));
316 	}
317 
318 }