1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.jira.rest.client.internal.json;
18
19 import com.atlassian.jira.rest.client.BasicComponentNameExtractionFunction;
20 import com.atlassian.jira.rest.client.domain.Attachment;
21 import com.atlassian.jira.rest.client.domain.BasicComponent;
22 import com.atlassian.jira.rest.client.domain.BasicIssueType;
23 import com.atlassian.jira.rest.client.domain.BasicPriority;
24 import com.atlassian.jira.rest.client.domain.BasicProject;
25 import com.atlassian.jira.rest.client.domain.BasicUser;
26 import com.atlassian.jira.rest.client.domain.BasicWatchers;
27 import com.atlassian.jira.rest.client.domain.ChangelogGroup;
28 import com.atlassian.jira.rest.client.domain.ChangelogItem;
29 import com.atlassian.jira.rest.client.domain.Comment;
30 import com.atlassian.jira.rest.client.domain.Field;
31 import com.atlassian.jira.rest.client.domain.Issue;
32 import com.atlassian.jira.rest.client.domain.IssueLink;
33 import com.atlassian.jira.rest.client.domain.IssueLinkType;
34 import com.atlassian.jira.rest.client.domain.Subtask;
35 import com.atlassian.jira.rest.client.domain.TimeTracking;
36 import com.atlassian.jira.rest.client.domain.Visibility;
37 import com.atlassian.jira.rest.client.domain.Worklog;
38 import com.google.common.collect.ImmutableList;
39 import com.google.common.collect.Iterables;
40 import org.codehaus.jettison.json.JSONException;
41 import org.codehaus.jettison.json.JSONObject;
42 import org.hamcrest.collection.IsEmptyCollection;
43 import org.hamcrest.collection.IsEmptyIterable;
44 import org.joda.time.format.ISODateTimeFormat;
45 import org.junit.Assert;
46 import org.junit.Test;
47
48 import java.util.Iterator;
49
50 import static com.atlassian.jira.rest.client.TestUtil.toDateTime;
51 import static com.atlassian.jira.rest.client.TestUtil.toDateTimeFromIsoDate;
52 import static com.atlassian.jira.rest.client.TestUtil.toUri;
53 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
54 import static org.junit.Assert.*;
55
56
57 @SuppressWarnings("ConstantConditions")
58 public class IssueJsonParserTest {
59 @Test
60 public void testParseIssue() throws Exception {
61 final Issue issue = parseIssue("/json/issue/valid-all-expanded.json");
62 assertExpectedIssue(issue);
63 assertEquals(new BasicIssueType(toUri("http://localhost:8090/jira/rest/api/latest/issueType/1"), 1L, "Bug", false),
64 issue.getIssueType());
65 }
66
67 @Test
68 public void testParseIssueJira4x2() throws Exception {
69 final Issue issue = parseIssue("/json/issue/valid-all-expanded-jira-4-2.json");
70 assertExpectedIssue(issue);
71 assertEquals(new BasicIssueType(toUri("http://localhost:8090/jira/rest/api/latest/issueType/1"), null, "Bug", false),
72 issue.getIssueType());
73 }
74
75 private void assertExpectedIssue(Issue issue) {
76 assertEquals("Testing issue", issue.getSummary());
77 assertEquals("TST-2", issue.getKey());
78 assertEquals(new BasicProject(toUri("http://localhost:8090/jira/rest/api/latest/project/TST"), "TST", null), issue.getProject());
79 assertEquals("Major", issue.getPriority().getName());
80 assertNull(issue.getResolution());
81 assertEquals(toDateTime("2010-07-26T13:29:18.262+0200"), issue.getCreationDate());
82 assertEquals(toDateTime("2010-08-27T15:00:02.107+0200"), issue.getUpdateDate());
83 assertEquals(null, issue.getDueDate());
84
85 assertEquals(TestConstants.USER_ADMIN, issue.getReporter());
86 assertEquals(TestConstants.USER1, issue.getAssignee());
87
88
89 Assert.assertThat(issue.getIssueLinks(), containsInAnyOrder(
90 new IssueLink("TST-1", toUri("http://localhost:8090/jira/rest/api/latest/issue/TST-1"),
91 new IssueLinkType("Duplicate", "duplicates", IssueLinkType.Direction.OUTBOUND)),
92 new IssueLink("TST-1", toUri("http://localhost:8090/jira/rest/api/latest/issue/TST-1"),
93 new IssueLinkType("Duplicate", "is duplicated by", IssueLinkType.Direction.INBOUND))
94 ));
95
96
97
98 final BasicWatchers watchers = issue.getWatchers();
99 assertFalse(watchers.isWatching());
100 assertEquals(toUri("http://localhost:8090/jira/rest/api/latest/issue/TST-2/watchers"), watchers.getSelf());
101 assertEquals(1, watchers.getNumWatchers());
102 assertEquals(new TimeTracking(0, 0, 145), issue.getTimeTracking());
103
104
105 final Iterable<Attachment> attachments = issue.getAttachments();
106 assertEquals(3, Iterables.size(attachments));
107 final Attachment attachment = attachments.iterator().next();
108 assertEquals("jira_logo.gif", attachment.getFilename());
109 assertEquals(TestConstants.USER_ADMIN, attachment.getAuthor());
110 assertEquals(2517, attachment.getSize());
111 assertEquals(toUri("http://localhost:8090/jira/secure/thumbnail/10036/10036_jira_logo.gif"), attachment.getThumbnailUri());
112 final Iterator<Attachment> attachmentIt = attachments.iterator();
113 attachmentIt.next();
114 attachmentIt.next();
115 final Attachment lastAttachment = attachmentIt.next();
116 assertEquals("transparent-png.png", lastAttachment.getFilename());
117
118
119 final Iterable<Worklog> worklogs = issue.getWorklogs();
120 assertEquals(5, Iterables.size(worklogs));
121 final Worklog worklog = Iterables.get(worklogs, 2);
122 assertEquals(new Worklog(toUri("http://localhost:8090/jira/rest/api/latest/worklog/10012"),
123 toUri("http://localhost:8090/jira/rest/api/latest/issue/TST-2"), TestConstants.USER1,
124 TestConstants.USER1, "a worklog viewable just by jira-users",
125 toDateTime("2010-08-17T16:53:15.848+0200"), toDateTime("2010-08-17T16:53:15.848+0200"),
126 toDateTime("2010-08-11T16:52:00.000+0200"), 3, Visibility.group("jira-users")), worklog);
127
128 final Worklog worklog3 = Iterables.get(worklogs, 3);
129 assertEquals("", worklog3.getComment());
130
131
132 assertEquals(3, Iterables.size(issue.getComments()));
133 final Comment comment = issue.getComments().iterator().next();
134 assertEquals(Visibility.Type.ROLE, comment.getVisibility().getType());
135 assertEquals(TestConstants.USER_ADMIN, comment.getAuthor());
136 assertEquals(TestConstants.USER_ADMIN, comment.getUpdateAuthor());
137 }
138
139 private Issue parseIssue(final String resourcePath) throws JSONException {
140 final JSONObject issueJson = ResourceUtil.getJsonObjectFromResource(resourcePath);
141 final IssueJsonParser parser = new IssueJsonParser();
142 return parser.parse(issueJson);
143 }
144
145 @Test
146 public void testParseIssueWithResolution() throws JSONException {
147 final Issue issue = parseIssue("/json/issue/valid-all-expanded-with-resolution.json");
148 assertEquals("Incomplete", issue.getResolution().getName());
149
150 }
151
152 @Test
153 public void testParseIssueWhenWatchersAndVotersAreSwitchedOff() throws JSONException {
154 final Issue issue = parseIssue("/json/issue/valid-no-votes-no-watchers.json");
155 assertNull(issue.getWatchers());
156 assertNull(issue.getVotes());
157 }
158
159 @Test
160 public void testParseUnassignedIssue() throws JSONException {
161 final Issue issue = parseIssue("/json/issue/valid-unassigned.json");
162 assertNull(issue.getAssignee());
163 }
164
165 @Test
166 public void testParseNoTimeTrackingInfo() throws JSONException {
167 final Issue issue = parseIssue("/json/issue/valid-unassigned.json");
168 assertNull(issue.getTimeTracking());
169 }
170
171 @Test
172 public void testParseUnassignedIssueJira4x3() throws JSONException {
173 final Issue issue = parseIssue("/json/issue/valid-unassigned-jira-4.3.json");
174 assertNull(issue.getAssignee());
175 }
176
177 @Test
178 public void testParseIssueWithAnonymousComment() throws JSONException {
179 final Issue issue = parseIssue("/json/issue/valid-anonymous-comment-jira-4.3.json");
180 assertEquals(1, Iterables.size(issue.getComments()));
181 final Comment comment = issue.getComments().iterator().next();
182 assertEquals("A comment from anonymous user", comment.getBody());
183 assertNull(comment.getAuthor());
184
185 }
186
187 @Test
188 public void testParseIssueWithVisibilityJira4x3() throws JSONException {
189 final Issue issue = parseIssue("/json/issue/valid-visibility-jira-4.3.json");
190 assertEquals(Visibility.role("Administrators"), issue.getComments().iterator().next().getVisibility());
191 assertEquals(Visibility.role("Developers"), Iterables.get(issue.getWorklogs(), 1).getVisibility());
192 assertEquals(Visibility.group("jira-users"), Iterables.get(issue.getWorklogs(), 2).getVisibility());
193 }
194
195 @Test
196 public void testParseIssueWithUserPickerCustomFieldFilledOut() throws JSONException {
197 final Issue issue = parseIssue("/json/issue/valid-user-picker-custom-field-filled-out.json");
198 final Field extraUserField = issue.getFieldByName("Extra User");
199 assertNotNull(extraUserField);
200 assertEquals(BasicUser.class, extraUserField.getValue().getClass());
201 assertEquals(TestConstants.USER1, extraUserField.getValue());
202 }
203
204 @Test
205 public void testParseIssueWithUserPickerCustomFieldEmpty() throws JSONException {
206 final Issue issue = parseIssue("/json/issue/valid-user-picker-custom-field-empty.json");
207 final Field extraUserField = issue.getFieldByName("Extra User");
208 assertNotNull(extraUserField);
209 assertNull(extraUserField.getValue());
210 }
211
212 @Test
213 public void testParseIssueJira5x0Representation() throws JSONException {
214 final Issue issue = parseIssue("/json/issue/valid-5.0.json");
215 assertEquals(3, Iterables.size(issue.getComments()));
216 final BasicPriority priority = issue.getPriority();
217 assertNotNull(priority);
218 assertEquals("Major", priority.getName());
219 assertEquals("my description", issue.getDescription());
220 assertEquals("TST", issue.getProject().getKey());
221 assertNotNull(issue.getDueDate());
222 assertEquals(toDateTimeFromIsoDate("2010-07-05"), issue.getDueDate());
223 assertEquals(4, Iterables.size(issue.getAttachments()));
224 assertEquals(1, Iterables.size(issue.getIssueLinks()));
225 assertEquals(1.457, issue.getField("customfield_10000").getValue());
226 assertThat(Iterables.transform(issue.getComponents(), new BasicComponentNameExtractionFunction()), containsInAnyOrder("Component A", "Component B"));
227 assertEquals(2, Iterables.size(issue.getWorklogs()));
228 assertEquals(1, issue.getWatchers().getNumWatchers());
229 assertFalse(issue.getWatchers().isWatching());
230 assertEquals(new TimeTracking(2700, 2220, 180), issue.getTimeTracking());
231
232 assertEquals(Visibility.role("Developers"), issue.getWorklogs().iterator().next().getVisibility());
233 assertEquals(Visibility.group("jira-users"), Iterables.get(issue.getWorklogs(), 1).getVisibility());
234
235 }
236
237 @Test
238 public void testParseIssueJira50Representation() throws JSONException {
239 final Issue issue = parseIssue("/json/issue/valid-5.0-1.json");
240 assertEquals(0, Iterables.size(issue.getComments()));
241 final BasicPriority priority = issue.getPriority();
242 assertNull(priority);
243 assertEquals("Pivotal Tracker provides time tracking information on the project level.\n"
244 + "JIRA stores time tracking information on issue level, so this issue has been created to store imported time tracking information.", issue.getDescription());
245 assertEquals("TIMETRACKING", issue.getProject().getKey());
246 assertNull(issue.getDueDate());
247 assertEquals(0, Iterables.size(issue.getAttachments()));
248 assertNull(issue.getIssueLinks());
249 assertNull(issue.getField("customfield_10000").getValue());
250 assertThat(issue.getComponents(), IsEmptyIterable.<BasicComponent>emptyIterable());
251 assertEquals(2, Iterables.size(issue.getWorklogs()));
252 assertEquals(0, issue.getWatchers().getNumWatchers());
253 assertFalse(issue.getWatchers().isWatching());
254 assertEquals(new TimeTracking(null, null, 840), issue.getTimeTracking());
255
256 assertNull(issue.getWorklogs().iterator().next().getVisibility());
257 assertNull(Iterables.get(issue.getWorklogs(), 1).getVisibility());
258 }
259
260 @Test
261 public void testParseIssueWithProjectNamePresentInRepresentation() throws JSONException {
262 final Issue issue = parseIssue("/json/issue/issue-with-project-name-present.json");
263 assertEquals("My Test Project", issue.getProject().getName());
264 }
265
266 @Test
267 public void testParseIssueJiraRepresentationJrjc49() throws JSONException {
268 final Issue issue = parseIssue("/json/issue/jrjc49.json");
269 final Iterable<Worklog> worklogs = issue.getWorklogs();
270 assertEquals(1, Iterables.size(worklogs));
271 final Worklog worklog = Iterables.get(worklogs, 0);
272 assertNull(worklog.getComment());
273 assertEquals(180, worklog.getMinutesSpent());
274 assertEquals("Sample, User", worklog.getAuthor().getDisplayName());
275
276 }
277
278 @Test
279 public void testParseIssueJira5x0RepresentationNullCustomField() throws JSONException {
280 final Issue issue = parseIssue("/json/issue/valid-5.0-null-custom-field.json");
281 assertEquals(null, issue.getField("customfield_10000").getValue());
282 assertNull(issue.getIssueLinks());
283 }
284
285 @Test
286 public void issueWithSubtasks() throws JSONException {
287 final Issue issue = parseIssue("/json/issue/subtasks-5.json");
288 Iterable<Subtask> subtasks = issue.getSubtasks();
289 assertEquals(1, Iterables.size(subtasks));
290 Subtask subtask = Iterables.get(subtasks, 0, null);
291 assertNotNull(subtask);
292 assertEquals("SAM-2", subtask.getIssueKey());
293 assertEquals("Open", subtask.getStatus().getName());
294 assertEquals("Subtask", subtask.getIssueType().getName());
295 }
296
297 @Test
298 public void issueWithChangelog() throws JSONException {
299 final Issue issue = parseIssue("/json/issue/valid-5.0-with-changelog.json");
300 assertEquals("HST-1", issue.getKey());
301
302 final Iterable<ChangelogGroup> changelog = issue.getChangelog();
303 assertNotNull(changelog);
304
305 assertEquals(4, Iterables.size(changelog));
306 final Iterator<ChangelogGroup> iterator = changelog.iterator();
307
308 final BasicUser user1 = new BasicUser(toUri("http://localhost:2990/jira/rest/api/2/user?username=user1"), "user1", "User One");
309 final BasicUser user2 = new BasicUser(toUri("http://localhost:2990/jira/rest/api/2/user?username=user2"), "user2", "User Two");
310
311 verifyChangelog(iterator.next(),
312 "2012-04-12T14:28:28.255+0200",
313 user1,
314 ImmutableList.of(
315 new ChangelogItem(ChangelogItem.FieldType.JIRA, "duedate", null, null, "2012-04-12", "2012-04-12 00:00:00.0"),
316 new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "Radio Field", null, null, "10000", "One")
317 ));
318
319 verifyChangelog(iterator.next(),
320 "2012-04-12T14:28:44.079+0200",
321 user1,
322 ImmutableList.of(
323 new ChangelogItem(ChangelogItem.FieldType.JIRA, "assignee", "user1", "User One", "user2", "User Two")
324 ));
325
326 verifyChangelog(iterator.next(),
327 "2012-04-12T14:30:09.690+0200",
328 user2,
329 ImmutableList.of(
330 new ChangelogItem(ChangelogItem.FieldType.JIRA, "summary", null, "Simple history test", null, "Simple history test - modified"),
331 new ChangelogItem(ChangelogItem.FieldType.JIRA, "issuetype", "1", "Bug", "2", "New Feature"),
332 new ChangelogItem(ChangelogItem.FieldType.JIRA, "priority", "3", "Major", "4", "Minor"),
333 new ChangelogItem(ChangelogItem.FieldType.JIRA, "description", null, "Initial Description", null, "Modified Description"),
334 new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "Date Field", "2012-04-11T14:26+0200", "11/Apr/12 2:26 PM", "2012-04-12T14:26+0200", "12/Apr/12 2:26 PM"),
335 new ChangelogItem(ChangelogItem.FieldType.JIRA, "duedate", "2012-04-12", "2012-04-12 00:00:00.0", "2012-04-13", "2012-04-13 00:00:00.0"),
336 new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "Radio Field", "10000", "One", "10001", "Two"),
337 new ChangelogItem(ChangelogItem.FieldType.CUSTOM, "Text Field", null, "Initial text field value", null, "Modified text field value")
338 ));
339
340 verifyChangelog(iterator.next(),
341 "2012-04-12T14:28:44.079+0200",
342 null,
343 ImmutableList.of(
344 new ChangelogItem(ChangelogItem.FieldType.JIRA, "assignee", "user1", "User One", "user2", "User Two")
345 ));
346 }
347
348 private static void verifyChangelog(ChangelogGroup changelogGroup, String createdDate, BasicUser author, Iterable<ChangelogItem> expectedItems) {
349 assertEquals(ISODateTimeFormat.dateTime().parseDateTime(createdDate), changelogGroup.getCreated());
350 assertEquals(author, changelogGroup.getAuthor());
351 assertEquals(expectedItems, changelogGroup.getItems());
352 }
353
354 @Test
355 public void testParseIssueWithLabelsForJira5x0() throws JSONException {
356 final Issue issue = parseIssue("/json/issue/valid-5.0-with-labels.json");
357 assertThat(issue.getLabels(), containsInAnyOrder("a", "bcds"));
358 }
359
360 @Test
361 public void testParseIssueWithLabels() throws JSONException {
362 final Issue issue = parseIssue("/json/issue/valid-5.0-with-labels.json");
363 assertThat(issue.getLabels(), containsInAnyOrder("a", "bcds"));
364 }
365
366 @Test
367 public void testParseIssueWithoutLabelsForJira5x0() throws JSONException {
368 final Issue issue = parseIssue("/json/issue/valid-5.0-without-labels.json");
369 assertThat(issue.getLabels(), IsEmptyCollection.<String>empty());
370 }
371
372 @Test
373 public void testParseIssueWithoutLabels() throws JSONException {
374 final Issue issue = parseIssue("/json/issue/valid-without-labels.json");
375 assertThat(issue.getLabels(), IsEmptyCollection.<String>empty());
376 }
377
378 }