Skip to content

Commit dd8d7cf

Browse files
committed
prevent NPE by collections4 Optional, rewrite tests
1 parent 4d64b44 commit dd8d7cf

File tree

3 files changed

+189
-147
lines changed

3 files changed

+189
-147
lines changed

src/main/java/hudson/plugins/jira/JiraSession.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
package hudson.plugins.jira;
22

3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Optional;
10+
import java.util.Set;
11+
import java.util.concurrent.TimeoutException;
12+
import java.util.logging.Logger;
13+
import java.util.regex.Matcher;
14+
import java.util.regex.Pattern;
15+
16+
import org.apache.commons.lang.StringUtils;
317
import static org.apache.commons.lang.StringUtils.isNotEmpty;
418

519
import com.atlassian.jira.rest.client.api.domain.BasicIssue;
@@ -11,22 +25,11 @@
1125
import com.atlassian.jira.rest.client.api.domain.Status;
1226
import com.atlassian.jira.rest.client.api.domain.Transition;
1327
import com.atlassian.jira.rest.client.api.domain.Version;
28+
1429
import edu.umd.cs.findbugs.annotations.NonNull;
1530
import edu.umd.cs.findbugs.annotations.Nullable;
1631
import hudson.plugins.jira.extension.ExtendedVersion;
1732
import hudson.plugins.jira.model.JiraIssueField;
18-
import java.util.ArrayList;
19-
import java.util.Collections;
20-
import java.util.HashMap;
21-
import java.util.HashSet;
22-
import java.util.List;
23-
import java.util.Map;
24-
import java.util.Set;
25-
import java.util.concurrent.TimeoutException;
26-
import java.util.logging.Logger;
27-
import java.util.regex.Matcher;
28-
import java.util.regex.Pattern;
29-
import org.apache.commons.lang.StringUtils;
3033

3134
/**
3235
* Connection to Jira.
@@ -266,31 +269,27 @@ public void replaceFixVersion(String projectKey, String fromVersion, String toVe
266269
Set<Version> newVersions = new HashSet<>();
267270
newVersions.add(newVersion);
268271

272+
Iterable<Version> issueVersions =
273+
Optional.of(issue.getFixVersions()).orElse(Collections.emptyList());
274+
LOGGER.fine(String.format("[%s] current versions: %s", issue.getKey(), issueVersions));
275+
269276
if (StringUtils.startsWith(fromVersion, "/") && StringUtils.endsWith(fromVersion, "/")) {
270277

271278
String regEx = StringUtils.removeStart(fromVersion, "/");
272279
regEx = StringUtils.removeEnd(regEx, "/");
273-
274-
LOGGER.fine("Using regular expression: " + regEx);
275-
276280
Pattern fromVersionPattern = Pattern.compile(regEx);
281+
LOGGER.fine("Using regular expression: " + regEx);
277282

278-
Iterable<Version> versions = issue.getFixVersions();
279-
if (versions != null) {
280-
for (Version currentVersion : versions) {
281-
Matcher versionToRemove = fromVersionPattern.matcher(currentVersion.getName());
282-
if (!versionToRemove.matches()) {
283-
newVersions.add(currentVersion);
284-
}
283+
for (Version currentVersion : issueVersions) {
284+
Matcher versionToRemove = fromVersionPattern.matcher(currentVersion.getName());
285+
if (!versionToRemove.matches()) {
286+
newVersions.add(currentVersion);
285287
}
286288
}
287289
} else {
288-
Iterable<Version> versions = issue.getFixVersions();
289-
if (versions != null) {
290-
for (Version currentVersion : versions) {
291-
if (!currentVersion.getName().equals(fromVersion)) {
292-
newVersions.add(currentVersion);
293-
}
290+
for (Version currentVersion : issueVersions) {
291+
if (!currentVersion.getName().equals(fromVersion)) {
292+
newVersions.add(currentVersion);
294293
}
295294
}
296295
}

src/test/java/hudson/plugins/jira/JiraReplaceFixVersionByRegExTest.java

Lines changed: 0 additions & 119 deletions
This file was deleted.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package hudson.plugins.jira;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.equalTo;
5+
import static org.hamcrest.Matchers.hasItem;
6+
import static org.hamcrest.Matchers.hasProperty;
7+
import static org.mockito.Mockito.spy;
8+
import static org.mockito.Mockito.times;
9+
import static org.mockito.Mockito.verify;
10+
import static org.mockito.Mockito.when;
11+
12+
import com.atlassian.jira.rest.client.api.domain.Issue;
13+
import com.atlassian.jira.rest.client.api.domain.Version;
14+
import hudson.plugins.jira.extension.ExtendedVersion;
15+
import java.io.IOException;
16+
import java.net.URI;
17+
import java.net.URISyntaxException;
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.List;
21+
import java.util.concurrent.ThreadLocalRandom;
22+
import java.util.concurrent.TimeoutException;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.extension.ExtendWith;
26+
import org.mockito.ArgumentCaptor;
27+
import org.mockito.Mock;
28+
import org.mockito.junit.jupiter.MockitoExtension;
29+
30+
@ExtendWith(MockitoExtension.class)
31+
class JiraSessionTest {
32+
33+
private static final String PROJECT_KEY = "myKey";
34+
private static final String QUERY = "query";
35+
36+
private JiraSession jiraSession = null;
37+
38+
@Mock
39+
private JiraSite site;
40+
41+
@Mock
42+
private JiraRestService service = null;
43+
44+
@BeforeEach
45+
void prepareMocks() throws IOException, InterruptedException {
46+
jiraSession = spy(new JiraSession(site, service));
47+
}
48+
49+
@Test
50+
void replaceWithFixVersionByRegex() throws URISyntaxException, TimeoutException {
51+
final ExtendedVersion newVersion =
52+
new ExtendedVersion(new URI("self"), 3L, "v3.0", null, false, false, null, null);
53+
List<ExtendedVersion> myVersions = new ArrayList<>();
54+
myVersions.add(newVersion);
55+
when(jiraSession.getVersions(PROJECT_KEY)).thenReturn(myVersions);
56+
57+
ArrayList<Issue> issues = new ArrayList<>();
58+
issues.add(getIssue(Arrays.asList("v1.0"), 1L));
59+
issues.add(getIssue(Arrays.asList("v1.0", "v2.0", "v2.0.0"), 2L));
60+
when(service.getIssuesFromJqlSearch(QUERY, JiraSession.MAX_ISSUES)).thenReturn(issues);
61+
62+
jiraSession.replaceFixVersion(PROJECT_KEY, "/v1.*/", newVersion.getName(), QUERY);
63+
64+
ArgumentCaptor<String> issueKeys = ArgumentCaptor.forClass(String.class);
65+
ArgumentCaptor<List> versionList = ArgumentCaptor.forClass(List.class);
66+
verify(service, times(2)).updateIssue(issueKeys.capture(), versionList.capture());
67+
68+
// First Issue, current FixVersion replaced by new one
69+
assertThat(issueKeys.getAllValues().get(0), equalTo(issues.get(0).getKey()));
70+
List<ExtendedVersion> firstIssueUpdatedFixVersions =
71+
versionList.getAllValues().get(0);
72+
assertThat(firstIssueUpdatedFixVersions.size(), equalTo(1));
73+
assertThat(firstIssueUpdatedFixVersions.get(0).getName(), equalTo(newVersion.getName()));
74+
75+
// Second Issue, current FixVersion stays, new fixVersion added.
76+
assertThat(issueKeys.getAllValues().get(1), equalTo(issues.get(1).getKey()));
77+
List<ExtendedVersion> secondIssueUpdatedFixVersions =
78+
versionList.getAllValues().get(1);
79+
assertThat(secondIssueUpdatedFixVersions.size(), equalTo(3));
80+
81+
// Check that the collection contains versions with these names in any order
82+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo(newVersion.getName()))));
83+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo("v2.0"))));
84+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo("v2.0.0"))));
85+
}
86+
87+
@Test
88+
void replaceFixVersion() throws URISyntaxException, TimeoutException {
89+
final ExtendedVersion newVersion =
90+
new ExtendedVersion(new URI("self"), 3L, "v3.0", null, false, false, null, null);
91+
List<ExtendedVersion> myVersions = new ArrayList<>();
92+
myVersions.add(newVersion);
93+
when(jiraSession.getVersions(PROJECT_KEY)).thenReturn(myVersions);
94+
95+
ArrayList<Issue> issues = new ArrayList<>();
96+
issues.add(getIssue(Arrays.asList("v1.0"), 1L));
97+
issues.add(getIssue(Arrays.asList("v1.0", "v1.0.0", "v2.0.0"), 2L));
98+
when(service.getIssuesFromJqlSearch(QUERY, JiraSession.MAX_ISSUES)).thenReturn(issues);
99+
100+
jiraSession.replaceFixVersion(PROJECT_KEY, "v1.0", newVersion.getName(), QUERY);
101+
102+
ArgumentCaptor<String> issueKeys = ArgumentCaptor.forClass(String.class);
103+
ArgumentCaptor<List> versionList = ArgumentCaptor.forClass(List.class);
104+
verify(service, times(2)).updateIssue(issueKeys.capture(), versionList.capture());
105+
106+
// First Issue, current FixVersion replaced by new one
107+
assertThat(issueKeys.getAllValues().get(0), equalTo(issues.get(0).getKey()));
108+
List<Version> firstIssueUpdatedFixVersions = versionList.getAllValues().get(0);
109+
assertThat(firstIssueUpdatedFixVersions.size(), equalTo(1));
110+
assertThat(firstIssueUpdatedFixVersions.get(0), equalTo(newVersion));
111+
112+
// Second Issue, current FixVersion stays, new fixVersion added.
113+
assertThat(issueKeys.getAllValues().get(1), equalTo(issues.get(1).getKey()));
114+
List<Version> secondIssueUpdatedFixVersions = versionList.getAllValues().get(1);
115+
assertThat(secondIssueUpdatedFixVersions.size(), equalTo(3));
116+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo(newVersion.getName()))));
117+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo("v1.0.0"))));
118+
assertThat(secondIssueUpdatedFixVersions, hasItem(hasProperty("name", equalTo("v2.0.0"))));
119+
}
120+
121+
private Issue getIssue(List<String> versions, long id) throws URISyntaxException {
122+
List<Version> fixVersions = new ArrayList<>();
123+
for (String fixVersion : versions) {
124+
fixVersions.add(new Version(
125+
new URI("self"), ThreadLocalRandom.current().nextLong(), fixVersion, null, false, false, null));
126+
}
127+
return new Issue(
128+
"",
129+
new URI(""),
130+
PROJECT_KEY + id,
131+
ThreadLocalRandom.current().nextLong(),
132+
null,
133+
null,
134+
null,
135+
null,
136+
null,
137+
null,
138+
null,
139+
null,
140+
null,
141+
null,
142+
null,
143+
null,
144+
null,
145+
fixVersions,
146+
null,
147+
null,
148+
null,
149+
null,
150+
null,
151+
null,
152+
null,
153+
null,
154+
null,
155+
null,
156+
null,
157+
null,
158+
null,
159+
null,
160+
null);
161+
}
162+
}

0 commit comments

Comments
 (0)