3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.platform.db.migration.version.v108;
22 import java.sql.SQLException;
23 import java.util.HashMap;
25 import java.util.stream.Collectors;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.junit.jupiter.api.extension.RegisterExtension;
29 import org.sonar.core.util.UuidFactoryImpl;
30 import org.sonar.db.MigrationDbTester;
32 import static org.assertj.core.api.Assertions.assertThat;
33 import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY;
34 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES_KEY;
35 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES_KEY;
36 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES_KEY;
37 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY;
38 import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY;
39 import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY;
40 import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY;
41 import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY;
42 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY;
43 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY;
44 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES_KEY;
45 import static org.sonar.server.platform.db.migration.version.v108.MeasureMigration.MIGRATION_MAP;
47 class MigrateProjectMeasuresDeprecatedMetricsTest {
48 private static final String ANALYSIS_UUID_1 = UuidFactoryImpl.INSTANCE.create();
49 private static final String ANALYSIS_UUID_2 = UuidFactoryImpl.INSTANCE.create();
51 private final MigrationDbTester db = MigrationDbTester.createForMigrationStep(MigrateProjectMeasuresDeprecatedMetrics.class);
52 private final MigrateProjectMeasuresDeprecatedMetrics underTest = new MigrateProjectMeasuresDeprecatedMetrics(db.database(),
53 UuidFactoryImpl.INSTANCE);
54 private Map<String, String> metricsToMigrate;
55 private Map<String, String> replacementMetrics;
59 metricsToMigrate = insertMetricsToMigrate();
60 replacementMetrics = insertReplacementMetrics();
64 void execute_shouldCreateNewMetrics() throws SQLException {
65 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "1");
66 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(RELIABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "3");
67 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(SECURITY_ISSUES_KEY), ANALYSIS_UUID_1, "5");
68 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "11");
69 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_RELIABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "13");
70 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_SECURITY_ISSUES_KEY), ANALYSIS_UUID_1, "15");
73 assertThat(db.select("select metric_uuid, value from project_measures where metric_uuid in (%s)"
74 .formatted(replacementMetrics.values().stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")))))
76 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), "value", 1.0)))
77 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY), "value", 3.0)))
78 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_SECURITY_ISSUES_KEY), "value", 5.0)))
79 .contains((Map.of("metric_uuid", replacementMetrics.get(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), "value", 11.0)))
80 .contains((Map.of("metric_uuid", replacementMetrics.get(NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY), "value", 13.0)))
81 .contains((Map.of("metric_uuid", replacementMetrics.get(NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY), "value", 15.0)));
85 void execute_shouldBeReentrant() throws SQLException {
86 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "1");
87 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(RELIABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "3");
88 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(SECURITY_ISSUES_KEY), ANALYSIS_UUID_1, "5");
89 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "11");
90 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_RELIABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "13");
91 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(NEW_SECURITY_ISSUES_KEY), ANALYSIS_UUID_1, "15");
94 assertThat(db.select("select * from project_measures"))
95 .hasSize(MIGRATION_MAP.size() * 2);
99 void execute_whenValueCannotBeConverted_shouldCreateOtherNewMetrics() throws SQLException {
100 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "1");
101 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(RELIABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "NOT_VALID_NUMBER");
102 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(SECURITY_ISSUES_KEY), ANALYSIS_UUID_1, "5");
105 assertThat(db.select("select metric_uuid, value from project_measures where metric_uuid in (%s)"
106 .formatted(replacementMetrics.values().stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")))))
108 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), "value", 1.0)))
109 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_SECURITY_ISSUES_KEY), "value", 5.0)));
113 void execute_whenWasPartiallyMigrated_shouldContinueWithOtherAnalysis() throws SQLException {
115 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, "1");
116 createProjectMeasureForNewMetric(replacementMetrics.get(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_1, 1);
118 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(MAINTAINABILITY_ISSUES_KEY), ANALYSIS_UUID_2, "4");
119 createProjectMeasureForDeprecatedMetric(metricsToMigrate.get(SECURITY_ISSUES_KEY), ANALYSIS_UUID_2, "5");
122 assertThat(db.select("select metric_uuid, value, analysis_uuid from project_measures where metric_uuid in (%s)"
123 .formatted(replacementMetrics.values().stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")))))
125 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), "value", 1.0, "analysis_uuid"
127 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY), "value", 4.0, "analysis_uuid"
129 .contains((Map.of("metric_uuid", replacementMetrics.get(SOFTWARE_QUALITY_SECURITY_ISSUES_KEY), "value", 5.0, "analysis_uuid",
133 private void createProjectMeasureForDeprecatedMetric(String metricUuid, String analysisUuid, String totalIssues) {
134 String uuid = UuidFactoryImpl.INSTANCE.create();
135 Map<String, Object> map = Map.ofEntries(
136 Map.entry("UUID", uuid),
137 Map.entry("TEXT_VALUE", "{\"LOW\":X,\"MEDIUM\":Y,\"HIGH\":Z,\"total\":" + totalIssues + "}"),
138 Map.entry("ANALYSIS_UUID", analysisUuid),
139 Map.entry("METRIC_UUID", metricUuid),
140 Map.entry("COMPONENT_UUID", UuidFactoryImpl.INSTANCE.create()));
141 db.executeInsert("project_measures", map);
144 private void createProjectMeasureForNewMetric(String metricUuid, String analysisUuid, int totalIssues) {
145 String uuid = UuidFactoryImpl.INSTANCE.create();
146 Map<String, Object> map = Map.ofEntries(
147 Map.entry("UUID", uuid),
148 Map.entry("VALUE", totalIssues),
149 Map.entry("ANALYSIS_UUID", analysisUuid),
150 Map.entry("METRIC_UUID", metricUuid),
151 Map.entry("COMPONENT_UUID", UuidFactoryImpl.INSTANCE.create()));
152 db.executeInsert("project_measures", map);
155 private Map<String, String> insertMetricsToMigrate() {
156 Map<String, String> createdMetrics = new HashMap<>();
157 MIGRATION_MAP.keySet().forEach(metricKey -> createdMetrics.put(metricKey, insertMetric(metricKey)));
158 return createdMetrics;
161 private Map<String, String> insertReplacementMetrics() {
162 Map<String, String> createdMetrics = new HashMap<>();
163 MIGRATION_MAP.values().forEach(metricKey -> createdMetrics.put(metricKey, insertMetric(metricKey)));
164 return createdMetrics;
167 private String insertMetric(String key) {
168 String uuid = UuidFactoryImpl.INSTANCE.create();
169 Map<String, Object> map = Map.ofEntries(
170 Map.entry("UUID", uuid),
171 Map.entry("NAME", key));
172 db.executeInsert("metrics", map);