aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-06-24 17:21:51 +0200
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-06-29 11:06:00 +0200
commitda6dbbc8e24d9a2150b5f06a6c300c541a3df1cb (patch)
treefca64050bb74277370e000bd74a7768d69e0aaa3
parent082949f81baed8e98867d6e752a6378cec4b2960 (diff)
downloadsonarqube-da6dbbc8e24d9a2150b5f06a6c300c541a3df1cb.tar.gz
sonarqube-da6dbbc8e24d9a2150b5f06a6c300c541a3df1cb.zip
SONAR-7824 Populate DB column ACTIVITIES.PROFILE_KEY
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityResultSetIterator.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java1
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/activity/index/ActivityResultSetIteratorTest.java3
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1260_populate_profile_key_of_activities.rb28
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivities.java63
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql1
-rw-r--r--sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest.java97
-rw-r--r--sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest/activities.sql11
12 files changed, 221 insertions, 9 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityResultSetIterator.java
index c9409491add..2440075e8dd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityResultSetIterator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityResultSetIterator.java
@@ -27,6 +27,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
+import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.api.utils.KeyValueFormat;
@@ -50,7 +51,8 @@ class ActivityResultSetIterator extends ResultSetIterator<UpdateRequest> {
"data_field",
"user_login",
"log_type",
- "created_at"
+ "created_at",
+ "profile_key"
};
private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from activities ";
@@ -86,7 +88,9 @@ class ActivityResultSetIterator extends ResultSetIterator<UpdateRequest> {
writer.prop(ActivityIndexDefinition.FIELD_KEY, key);
writer.prop(ActivityIndexDefinition.FIELD_ACTION, rs.getString(2));
writer.prop(ActivityIndexDefinition.FIELD_MESSAGE, rs.getString(3));
- writer.name(ActivityIndexDefinition.FIELD_DETAILS).valueObject(KeyValueFormat.parse(rs.getString(4)));
+ Map<String, String> details = KeyValueFormat.parse(rs.getString(4));
+ details.put("profileKey", rs.getString(8));
+ writer.name(ActivityIndexDefinition.FIELD_DETAILS).valueObject(details);
writer.prop(ActivityIndexDefinition.FIELD_LOGIN, rs.getString(5));
writer.prop(ActivityIndexDefinition.FIELD_TYPE, rs.getString(6));
Date createdAt = rs.getTimestamp(7);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java
index 87350de9d01..9621ce0fc26 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java
@@ -95,7 +95,6 @@ public class ActiveRuleChange {
activity.setProfileKey(getKey().qProfile());
activity.setData("key", getKey().toString());
activity.setData("ruleKey", getKey().ruleKey().toString());
- activity.setData("profileKey", getKey().qProfile());
parameters.entrySet().stream()
.filter(param -> !param.getKey().isEmpty())
diff --git a/server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java
index 69618927959..7f5eccc0a01 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java
@@ -71,15 +71,21 @@ public class ActivityServiceTest {
activity.setAction("THE_ACTION");
activity.setMessage("THE_MSG");
activity.setData("foo", "bar");
- activity.setData("profileKey", "PROFILE_KEY");
activity.setProfileKey("PROFILE_KEY");
service.save(activity);
- Map<String, Object> dbMap = db.selectFirst("select log_type as \"type\", log_action as \"action\", log_message as \"msg\", data_field as \"data\" from activities");
+ Map<String, Object> dbMap = db.selectFirst("select " +
+ " log_type as \"type\", " +
+ " log_action as \"action\", " +
+ " log_message as \"msg\", " +
+ " data_field as \"data\", " +
+ " profile_key as \"profileKey\" " +
+ "from activities");
assertThat(dbMap).containsEntry("type", "ANALYSIS_REPORT");
assertThat(dbMap).containsEntry("action", "THE_ACTION");
assertThat(dbMap).containsEntry("msg", "THE_MSG");
- assertThat(dbMap.get("data")).isEqualTo("foo=bar;profileKey=PROFILE_KEY");
+ assertThat(dbMap).containsEntry("profileKey", "PROFILE_KEY");
+ assertThat(dbMap.get("data")).isEqualTo("foo=bar");
List<ActivityDoc> docs = es.getDocuments("activities", "activity", ActivityDoc.class);
assertThat(docs).hasSize(1);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/activity/index/ActivityResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/activity/index/ActivityResultSetIteratorTest.java
index 7a20cd28de2..52713dc282b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/activity/index/ActivityResultSetIteratorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/activity/index/ActivityResultSetIteratorTest.java
@@ -49,7 +49,8 @@ public class ActivityResultSetIteratorTest {
assertThat(doc.get(ActivityIndexDefinition.FIELD_KEY)).isEqualTo("UUID1");
assertThat(doc.get(ActivityIndexDefinition.FIELD_ACTION)).isEqualTo("THE_ACTION");
assertThat(doc.get(ActivityIndexDefinition.FIELD_MESSAGE)).isEqualTo("THE_MSG");
- assertThat((Map) doc.get(ActivityIndexDefinition.FIELD_DETAILS)).containsOnly(MapEntry.entry("foo", "bar"));
+ assertThat((Map<String, String>) doc.get(ActivityIndexDefinition.FIELD_DETAILS))
+ .containsOnly(MapEntry.entry("foo", "bar"), MapEntry.entry("profileKey", "PROFILE_KEY"));
assertThat(doc.get(ActivityIndexDefinition.FIELD_LOGIN)).isEqualTo("THE_AUTHOR");
assertThat(it.hasNext()).isTrue();
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1260_populate_profile_key_of_activities.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1260_populate_profile_key_of_activities.rb
new file mode 100644
index 00000000000..bd92cfafe2c
--- /dev/null
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1260_populate_profile_key_of_activities.rb
@@ -0,0 +1,28 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 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.
+#
+#
+# SonarQube 6.0
+# SONAR-7794
+#
+class PopulateProfileKeyOfActivities < ActiveRecord::Migration
+ def self.up
+ execute_java_migration('org.sonar.db.version.v60.PopulateProfileKeyOfActivities')
+ end
+end
diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
index ec5a26be020..7279a6207be 100644
--- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
+++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
@@ -30,7 +30,7 @@ import org.sonar.db.MyBatis;
public class DatabaseVersion {
- public static final int LAST_VERSION = 1_259;
+ public static final int LAST_VERSION = 1_260;
/**
* The minimum supported version which can be upgraded. Lower
diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
index b8c9c9e3eb4..fb1ec165eb1 100644
--- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
+++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
@@ -128,6 +128,7 @@ import org.sonar.db.version.v60.PopulateComponentUuidColumnsOfSnapshots;
import org.sonar.db.version.v60.PopulateComponentUuidOfDuplicationsIndex;
import org.sonar.db.version.v60.PopulateComponentUuidOfMeasures;
import org.sonar.db.version.v60.PopulateLastUsedColumnOfRulesProfiles;
+import org.sonar.db.version.v60.PopulateProfileKeyOfActivities;
import org.sonar.db.version.v60.PopulateUuidColumnOnSnapshots;
import org.sonar.db.version.v60.PopulateUuidColumnsOfProjects;
import org.sonar.db.version.v60.PopulateUuidColumnsOfResourceIndex;
@@ -243,6 +244,7 @@ public class MigrationStepModule extends Module {
AddLastUsedColumnToRulesProfiles.class,
PopulateLastUsedColumnOfRulesProfiles.class,
AddProfileKeyToActivities.class,
+ PopulateProfileKeyOfActivities.class,
// SNAPSHOTS.UUID
AddUuidColumnToSnapshots.class,
diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivities.java b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivities.java
new file mode 100644
index 00000000000..fa9f0877115
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivities.java
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.db.version.v60;
+
+import java.sql.SQLException;
+import java.util.Map;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.db.Database;
+import org.sonar.db.version.BaseDataChange;
+import org.sonar.db.version.MassUpdate;
+import org.sonar.db.version.Select;
+import org.sonar.db.version.SqlStatement;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
+public class PopulateProfileKeyOfActivities extends BaseDataChange {
+
+ public PopulateProfileKeyOfActivities(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("select id, data_field from activities where profile_key is null");
+ massUpdate.update("update activities set profile_key=?, data_field=? where id=?");
+ massUpdate.rowPluralName("activities");
+ massUpdate.execute(PopulateProfileKeyOfActivities::handle);
+ }
+
+ private static boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+ int id = row.getInt(1);
+ String data = row.getString(2);
+ Map<String, String> fields = KeyValueFormat.parse(data);
+ String profileKey = fields.remove("profileKey");
+ checkState(isNotBlank(profileKey), "No profile key found in db row of activities.data_field", id);
+
+ update.setString(1, profileKey);
+ update.setString(2, KeyValueFormat.format(fields));
+ update.setInt(3, id);
+
+ return true;
+ }
+}
diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
index 207cb3d1b81..de83b31f714 100644
--- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
+++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
@@ -465,6 +465,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1255');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1256');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1257');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1258');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1259');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482');
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
diff --git a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
index 00e8e84fecb..d5522ed08da 100644
--- a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
public void verify_count_of_added_MigrationStep_types() {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
- assertThat(container.size()).isEqualTo(115);
+ assertThat(container.size()).isEqualTo(116);
}
}
diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest.java
new file mode 100644
index 00000000000..4bad1469671
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest.java
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.db.version.v60;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PopulateProfileKeyOfActivitiesTest {
+ private static final String ACTIVITIES_TABLE = "activities";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester db = DbTester.createForSchema(System2.INSTANCE, PopulateProfileKeyOfActivitiesTest.class, "activities.sql");
+
+ PopulateProfileKeyOfActivities underTest = new PopulateProfileKeyOfActivities(db.database());
+
+ @Test
+ public void migration_has_no_effect_on_empty_tables() throws SQLException {
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable(ACTIVITIES_TABLE)).isEqualTo(0);
+ }
+
+ @Test
+ public void migration_update_activities_profile_key() throws SQLException {
+ insertActivity("first-profile-key");
+ insertActivity("first-profile-key");
+ insertActivity("first-profile-key");
+ insertActivity("second-profile-key");
+ insertActivity("third-profile-key");
+
+ underTest.execute();
+
+ assertCountActivitiesWithProfile("first-profile-key", 3);
+ assertCountActivitiesWithProfile("second-profile-key", 1);
+ assertCountActivitiesWithProfile("third-profile-key", 1);
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ insertActivity("profile-key");
+ underTest.execute();
+ assertCountActivitiesWithProfile("profile-key", 1);
+
+ underTest.execute();
+ assertCountActivitiesWithProfile("profile-key", 1);
+ }
+
+ @Test
+ public void fail_if_activity_data_is_not_well_formatted() throws SQLException {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Error during processing of row: ");
+
+ db.executeInsert(ACTIVITIES_TABLE, "data_field", "key=fakeKey");
+
+ underTest.execute();
+ }
+
+ private void assertCountActivitiesWithProfile(String profileKey, int expectedNumberOfActivities) {
+ assertThat(countActivitiesWithProfile(profileKey)).isEqualTo(expectedNumberOfActivities);
+ }
+
+ private int countActivitiesWithProfile(String qualityProfileKey) {
+ // profile key is removed from data_field
+ return db.countSql(String.format("select count(1) from activities where profile_key='%s' and data_field='key=fakeKey'", qualityProfileKey));
+ }
+
+ private void insertActivity(String profileKey) {
+ db.executeInsert(ACTIVITIES_TABLE,
+ "data_field", "key=fakeKey;profileKey=" + profileKey);
+ }
+}
diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest/activities.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest/activities.sql
new file mode 100644
index 00000000000..fead19a9ef2
--- /dev/null
+++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateProfileKeyOfActivitiesTest/activities.sql
@@ -0,0 +1,11 @@
+CREATE TABLE "ACTIVITIES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOG_KEY" VARCHAR(250),
+ "PROFILE_KEY" VARCHAR(255),
+ "CREATED_AT" TIMESTAMP,
+ "USER_LOGIN" VARCHAR(255),
+ "LOG_TYPE" VARCHAR(250),
+ "LOG_ACTION" VARCHAR(250),
+ "LOG_MESSAGE" VARCHAR(250),
+ "DATA_FIELD" CLOB(2147483647)
+);