]> source.dussan.org Git - sonarqube.git/blob
5b915f3f6b470cece665bfe7a858c0bf53d8028f
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2020 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.issue.workflow;
21
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import java.util.Arrays;
26 import java.util.Calendar;
27 import java.util.Collection;
28 import java.util.Date;
29 import java.util.List;
30 import org.apache.commons.lang.time.DateUtils;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 import org.sonar.api.issue.DefaultTransitions;
34 import org.sonar.api.rule.RuleKey;
35 import org.sonar.api.rules.RuleType;
36 import org.sonar.core.issue.DefaultIssue;
37 import org.sonar.core.issue.FieldDiffs;
38 import org.sonar.core.issue.IssueChangeContext;
39 import org.sonar.core.util.stream.MoreCollectors;
40 import org.sonar.server.issue.IssueFieldsSetter;
41
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
44 import static org.sonar.api.issue.Issue.RESOLUTION_REMOVED;
45 import static org.sonar.api.issue.Issue.STATUS_CLOSED;
46 import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
47 import static org.sonar.api.issue.Issue.STATUS_REVIEWED;
48 import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
49 import static org.sonar.db.rule.RuleTesting.XOO_X1;
50
51 @RunWith(DataProviderRunner.class)
52 public class IssueWorkflowForSecurityHotspotsTest {
53
54   private static final String[] ALL_STATUSES_LEADING_TO_CLOSED = new String[] {STATUS_TO_REVIEW, STATUS_RESOLVED};
55
56   private static final String[] SUPPORTED_RESOLUTIONS_FOR_UNCLOSING = new String[] {RESOLUTION_FIXED, RESOLUTION_REMOVED};
57
58   private IssueFieldsSetter updater = new IssueFieldsSetter();
59
60   private IssueWorkflow underTest = new IssueWorkflow(new FunctionExecutor(updater), updater);
61
62   @DataProvider
63   public static Object[][] allStatusesLeadingToClosed() {
64     return Arrays.stream(ALL_STATUSES_LEADING_TO_CLOSED)
65       .map(t -> new Object[] {t})
66       .toArray(Object[][]::new);
67   }
68
69   private static DefaultIssue newClosedIssue(String resolution) {
70     return new DefaultIssue()
71       .setKey("ABCDE")
72       .setRuleKey(RuleKey.of("js", "S001"))
73       .setResolution(resolution)
74       .setStatus(STATUS_CLOSED)
75       .setNew(false)
76       .setCloseDate(new Date(5_999_999L));
77   }
78
79   private static void setStatusPreviousToClosed(DefaultIssue issue, String previousStatus) {
80     addStatusChange(issue, new Date(), previousStatus, STATUS_CLOSED);
81   }
82
83   private static void addStatusChange(DefaultIssue issue, Date date, String previousStatus, String newStatus) {
84     issue.addChange(new FieldDiffs().setCreationDate(date).setDiff("status", previousStatus, newStatus));
85   }
86
87   @Test
88   public void list_out_transitions_in_status_to_review() {
89     underTest.start();
90     DefaultIssue issue = new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(STATUS_TO_REVIEW);
91
92     List<Transition> transitions = underTest.outTransitions(issue);
93
94     assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed");
95   }
96
97   @Test
98   public void list_out_transitions_in_status_reviewed() {
99     underTest.start();
100     DefaultIssue issue = new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(STATUS_REVIEWED);
101
102     List<Transition> transitions = underTest.outTransitions(issue);
103
104     assertThat(keys(transitions)).containsExactlyInAnyOrder("resetastoreview");
105   }
106
107   @Test
108   public void resolve_as_reviewed_from_to_review() {
109     underTest.start();
110     DefaultIssue issue = new DefaultIssue()
111       .setType(RuleType.SECURITY_HOTSPOT)
112       .setStatus(STATUS_TO_REVIEW);
113
114     boolean result = underTest.doManualTransition(issue, DefaultTransitions.RESOLVE_AS_REVIEWED, IssueChangeContext.createUser(new Date(), "USER1"));
115
116     assertThat(result).isTrue();
117     assertThat(issue.getStatus()).isEqualTo(STATUS_REVIEWED);
118     assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED);
119   }
120
121   @Test
122   public void reset_as_to_review_from_reviewed() {
123     underTest.start();
124     DefaultIssue issue = new DefaultIssue()
125       .setType(RuleType.SECURITY_HOTSPOT)
126       .setStatus(STATUS_REVIEWED)
127       .setResolution(RESOLUTION_FIXED);
128
129     boolean result = underTest.doManualTransition(issue, DefaultTransitions.RESET_AS_TO_REVIEW, IssueChangeContext.createUser(new Date(), "USER1"));
130     assertThat(result).isTrue();
131     assertThat(issue.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);
132     assertThat(issue.getStatus()).isEqualTo(STATUS_TO_REVIEW);
133     assertThat(issue.resolution()).isNull();
134   }
135
136   @Test
137   public void automatically_close_resolved_security_hotspots_in_status_to_review() {
138     underTest.start();
139     DefaultIssue issue = new DefaultIssue()
140       .setType(RuleType.SECURITY_HOTSPOT)
141       .setResolution(null)
142       .setStatus(STATUS_TO_REVIEW)
143       .setNew(false)
144       .setBeingClosed(true);
145     Date now = new Date();
146
147     underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
148
149     assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED);
150     assertThat(issue.status()).isEqualTo(STATUS_CLOSED);
151     assertThat(issue.closeDate()).isNotNull();
152     assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
153   }
154
155   @Test
156   public void automatically_close_resolved_security_hotspots_in_status_reviewed() {
157     underTest.start();
158     DefaultIssue issue = new DefaultIssue()
159       .setType(RuleType.SECURITY_HOTSPOT)
160       .setResolution(RESOLUTION_FIXED)
161       .setStatus(STATUS_REVIEWED)
162       .setNew(false)
163       .setBeingClosed(true);
164     Date now = new Date();
165
166     underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
167
168     assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED);
169     assertThat(issue.status()).isEqualTo(STATUS_CLOSED);
170     assertThat(issue.closeDate()).isNotNull();
171     assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
172   }
173
174   @Test
175   @UseDataProvider("allStatusesLeadingToClosed")
176   public void do_not_automatically_reopen_closed_issues_of_security_hotspots(String previousStatus) {
177     DefaultIssue[] issues = Arrays.stream(SUPPORTED_RESOLUTIONS_FOR_UNCLOSING)
178       .map(resolution -> {
179         DefaultIssue issue = newClosedIssue(resolution);
180         setStatusPreviousToClosed(issue, previousStatus);
181         issue.setType(RuleType.SECURITY_HOTSPOT);
182         return issue;
183       })
184       .toArray(DefaultIssue[]::new);
185     Date now = new Date();
186     underTest.start();
187
188     Arrays.stream(issues).forEach(issue -> {
189       underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
190
191       assertThat(issue.status()).isEqualTo(STATUS_CLOSED);
192       assertThat(issue.updateDate()).isNull();
193     });
194   }
195
196   @Test
197   public void doAutomaticTransition_does_nothing_on_security_hotspots_in_to_review_status() {
198     DefaultIssue issue = new DefaultIssue()
199       .setKey("ABCDE")
200       .setRuleKey(XOO_X1)
201       .setResolution(null)
202       .setStatus(STATUS_TO_REVIEW);
203
204     underTest.start();
205     underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(new Date()));
206
207     assertThat(issue.status()).isEqualTo(STATUS_TO_REVIEW);
208     assertThat(issue.resolution()).isNull();
209   }
210
211   private Collection<String> keys(List<Transition> transitions) {
212     return transitions.stream().map(Transition::key).collect(MoreCollectors.toList());
213   }
214 }