]> source.dussan.org Git - sonarqube.git/blob
cefd7097832a45196ffa9ef054085967c6d3221f
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 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
21 package org.sonar.server.platform.db.migration.version.v78;
22
23 import java.sql.SQLException;
24 import javax.annotation.Nullable;
25 import org.apache.commons.lang.math.RandomUtils;
26 import org.assertj.core.groups.Tuple;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.sonar.api.config.internal.MapSettings;
30 import org.sonar.api.utils.internal.TestSystem2;
31 import org.sonar.core.util.UuidFactoryFast;
32 import org.sonar.db.CoreDbTester;
33 import org.sonar.server.platform.db.migration.es.MigrationEsClient;
34 import org.sonar.server.platform.db.migration.step.DataChange;
35
36 import static java.util.stream.Collectors.toList;
37 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
38 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
39 import static org.assertj.core.api.Assertions.assertThat;
40 import static org.assertj.core.api.Assertions.tuple;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.verify;
43
44 public class UpdateSecurityHotspotsStatusesTest {
45
46   private static final long PAST = 5_000_000_000L;
47   private static final long NOW = 10_000_000_000L;
48
49   @Rule
50   public CoreDbTester db = CoreDbTester.createForSchema(UpdateSecurityHotspotsStatusesTest.class, "schema.sql");
51
52   private MapSettings settings = new MapSettings();
53   private TestSystem2 system2 = new TestSystem2().setNow(NOW);
54   private MigrationEsClient esClient = mock(MigrationEsClient.class);
55
56   private DataChange underTest = new UpdateSecurityHotspotsStatuses(db.database(), settings.asConfig(), system2, esClient, UuidFactoryFast.getInstance());
57
58   @Test
59   public void migrate_open_and_reopen_hotspots() throws SQLException {
60     int rule = insertRule(4);
61     String issue1 = insertIssue("OPEN", null, 4, rule);
62     String issue2 = insertIssue("REOPENED", null, 4, rule);
63     // Other type of issues should not be updated
64     String issue3 = insertIssue("OPEN", null, 1, rule);
65     String issue4 = insertIssue("REOPENED", null, 2, rule);
66     String issue5 = insertIssue("OPEN", null, 3, rule);
67
68     underTest.execute();
69
70     assertIssues(
71       tuple(issue1, "TOREVIEW", null, 4, NOW),
72       tuple(issue2, "TOREVIEW", null, 4, NOW),
73       // Not updated
74       tuple(issue3, "OPEN", null, 1, PAST),
75       tuple(issue4, "REOPENED", null, 2, PAST),
76       tuple(issue5, "OPEN", null, 3, PAST));
77   }
78
79   @Test
80   public void migrate_resolved_as_fixed_and_wont_fix_hotspots() throws SQLException {
81     int rule = insertRule(4);
82     String issue1 = insertIssue("RESOLVED", "FIXED", 4, rule);
83     String issue2 = insertIssue("RESOLVED", "WONTFIX", 4, rule);
84     // Other type of issues should not be updated
85     String issue3 = insertIssue("RESOLVED", "FIXED", 1, rule);
86     String issue4 = insertIssue("RESOLVED", "WONTFIX", 2, rule);
87     String issue5 = insertIssue("RESOLVED", "WONTFIX", 3, rule);
88
89     underTest.execute();
90
91     assertIssues(
92       tuple(issue1, "INREVIEW", null, 4, NOW),
93       tuple(issue2, "REVIEWED", "FIXED", 4, NOW),
94       // Not updated
95       tuple(issue3, "RESOLVED", "FIXED", 1, PAST),
96       tuple(issue4, "RESOLVED", "WONTFIX", 2, PAST),
97       tuple(issue5, "RESOLVED", "WONTFIX", 3, PAST));
98   }
99
100   @Test
101   public void insert_issue_changes() throws SQLException {
102     int rule = insertRule(4);
103     String issue1 = insertIssue("REOPENED", null, 4, rule);
104     // No changelog on OPEN issue as there was no previous state
105     String issue2 = insertIssue("OPEN", null, 4, rule);
106     String issue3 = insertIssue("RESOLVED", "FIXED", 4, rule);
107     String issue4 = insertIssue("RESOLVED", "WONTFIX", 4, rule);
108
109     underTest.execute();
110
111     assertIssueChanges(
112       tuple(issue1, "diff", "status=REOPENED|TOREVIEW,resolution=", NOW, NOW, NOW),
113       tuple(issue3, "diff", "status=RESOLVED|INREVIEW,resolution=FIXED|", NOW, NOW, NOW),
114       tuple(issue4, "diff", "status=RESOLVED|REVIEWED,resolution=WONTFIX|FIXED", NOW, NOW, NOW));
115   }
116
117   @Test
118   public void do_not_update_vulnerabilities_coming_from_hotspot() throws SQLException {
119     int rule = insertRule(4);
120     String issue1 = insertIssue("OPEN", null, 3, rule);
121
122     underTest.execute();
123
124     assertIssues(tuple(issue1, "OPEN", null, 3, PAST));
125     assertNoIssueChanges();
126   }
127
128   @Test
129   public void do_not_update_closed_hotspots() throws SQLException {
130     int rule = insertRule(4);
131     String issue1 = insertIssue("CLOSED", "FIXED", 4, rule);
132     String issue2 = insertIssue("CLOSED", "REMOVED", 4, rule);
133
134     underTest.execute();
135
136     assertIssues(
137       tuple(issue1, "CLOSED", "FIXED", 4, PAST),
138       tuple(issue2, "CLOSED", "REMOVED", 4, PAST));
139     assertNoIssueChanges();
140   }
141
142   @Test
143   public void do_nothing_on_sonarcloud() throws SQLException {
144     settings.setProperty("sonar.sonarcloud.enabled", "true");
145     int rule = insertRule(4);
146     String issue1 = insertIssue("OPEN", null, 4, rule);
147
148     underTest.execute();
149
150     assertIssues(tuple(issue1, "OPEN", null, 4, PAST));
151     assertNoIssueChanges();
152   }
153
154   @Test
155   public void migration_is_reentrant() throws SQLException {
156     int rule = insertRule(4);
157     String issue1 = insertIssue("OPEN", null, 4, rule);
158     String issue2 = insertIssue("REOPENED", null, 4, rule);
159
160     underTest.execute();
161     assertIssues(
162       tuple(issue1, "TOREVIEW", null, 4, NOW),
163       tuple(issue2, "TOREVIEW", null, 4, NOW));
164
165     // Set a new date for NOW in order to check that issues has not been updated again
166     system2.setNow(NOW + 1_000_000_000L);
167     underTest.execute();
168     assertIssues(
169       tuple(issue1, "TOREVIEW", null, 4, NOW),
170       tuple(issue2, "TOREVIEW", null, 4, NOW));
171   }
172
173   @Test
174   public void issues_index_is_removed() throws SQLException {
175     underTest.execute();
176
177     verify(esClient).deleteIndexes("issues");
178   }
179
180   private void assertIssues(Tuple... expectedTuples) {
181     assertThat(db.select("SELECT kee, status, resolution, issue_type, updated_at FROM issues")
182       .stream()
183       .map(map -> new Tuple(map.get("KEE"), map.get("STATUS"), map.get("RESOLUTION"), map.get("ISSUE_TYPE"), map.get("UPDATED_AT")))
184       .collect(toList()))
185         .containsExactlyInAnyOrder(expectedTuples);
186   }
187
188   private void assertNoIssueChanges() {
189     assertThat(db.countRowsOfTable("issue_changes")).isZero();
190   }
191
192   private void assertIssueChanges(Tuple... expectedTuples) {
193     assertThat(db.select("SELECT issue_key, change_type, change_data, created_at, updated_at, issue_change_creation_date FROM issue_changes")
194       .stream()
195       .map(map -> new Tuple(map.get("ISSUE_KEY"), map.get("CHANGE_TYPE"), map.get("CHANGE_DATA"), map.get("CREATED_AT"), map.get("UPDATED_AT"),
196         map.get("ISSUE_CHANGE_CREATION_DATE")))
197       .collect(toList()))
198         .containsExactlyInAnyOrder(expectedTuples);
199   }
200
201   private String insertIssue(String status, @Nullable String resolution, int issueType, int ruleId) {
202     String issueKey = randomAlphabetic(3);
203     db.executeInsert(
204       "ISSUES",
205       "KEE", issueKey,
206       "STATUS", status,
207       "RESOLUTION", resolution,
208       "RULE_ID", ruleId,
209       "ISSUE_TYPE", issueType,
210       "COMPONENT_UUID", randomAlphanumeric(10),
211       "PROJECT_UUID", randomAlphanumeric(10),
212       "MANUAL_SEVERITY", false,
213       "CREATED_AT", PAST,
214       "UPDATED_AT", PAST);
215     return issueKey;
216   }
217
218   private int insertRule(int ruleType) {
219     int id = RandomUtils.nextInt();
220     db.executeInsert("RULES",
221       "ID", id,
222       "RULE_TYPE", ruleType,
223       "IS_EXTERNAL", false,
224       "PLUGIN_RULE_KEY", randomAlphanumeric(3),
225       "PLUGIN_NAME", randomAlphanumeric(3),
226       "SCOPE", "MAIN",
227       "IS_AD_HOC", false,
228       "CREATED_AT", PAST,
229       "UPDATED_AT", PAST);
230     return id;
231   }
232
233 }