From: Julien Lancelot Date: Tue, 25 Feb 2014 15:33:24 +0000 (+0100) Subject: SONAR-4996 Create migration on debt measures X-Git-Tag: 4.3~691 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a279700135f8fe21708db3e036119b36f6c91339;p=sonarqube.git SONAR-4996 Create migration on debt measures --- diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/DebtConvertor.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/DebtConvertor.java index 28f0414211b..16893645878 100644 --- a/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/DebtConvertor.java +++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/DebtConvertor.java @@ -64,6 +64,10 @@ class DebtConvertor { return ((Double) (days * hoursInDay() * ONE_HOUR)).longValue(); } + long createFromDays(double days) { + return ((Double) (days * hoursInDay() * 3600L)).longValue(); + } + private int hoursInDay() { int hoursInDay = settings.getInt(HOURS_IN_DAY_PROPERTY); if (hoursInDay < 0) { diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigration.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigration.java new file mode 100644 index 00000000000..6e59af22a32 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigration.java @@ -0,0 +1,188 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.db.migrations.debt; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.commons.dbutils.DbUtils; +import org.apache.commons.dbutils.QueryRunner; +import org.apache.commons.dbutils.handlers.AbstractListHandler; +import org.picocontainer.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.config.Settings; +import org.sonar.api.utils.MessageException; +import org.sonar.core.persistence.Database; +import org.sonar.server.db.migrations.DatabaseMigration; +import org.sonar.server.db.migrations.util.SqlUtil; + +import javax.annotation.CheckForNull; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * Used in the Active Record Migration 515 + */ +public class TechnicalDebtMeasureMigration implements DatabaseMigration { + + private Logger logger = LoggerFactory.getLogger(TechnicalDebtMeasureMigration.class); + + private static final String ID = "id"; + private static final String VALUE = "changeData"; + private static final String VAR1 = "var1"; + private static final String VAR2 = "var2"; + private static final String VAR3 = "var3"; + private static final String VAR4 = "var4"; + private static final String VAR5 = "var5"; + + private static final String FAILURE_MESSAGE = "Fail to migrate data"; + + private static final String SQL_SELECT = "SELECT * FROM project_measures INNER JOIN metrics on metrics.id=project_measures.metric_id " + + "WHERE metrics.name='sqale_index' or metrics.name='new_technical_debt'"; + private static final String SQL_UPDATE = "UPDATE project_measures SET value=?," + + "variation_value_1=?,variation_value_2=?,variation_value_3=?,variation_value_4=?,variation_value_5=? WHERE id=?"; + private static final String SQL_SELECT_ALL; + + static { + StringBuilder sb = new StringBuilder("SELECT pm.id AS " + ID + ", pm.value AS " + VALUE + + ", pm.variation_value_1 AS " + VAR1 + ", pm.variation_value_2 AS " + VAR2 + ", pm.variation_value_3 AS " + VAR3 + + ", pm.variation_value_4 AS " + VAR4 + ", pm.variation_value_5 AS " + VAR5 + + " FROM project_measures pm " + + " WHERE "); + for (int i = 0; i < Referentials.GROUP_SIZE; i++) { + if (i > 0) { + sb.append(" OR "); + } + sb.append("pm.id=?"); + } + SQL_SELECT_ALL = sb.toString(); + } + + private final DebtConvertor debtConvertor; + private final Database db; + + public TechnicalDebtMeasureMigration(Database database, Settings settings) { + this.db = database; + this.debtConvertor = new DebtConvertor(settings); + } + + @Override + public void execute() { + try { + logger.info("Initialize input"); + Referentials referentials = new Referentials(db, SQL_SELECT); + if (referentials.size() > 0) { + logger.info("Migrate {} rows", referentials.size()); + convert(referentials); + } + } catch (SQLException e) { + logger.error(FAILURE_MESSAGE, e); + SqlUtil.log(logger, e); + throw MessageException.of(FAILURE_MESSAGE); + + } catch (Exception e) { + logger.error(FAILURE_MESSAGE, e); + throw MessageException.of(FAILURE_MESSAGE); + } + } + + public Object convert(Referentials referentials) throws Exception { + Long[] ids = referentials.pollGroupOfIds(); + while (ids.length > 0) { + List> rows = selectRows(ids); + convert(rows, ids); + + ids = referentials.pollGroupOfIds(); + } + return null; + } + + private List> selectRows(Long[] ids) throws SQLException { + Connection readConnection = null; + try { + readConnection = db.getDataSource().getConnection(); + RowHandler rowHandler = new RowHandler(); + return new QueryRunner().query(readConnection, SQL_SELECT_ALL, rowHandler, ids); + + } finally { + DbUtils.closeQuietly(readConnection); + } + } + + private void convert(List> rows, Long[] ids) throws SQLException { + Connection readConnection = null; + Connection writeConnection = null; + try { + readConnection = db.getDataSource().getConnection(); + writeConnection = db.getDataSource().getConnection(); + writeConnection.setAutoCommit(false); + + List allParams = Lists.newArrayList(); + QueryRunner runner = new QueryRunner(); + for (Map row : rows) { + Object[] params = new Object[7]; + params[0] = convertDebtForDays((Double) row.get(VALUE)); + params[1] = convertDebtForDays((Double) row.get(VAR1)); + params[2] = convertDebtForDays((Double) row.get(VAR2)); + params[3] = convertDebtForDays((Double) row.get(VAR3)); + params[4] = convertDebtForDays((Double) row.get(VAR4)); + params[5] = convertDebtForDays((Double) row.get(VAR5)); + params[6] = row.get(ID); + allParams.add(params); + } + runner.batch(writeConnection, SQL_UPDATE, allParams.toArray(new Object[allParams.size()][])); + writeConnection.commit(); + + } finally { + DbUtils.closeQuietly(readConnection); + DbUtils.closeQuietly(writeConnection); + } + } + + @VisibleForTesting + @CheckForNull + Long convertDebtForDays(@Nullable Double data) { + if (data == null) { + return null; + } + return debtConvertor.createFromDays(data); + } + + private static class RowHandler extends AbstractListHandler> { + @Override + protected Map handleRow(ResultSet rs) throws SQLException { + Map map = Maps.newHashMap(); + map.put(ID, SqlUtil.getLong(rs, ID)); + map.put(VALUE, SqlUtil.getDouble(rs, VALUE)); + map.put(VAR1, SqlUtil.getDouble(rs, VAR1)); + map.put(VAR2, SqlUtil.getDouble(rs, VAR2)); + map.put(VAR3, SqlUtil.getDouble(rs, VAR3)); + map.put(VAR4, SqlUtil.getDouble(rs, VAR4)); + map.put(VAR5, SqlUtil.getDouble(rs, VAR5)); + return map; + } + } + +} diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/515_update_measures_debt_to_seconds.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/515_update_measures_debt_to_seconds.rb new file mode 100644 index 00000000000..0db6ccadc2c --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/515_update_measures_debt_to_seconds.rb @@ -0,0 +1,30 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2013 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# Sonar 4.3 +# SONAR-4996 +# +class UpdateMeasuresDebtToSeconds < ActiveRecord::Migration + + def self.up + Java::OrgSonarServerUi::JRubyFacade.getInstance().databaseMigrator().executeMigration('org.sonar.server.db.migrations.debt.TechnicalDebtMeasureMigration') + end +end diff --git a/sonar-server/src/test/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest.java b/sonar-server/src/test/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest.java new file mode 100644 index 00000000000..fb5c590b361 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest.java @@ -0,0 +1,67 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.db.migrations.debt; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.api.config.Settings; +import org.sonar.core.persistence.TestDatabase; + +@RunWith(MockitoJUnitRunner.class) +public class TechnicalDebtMeasureMigrationTest { + + @ClassRule + public static TestDatabase db = new TestDatabase().schema(TechnicalDebtMeasureMigrationTest.class, "schema.sql"); + + Settings settings; + + TechnicalDebtMeasureMigration migration; + + @Before + public void setUp() throws Exception { + settings = new Settings(); + settings.setProperty(DebtConvertor.HOURS_IN_DAY_PROPERTY, 8); + + migration = new TechnicalDebtMeasureMigration(db.database(), settings); + } + + @Test + public void migrate_technical_debt_measures() throws Exception { + db.prepareDbUnit(getClass(), "migrate_technical_debt_measures.xml"); + + migration.execute(); + + db.assertDbUnit(getClass(), "migrate_technical_debt_measures_result.xml", "project_measures"); + } + + @Test + public void migrate_added_technical_debt_measures() throws Exception { + db.prepareDbUnit(getClass(), "migrate_new_technical_debt_measures.xml"); + + migration.execute(); + + db.assertDbUnit(getClass(), "migrate_new_technical_debt_measures_result.xml", "project_measures"); + } + +} diff --git a/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures.xml b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures.xml new file mode 100644 index 00000000000..186b86bf6c7 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures.xml @@ -0,0 +1,29 @@ + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures_result.xml b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures_result.xml new file mode 100644 index 00000000000..591506c8276 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_new_technical_debt_measures_result.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures.xml b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures.xml new file mode 100644 index 00000000000..e7e24866b7c --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures.xml @@ -0,0 +1,35 @@ + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures_result.xml b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures_result.xml new file mode 100644 index 00000000000..150674c514f --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/migrate_technical_debt_measures_result.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/schema.sql b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/schema.sql new file mode 100644 index 00000000000..1e29613934e --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/db/migrations/debt/TechnicalDebtMeasureMigrationTest/schema.sql @@ -0,0 +1,45 @@ +-- 4.3 + +CREATE TABLE "PROJECT_MEASURES" ( + "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "VALUE" DOUBLE, + "METRIC_ID" INTEGER NOT NULL, + "SNAPSHOT_ID" INTEGER, + "RULE_ID" INTEGER, + "RULES_CATEGORY_ID" INTEGER, + "TEXT_VALUE" VARCHAR(96), + "TENDENCY" INTEGER, + "MEASURE_DATE" TIMESTAMP, + "PROJECT_ID" INTEGER, + "ALERT_STATUS" VARCHAR(5), + "ALERT_TEXT" VARCHAR(4000), + "URL" VARCHAR(2000), + "DESCRIPTION" VARCHAR(4000), + "RULE_PRIORITY" INTEGER, + "CHARACTERISTIC_ID" INTEGER, + "PERSON_ID" INTEGER, + "VARIATION_VALUE_1" DOUBLE, + "VARIATION_VALUE_2" DOUBLE, + "VARIATION_VALUE_3" DOUBLE, + "VARIATION_VALUE_4" DOUBLE, + "VARIATION_VALUE_5" DOUBLE +); + +CREATE TABLE "METRICS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "NAME" VARCHAR(64) NOT NULL, + "DESCRIPTION" VARCHAR(255), + "DIRECTION" INTEGER NOT NULL DEFAULT 0, + "DOMAIN" VARCHAR(64), + "SHORT_NAME" VARCHAR(64), + "QUALITATIVE" BOOLEAN NOT NULL DEFAULT FALSE, + "VAL_TYPE" VARCHAR(8), + "USER_MANAGED" BOOLEAN DEFAULT FALSE, + "ENABLED" BOOLEAN DEFAULT TRUE, + "ORIGIN" VARCHAR(3), + "WORST_VALUE" DOUBLE, + "BEST_VALUE" DOUBLE, + "OPTIMIZED_BEST_VALUE" BOOLEAN, + "HIDDEN" BOOLEAN, + "DELETE_HISTORICAL_DATA" BOOLEAN +);