1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package it;
18
19 import com.atlassian.jira.nimblefunctests.annotation.JiraBuildNumberDependent;
20 import com.atlassian.jira.nimblefunctests.annotation.RestoreOnce;
21 import com.atlassian.jira.rest.client.GetCreateIssueMetadataOptionsBuilder;
22 import com.atlassian.jira.rest.client.IntegrationTestUtil;
23 import com.atlassian.jira.rest.client.IssueRestClient;
24 import com.atlassian.jira.rest.client.RestClientException;
25 import com.atlassian.jira.rest.client.domain.BasicComponent;
26 import com.atlassian.jira.rest.client.domain.BasicIssue;
27 import com.atlassian.jira.rest.client.domain.BasicPriority;
28 import com.atlassian.jira.rest.client.domain.BasicUser;
29 import com.atlassian.jira.rest.client.domain.CimFieldInfo;
30 import com.atlassian.jira.rest.client.domain.CimIssueType;
31 import com.atlassian.jira.rest.client.domain.CimProject;
32 import com.atlassian.jira.rest.client.domain.CustomFieldOption;
33 import com.atlassian.jira.rest.client.domain.EntityHelper;
34 import com.atlassian.jira.rest.client.domain.Issue;
35 import com.atlassian.jira.rest.client.domain.IssueFieldId;
36 import com.atlassian.jira.rest.client.domain.TimeTracking;
37 import com.atlassian.jira.rest.client.domain.input.CannotTransformValueException;
38 import com.atlassian.jira.rest.client.domain.input.ComplexIssueInputFieldValue;
39 import com.atlassian.jira.rest.client.domain.input.FieldInput;
40 import com.atlassian.jira.rest.client.domain.input.IssueInput;
41 import com.atlassian.jira.rest.client.domain.input.IssueInputBuilder;
42 import com.atlassian.jira.rest.client.internal.json.JsonParseUtil;
43 import com.google.common.base.Predicate;
44 import com.google.common.collect.ImmutableList;
45 import com.google.common.collect.ImmutableMap;
46 import com.google.common.collect.Iterables;
47 import com.google.common.collect.Lists;
48 import org.joda.time.DateTime;
49 import org.junit.Rule;
50 import org.junit.Test;
51 import org.junit.rules.ExpectedException;
52
53 import java.text.MessageFormat;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.Collections;
57 import java.util.Date;
58 import java.util.List;
59 import java.util.Map;
60
61 import static com.atlassian.jira.rest.client.internal.ServerVersionConstants.BN_JIRA_5;
62 import static com.google.common.collect.Iterables.toArray;
63 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
64 import static org.hamcrest.core.IsCollectionContaining.hasItems;
65 import static org.junit.Assert.*;
66
67
68 @SuppressWarnings("ConstantConditions")
69
70 @RestoreOnce("jira3-export-for-creating-issue-tests.xml")
71 public class JerseyIssueRestClientCreateIssueTest extends AbstractJerseyRestClientTest {
72
73 @Rule
74 public ExpectedException thrown = ExpectedException.none();
75
76 @JiraBuildNumberDependent(BN_JIRA_5)
77 @Test
78 public void testCreateIssue() {
79
80 final IssueRestClient issueClient = client.getIssueClient();
81 final Iterable<CimProject> metadataProjects = issueClient.getCreateIssueMetadata(
82 new GetCreateIssueMetadataOptionsBuilder().withProjectKeys("TST").withExpandedIssueTypesFields().build(), pm);
83
84
85 assertEquals(1, Iterables.size(metadataProjects));
86 final CimProject project = metadataProjects.iterator().next();
87 final CimIssueType issueType = EntityHelper.findEntityByName(project.getIssueTypes(), "Bug");
88
89
90 final Iterable<Object> allowedValuesForComponents = issueType.getField(IssueFieldId.COMPONENTS_FIELD).getAllowedValues();
91 assertNotNull(allowedValuesForComponents);
92 assertTrue(allowedValuesForComponents.iterator().hasNext());
93 final BasicComponent component = (BasicComponent) allowedValuesForComponents.iterator().next();
94
95
96 final Iterable<Object> allowedValuesForPriority = issueType.getField(IssueFieldId.PRIORITY_FIELD).getAllowedValues();
97 assertNotNull(allowedValuesForPriority);
98 assertTrue(allowedValuesForPriority.iterator().hasNext());
99 final BasicPriority priority = (BasicPriority) allowedValuesForPriority.iterator().next();
100
101
102 final String summary = "My new issue!";
103 final String description = "Some description";
104 final BasicUser assignee = IntegrationTestUtil.USER1;
105 final List<String> affectedVersionsNames = Collections.emptyList();
106 final DateTime dueDate = new DateTime(new Date().getTime());
107 final ArrayList<String> fixVersionsNames = Lists.newArrayList("1.1");
108
109
110 final IssueInputBuilder issueInputBuilder = new IssueInputBuilder(project, issueType, summary)
111 .setDescription(description)
112 .setAssignee(assignee)
113 .setAffectedVersionsNames(affectedVersionsNames)
114 .setFixVersionsNames(fixVersionsNames)
115 .setComponents(component)
116 .setDueDate(dueDate)
117 .setPriority(priority);
118
119
120 final BasicIssue basicCreatedIssue = issueClient.createIssue(issueInputBuilder.build(), pm);
121 assertNotNull(basicCreatedIssue.getKey());
122
123
124 final Issue createdIssue = issueClient.getIssue(basicCreatedIssue.getKey(), pm);
125 assertNotNull(createdIssue);
126
127 assertEquals(basicCreatedIssue.getKey(), createdIssue.getKey());
128 assertEquals(project.getKey(), createdIssue.getProject().getKey());
129 assertEquals(issueType.getId(), createdIssue.getIssueType().getId());
130 assertEquals(summary, createdIssue.getSummary());
131 assertEquals(description, createdIssue.getDescription());
132
133 final BasicUser actualAssignee = createdIssue.getAssignee();
134 assertNotNull(actualAssignee);
135 assertEquals(assignee.getSelf(), actualAssignee.getSelf());
136
137 final Iterable<String> actualAffectedVersionsNames = EntityHelper.toNamesList(createdIssue.getAffectedVersions());
138 assertThat(affectedVersionsNames, containsInAnyOrder(toArray(actualAffectedVersionsNames, String.class)));
139
140 final Iterable<String> actualFixVersionsNames = EntityHelper.toNamesList(createdIssue.getFixVersions());
141 assertThat(fixVersionsNames, containsInAnyOrder(toArray(actualFixVersionsNames, String.class)));
142
143 assertTrue(createdIssue.getComponents().iterator().hasNext());
144 assertEquals(component.getId(), createdIssue.getComponents().iterator().next().getId());
145
146
147 final DateTime expectedDueDate = JsonParseUtil.parseDate(JsonParseUtil.formatDate(dueDate));
148 assertEquals(expectedDueDate, createdIssue.getDueDate());
149
150 final BasicPriority actualPriority = createdIssue.getPriority();
151 assertNotNull(actualPriority);
152 assertEquals(priority.getId(), actualPriority.getId());
153 }
154
155 @JiraBuildNumberDependent(BN_JIRA_5)
156 @Test
157 public void testCreateIssueWithOnlyRequiredFields() {
158
159 final IssueRestClient issueClient = client.getIssueClient();
160 final Iterable<CimProject> metadataProjects = issueClient.getCreateIssueMetadata(
161 new GetCreateIssueMetadataOptionsBuilder().withProjectKeys("TST").withExpandedIssueTypesFields().build(),
162 pm
163 );
164
165
166 assertEquals(1, Iterables.size(metadataProjects));
167 final CimProject project = metadataProjects.iterator().next();
168 final CimIssueType issueType = EntityHelper.findEntityByName(project.getIssueTypes(), "Bug");
169
170
171 final String summary = "My new issue!";
172
173
174 final IssueInput issueInput = new IssueInputBuilder(project, issueType, summary).build();
175 final BasicIssue basicCreatedIssue = issueClient.createIssue(issueInput, pm);
176 assertNotNull(basicCreatedIssue.getKey());
177
178
179 final Issue createdIssue = issueClient.getIssue(basicCreatedIssue.getKey(), pm);
180 assertNotNull(createdIssue);
181
182 assertEquals(basicCreatedIssue.getKey(), createdIssue.getKey());
183 assertEquals(project.getKey(), createdIssue.getProject().getKey());
184 assertEquals(issueType.getId(), createdIssue.getIssueType().getId());
185 assertEquals(summary, createdIssue.getSummary());
186 }
187
188 @JiraBuildNumberDependent(BN_JIRA_5)
189 @Test
190 public void testCreateIssueWithoutSummary() {
191 final IssueRestClient issueClient = client.getIssueClient();
192
193 thrown.expect(RestClientException.class);
194 thrown.expectMessage("You must specify a summary of the issue.");
195
196 final IssueInput issueInput = new IssueInputBuilder("TST", 1L).build();
197 issueClient.createIssue(issueInput, pm);
198 }
199
200 @JiraBuildNumberDependent(BN_JIRA_5)
201 @Test
202 public void testCreateIssueWithNotExistentProject() {
203 final IssueRestClient issueClient = client.getIssueClient();
204
205 thrown.expect(RestClientException.class);
206 thrown.expectMessage("project is required");
207
208 final IssueInput issueInput = new IssueInputBuilder("BAD", 1L, "Should fail").build();
209 issueClient.createIssue(issueInput, pm);
210 }
211
212 @JiraBuildNumberDependent(BN_JIRA_5)
213 @Test
214 public void testCreateIssueWithNotExistentIssueType() {
215 final IssueRestClient issueClient = client.getIssueClient();
216
217 thrown.expect(RestClientException.class);
218 thrown.expectMessage("valid issue type is required");
219
220 final IssueInput issueInput = new IssueInputBuilder("TST", 666L, "Should fail").build();
221 issueClient.createIssue(issueInput, pm);
222 }
223
224
225 @JiraBuildNumberDependent(BN_JIRA_5)
226 @Test
227 public void testCreateIssueWithoutProject() {
228 final IssueRestClient issueClient = client.getIssueClient();
229
230 thrown.expect(RestClientException.class);
231 thrown.expectMessage("project is required");
232
233 final IssueInput issueInput = new IssueInput(ImmutableMap.of(
234 "summary", new FieldInput("summary", "Summary"),
235 "issuetype", new FieldInput("issuetype", ComplexIssueInputFieldValue.with("id", "1"))
236 ));
237 issueClient.createIssue(issueInput, pm);
238 }
239
240 @JiraBuildNumberDependent(BN_JIRA_5)
241 @Test
242 public void testCreateIssueWithInvalidAdditionalField() {
243 final IssueRestClient issueClient = client.getIssueClient();
244 final String fieldId = "invalidField";
245
246 thrown.expect(RestClientException.class);
247 thrown.expectMessage(String
248 .format("Field '%s' cannot be set. It is not on the appropriate screen, or unknown.", fieldId));
249
250 final IssueInput issueInput = new IssueInputBuilder("TST", 1L, "Should fail")
251 .setFieldValue(fieldId, "test")
252 .build();
253 issueClient.createIssue(issueInput, pm);
254 }
255
256 @JiraBuildNumberDependent(BN_JIRA_5)
257 @Test
258 public void testCreateIssueWithFieldValueThatIsNotAllowed() {
259 final IssueRestClient issueClient = client.getIssueClient();
260 final BasicPriority invalidPriority = new BasicPriority(null, 666L, "Invalid Priority");
261
262 thrown.expect(RestClientException.class);
263 thrown.expectMessage(String
264 .format("Invalid value '%s' passed for customfield 'My Radio buttons'. Allowed values are: 10000[abc], 10001[Another], 10002[The last option], -1", invalidPriority
265 .getId()));
266
267 final IssueInput issueInput = new IssueInputBuilder("TST", 1L, "Should fail")
268 .setFieldValue("customfield_10001", invalidPriority)
269 .build();
270 issueClient.createIssue(issueInput, pm);
271 }
272
273 @JiraBuildNumberDependent(BN_JIRA_5)
274 @Test
275 public void testCreateIssueAsAnonymous() {
276 setAnonymousMode();
277
278 final IssueRestClient issueClient = client.getIssueClient();
279
280 final IssueInput issueInput = new IssueInputBuilder("ANONEDIT", 1L, "Anonymously created issue").build();
281 final BasicIssue createdIssue = issueClient.createIssue(issueInput, pm);
282
283 assertNotNull(createdIssue);
284 assertNotNull(createdIssue.getKey());
285 }
286
287 @JiraBuildNumberDependent(BN_JIRA_5)
288 @Test
289 public void testCreateIssueAsAnonymousWhenNotAllowed() {
290 setAnonymousMode();
291 final IssueRestClient issueClient = client.getIssueClient();
292
293 thrown.expect(RestClientException.class);
294 thrown.expectMessage("Anonymous users do not have permission to create issues in this project. Please try logging in first.");
295
296
297 final IssueInput issueInput = new IssueInputBuilder("TST", 1L
298 .build();
299 issueClient.createIssue(issueInput, pm);
300 }
301
302 @JiraBuildNumberDependent(BN_JIRA_5)
303 @Test
304 public void testJiradev13412BugNotFixedIfThisFailsThenCorrectAffectedTests() {
305
306
307
308
309
310
311
312 setAnonymousMode();
313 final IssueRestClient issueClient = client.getIssueClient();
314
315 thrown.expect(RestClientException.class);
316 thrown.expectMessage("Field 'summary' cannot be set. It is not on the appropriate screen, or unknown.");
317
318 final IssueInput issueInput = new IssueInputBuilder("TST", 1L, "Sample summary").build();
319 issueClient.createIssue(issueInput, pm);
320 }
321
322 @JiraBuildNumberDependent(BN_JIRA_5)
323 @Test
324 public void testCreateIssueWithAssigneeWhenNotAllowedToAssignIssue() {
325 setUser2();
326 final IssueRestClient issueClient = client.getIssueClient();
327
328 thrown.expect(RestClientException.class);
329 thrown.expectMessage("Field 'assignee' cannot be set. It is not on the appropriate screen, or unknown.");
330
331 final IssueInput issueInput = new IssueInputBuilder("TST", 1L, "Issue created by testCreateIssueWithAssigneeWhenNotAllowedToAssignIssue")
332 .setAssignee(IntegrationTestUtil.USER_ADMIN)
333 .build();
334 issueClient.createIssue(issueInput, pm);
335 }
336
337 @JiraBuildNumberDependent(BN_JIRA_5)
338 @Test
339 public void testCreateIssueWithoutCreateIssuePermission() {
340 setUser1();
341 final IssueRestClient issueClient = client.getIssueClient();
342
343 thrown.expect(RestClientException.class);
344 thrown.expectMessage("You do not have permission to create issues in this project.");
345
346
347 final IssueInput issueInput = new IssueInputBuilder("NCIFU", 1L
348 .build();
349 issueClient.createIssue(issueInput, pm);
350 }
351
352
353 @JiraBuildNumberDependent(BN_JIRA_5)
354 @Test
355 public void testCreateIssueWithoutBrowseProjectPermission() {
356 setUser1();
357 final IssueRestClient issueClient = client.getIssueClient();
358
359 thrown.expect(RestClientException.class);
360 thrown.expectMessage("You do not have permission to create issues in this project.");
361
362
363 final IssueInput issueInput = new IssueInputBuilder("RST", 1L
364 .build();
365 issueClient.createIssue(issueInput, pm);
366 }
367
368 @JiraBuildNumberDependent(BN_JIRA_5)
369 @Test
370 public void interactiveUseCase() throws CannotTransformValueException {
371 final IssueRestClient issueClient = client.getIssueClient();
372
373
374 final Iterable<CimProject> metadataProjects = issueClient.getCreateIssueMetadata(
375 new GetCreateIssueMetadataOptionsBuilder().withExpandedIssueTypesFields().build(),
376 pm
377 );
378 log.log("Available projects: ");
379 for (CimProject p : metadataProjects) {
380 log.log(MessageFormat.format("\t* [{0}] {1}", p.getKey(), p.getName()));
381 }
382 log.log("");
383 assertTrue("There is no project to select!", metadataProjects.iterator().hasNext());
384
385
386 final CimProject project = metadataProjects.iterator().next();
387 log.log(MessageFormat.format("Selected project: [{0}] {1}\n", project.getKey(), project.getName()));
388
389
390 log.log("Available issue types for selected project:");
391 for (CimIssueType t : project.getIssueTypes()) {
392 log.log(MessageFormat.format("\t* [{0}] {1}", t.getId(), t.getName()));
393 }
394 log.log("");
395
396 final CimIssueType issueType = project.getIssueTypes().iterator().next();
397 log.log(MessageFormat.format("Selected issue type: [{0}] {1}\n", issueType.getId(), issueType.getName()));
398
399 final IssueInputBuilder builder = new IssueInputBuilder(project.getKey(), issueType.getId());
400
401
402 log.log("Filling fields:");
403 for (Map.Entry<String, CimFieldInfo> entry : issueType.getFields().entrySet()) {
404 final CimFieldInfo fieldInfo = entry.getValue();
405 final String fieldCustomType = fieldInfo.getSchema().getCustom();
406 final String fieldType = fieldInfo.getSchema().getType();
407 final String fieldId = fieldInfo.getId();
408
409 if ("project".equals(fieldId) || "issuetype".equals(fieldId)) {
410
411 continue;
412 }
413
414 log.log(MessageFormat.format("\t* [{0}] {1}\n\t\t| schema: {2}\n\t\t| required: {3}", fieldId, fieldInfo
415 .getName(), fieldInfo.getSchema(), fieldInfo.isRequired()));
416
417
418 Object value = null;
419 final Iterable<Object> allowedValues = fieldInfo.getAllowedValues();
420 if (allowedValues != null) {
421 log.log("\t\t| field only accepts those values:");
422 for (Object val : allowedValues) {
423 log.log("\t\t\t* " + val);
424 }
425 if (allowedValues.iterator().hasNext()) {
426 final boolean expectedArray = "array".equals(fieldType);
427 Object singleValue = allowedValues.iterator().next();
428
429 if ("com.atlassian.jira.plugin.system.customfieldtypes:cascadingselect".equals(fieldCustomType)) {
430
431 final Iterable<Object> optionsWithChildren = Iterables.filter(allowedValues, new Predicate<Object>() {
432 @Override
433 public boolean apply(Object input) {
434 return ((CustomFieldOption) input).getChildren().iterator().hasNext();
435 }
436 });
437
438 if (optionsWithChildren.iterator().hasNext()) {
439
440 final CustomFieldOption option = (CustomFieldOption) optionsWithChildren.iterator().next();
441 value = new CustomFieldOption(option.getId(), option.getSelf(), option.getValue(),
442 Collections.<CustomFieldOption>emptyList(), option.getChildren().iterator().next());
443 }
444 else {
445
446 value = allowedValues.iterator().next();
447 }
448 }
449 else {
450 value = expectedArray ? Collections.singletonList(singleValue) : singleValue;
451 }
452 log.log("\t\t| selecting value: " + value);
453 } else {
454 log.log("\t\t| there is no allowed value - leaving field blank");
455 }
456 } else {
457 if ("com.atlassian.jirafisheyeplugin:jobcheckbox".equals(fieldCustomType)) {
458 value = "false";
459 }
460 else if ("com.atlassian.jira.plugin.system.customfieldtypes:url".equals(fieldCustomType)) {
461 value = "http://www.atlassian.com/";
462 }
463 else if ("string".equals(fieldType)) {
464 value = "This is simple string value for field " + fieldId + " named " + fieldInfo.getName() + ".";
465 } else if ("number".equals(fieldType)) {
466 value = 124;
467 } else if ("user".equals(fieldType)) {
468 value = IntegrationTestUtil.USER_ADMIN;
469 } else if ("array".equals(fieldType) && "user".equals(fieldInfo.getSchema().getItems())) {
470 value = ImmutableList.of(IntegrationTestUtil.USER_ADMIN);
471 } else if ("group".equals(fieldType)) {
472
473 value = ComplexIssueInputFieldValue.with("name", IntegrationTestUtil.GROUP_JIRA_ADMINISTRATORS);
474 } else if ("array".equals(fieldType) && "group".equals(fieldInfo.getSchema().getItems())) {
475
476 value = ImmutableList.of(ComplexIssueInputFieldValue.with("name", IntegrationTestUtil.GROUP_JIRA_ADMINISTRATORS));
477 } else if ("date".equals(fieldType)) {
478 value = JsonParseUtil.formatDate(new DateTime());
479 } else if ("datetime".equals(fieldType)) {
480 value = JsonParseUtil.formatDateTime(new DateTime());
481 } else if ("array".equals(fieldType) && "string".equals(fieldInfo.getSchema().getItems())) {
482 value = ImmutableList.of("one", "two", "three");
483 } else if ("timetracking".equals(fieldType)) {
484 value = new TimeTracking(60, 40, null);
485 } else {
486 if (fieldInfo.isRequired()) {
487 fail("I don't know how to fill that required field, sorry.");
488 } else {
489 log.log("\t\t| field value is not required, leaving blank");
490 }
491 }
492 }
493 if (value == null) {
494 log.log("\t\t| value is null, skipping filed");
495 } else {
496 log.log(MessageFormat.format("\t\t| setting value => {0}", value));
497 builder.setFieldValue(fieldId, value);
498 }
499 }
500 log.log("");
501
502
503 final IssueInput issueInput = builder.build();
504
505 final BasicIssue basicCreatedIssue = issueClient.createIssue(issueInput, pm);
506 assertNotNull(basicCreatedIssue);
507
508 final Issue createdIssue = issueClient.getIssue(basicCreatedIssue.getKey(), pm);
509 assertNotNull(createdIssue);
510
511 log.log("Created new issue successfully, key: " + basicCreatedIssue.getKey());
512
513
514 IssueInputBuilder actualBuilder = new IssueInputBuilder(createdIssue.getProject(), createdIssue
515 .getIssueType(), createdIssue.getSummary())
516 .setPriority(createdIssue.getPriority())
517 .setReporter(createdIssue.getReporter())
518 .setAssignee(createdIssue.getAssignee())
519 .setDescription(createdIssue.getDescription());
520
521 final Collection<FieldInput> actualValues = actualBuilder.build().getFields().values();
522 final Collection<FieldInput> expectedValues = issueInput.getFields().values();
523
524 assertThat(expectedValues, hasItems(toArray(actualValues, FieldInput.class)));
525 }
526 }