]> source.dussan.org Git - sonarqube.git/blob
94d2e0e07012886a7714b2f8cf31d8d875567dee
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.platform.db.migration.version.v108;
21
22 import java.nio.charset.StandardCharsets;
23 import java.sql.SQLException;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import org.junit.jupiter.api.Test;
28 import org.junit.jupiter.api.extension.RegisterExtension;
29 import org.slf4j.event.Level;
30 import org.sonar.api.testfixtures.log.LogTesterJUnit5;
31 import org.sonar.api.utils.System2;
32 import org.sonar.core.util.SequenceUuidFactory;
33 import org.sonar.db.MigrationDbTester;
34 import org.sonar.server.platform.db.migration.step.DataChange;
35
36 import static java.lang.String.format;
37 import static org.assertj.core.api.Assertions.assertThat;
38 import static org.assertj.core.api.Assertions.assertThatCode;
39 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
40 import static org.assertj.core.api.Assertions.tuple;
41 import static org.mockito.Mockito.mock;
42
43 class MigratePortfoliosLiveMeasuresToMeasuresIT {
44
45   private static final String MEASURES_MIGRATED_COLUMN = "measures_migrated";
46   public static final String SELECT_MEASURE = "select component_uuid, branch_uuid, json_value, json_value_hash, created_at, updated_at " +
47     "from measures where component_uuid = '%s'";
48
49   @RegisterExtension
50   public final MigrationDbTester db = MigrationDbTester.createForMigrationStep(MigratePortfoliosLiveMeasuresToMeasures.class);
51
52   @RegisterExtension
53   private final LogTesterJUnit5 logTester = new LogTesterJUnit5();
54
55   private final SequenceUuidFactory uuidFactory = new SequenceUuidFactory();
56   private final System2 system2 = mock();
57   private final DataChange underTest = new MigratePortfoliosLiveMeasuresToMeasures(db.database(), system2);
58
59   @Test
60   void shall_complete_when_tables_are_empty() throws SQLException {
61     underTest.execute();
62
63     assertThat(db.countRowsOfTable("measures")).isZero();
64   }
65
66   @Test
67   void migration_does_nothing_if_live_measures_table_is_missing() {
68     db.executeDdl("drop table live_measures");
69     db.assertTableDoesNotExist("live_measures");
70     String branch = "portfolio_1";
71     insertNotMigratedPortfolio(branch);
72
73     assertThatCode(underTest::execute)
74       .doesNotThrowAnyException();
75   }
76
77   @Test
78   void log_the_item_uuid_when_the_migration_fails() {
79     String nclocMetricUuid = insertMetric("ncloc", "INT");
80     String portfolio = "portfolio_1";
81     insertNotMigratedPortfolio(portfolio);
82     insertMeasure(portfolio, nclocMetricUuid, Map.of("value", 120));
83
84     db.executeDdl("drop table measures");
85     db.assertTableDoesNotExist("measures");
86
87     assertThatExceptionOfType(SQLException.class)
88       .isThrownBy(underTest::execute);
89
90     assertThat(logTester.logs(Level.ERROR))
91       .contains("Migration of portfolio portfolio_1 failed");
92   }
93
94   @Test
95   void shall_not_migrate_when_portfolio_is_already_flagged() throws SQLException {
96     String nclocMetricUuid = insertMetric("ncloc", "INT");
97     String qgStatusMetricUuid = insertMetric("quality_gate_status", "STRING");
98     String metricWithDataUuid = insertMetric("metric_with_data", "DATA");
99     String portfolio1 = "portfolio_1";
100     insertMigratedPortfolio(portfolio1);
101     insertMeasure(portfolio1, nclocMetricUuid, Map.of("value", 120));
102     insertMeasure(portfolio1, qgStatusMetricUuid, Map.of("text_value", "ok"));
103     insertMeasure(portfolio1, metricWithDataUuid, Map.of("measure_data", "some data".getBytes(StandardCharsets.UTF_8)));
104
105     insertMigratedPortfolio("portfolio_2");
106     insertMeasure("portfolio_2", nclocMetricUuid, Map.of("value", 14220));
107
108     underTest.execute();
109
110     assertThat(db.countRowsOfTable("measures")).isZero();
111   }
112
113   @Test
114   void should_flag_portfolio_with_no_measures() throws SQLException {
115     String portfolio = "portfolio_3";
116     insertNotMigratedPortfolio(portfolio);
117
118     underTest.execute();
119
120     assertPortfolioMigrated(portfolio);
121     assertThat(db.countRowsOfTable("measures")).isZero();
122   }
123
124   @Test
125   void should_migrate_portfolio_with_measures() throws SQLException {
126     String nclocMetricUuid = insertMetric("ncloc", "INT");
127     String qgStatusMetricUuid = insertMetric("quality_gate_status", "STRING");
128     String metricWithDataUuid = insertMetric("metric_with_data", "DATA");
129
130     String portfolio1 = "portfolio_4";
131     insertNotMigratedPortfolio(portfolio1);
132     String component1 = uuidFactory.create();
133     String component2 = uuidFactory.create();
134     insertMeasure(portfolio1, component1, nclocMetricUuid, Map.of("value", 120));
135     insertMeasure(portfolio1, component1, qgStatusMetricUuid, Map.of("text_value", "ok"));
136     insertMeasure(portfolio1, component2, metricWithDataUuid, Map.of("measure_data", "some data".getBytes(StandardCharsets.UTF_8)));
137
138     String portfolio2 = "portfolio_5";
139     insertNotMigratedPortfolio(portfolio2);
140     insertMeasure(portfolio2, nclocMetricUuid, Map.of("value", 64));
141
142     String migratedPortfolio = "portfolio_6";
143     insertMigratedPortfolio(migratedPortfolio);
144     insertMeasure(migratedPortfolio, nclocMetricUuid, Map.of("value", 3684));
145
146     underTest.execute();
147
148     assertPortfolioMigrated(portfolio1);
149     assertPortfolioMigrated(portfolio2);
150     assertThat(db.countRowsOfTable("measures")).isEqualTo(3);
151
152     assertThat(db.select(format(SELECT_MEASURE, component1)))
153       .hasSize(1)
154       .extracting(t -> t.get("component_uuid"), t -> t.get("branch_uuid"), t -> t.get("json_value"), t -> t.get("json_value_hash"))
155       .containsOnly(tuple(component1, portfolio1, "{\"ncloc\":120.0,\"quality_gate_status\":\"ok\"}", 6033012287291512746L));
156
157     assertThat(db.select(format(SELECT_MEASURE, component2)))
158       .hasSize(1)
159       .extracting(t -> t.get("component_uuid"), t -> t.get("branch_uuid"), t -> t.get("json_value"), t -> t.get("json_value_hash"))
160       .containsOnly(tuple(component2, portfolio1, "{\"metric_with_data\":\"some data\"}", -4524184678167636687L));
161   }
162
163   private void assertPortfolioMigrated(String portfolio) {
164     List<Map<String, Object>> result = db.select(format("select %s as \"MIGRATED\" from portfolios where uuid = '%s'", MEASURES_MIGRATED_COLUMN, portfolio));
165     assertThat(result)
166       .hasSize(1)
167       .extracting(t -> t.get("MIGRATED"))
168       .containsOnly(true);
169   }
170
171   private String insertMetric(String metricName, String valueType) {
172     String metricUuid = uuidFactory.create();
173     db.executeInsert("metrics",
174       "uuid", metricUuid,
175       "name", metricName,
176       "val_type", valueType);
177     return metricUuid;
178   }
179
180   private void insertMeasure(String portfolioUuid, String metricUuid, Map<String, Object> data) {
181     insertMeasure(portfolioUuid, uuidFactory.create(), metricUuid, data);
182   }
183
184   private void insertMeasure(String portfolioUuid, String componentUuid, String metricUuid, Map<String, Object> data) {
185     Map<String, Object> dataMap = new HashMap<>(data);
186     dataMap.put("uuid", uuidFactory.create());
187     dataMap.put("component_uuid", componentUuid);
188     dataMap.put("project_uuid", portfolioUuid);
189     dataMap.put("metric_uuid", metricUuid);
190     dataMap.put("created_at", 12L);
191     dataMap.put("updated_at", 12L);
192
193     db.executeInsert("live_measures", dataMap);
194   }
195
196   private void insertNotMigratedPortfolio(String portfolioUuid) {
197     insertPortfolio(portfolioUuid, false);
198   }
199
200   private void insertMigratedPortfolio(String portfolioUuid) {
201     insertPortfolio(portfolioUuid, true);
202   }
203
204   private void insertPortfolio(String portfolioUuid, boolean migrated) {
205     db.executeInsert("portfolios",
206       "uuid", portfolioUuid,
207       "kee", portfolioUuid,
208       "name", portfolioUuid,
209       "private", true,
210       "root_uuid", portfolioUuid,
211       "selection_mode", "MANUAL",
212       MEASURES_MIGRATED_COLUMN, migrated,
213       "created_at", 12L,
214       "updated_at", 12L
215     );
216   }
217 }