diff options
author | Eric Hartmann <hartmann.eric@gmail.com> | 2017-09-29 18:07:31 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-10-17 15:13:58 +0200 |
commit | c1f4d7c77fcf0e9b8d385167a7f34a68ac6c6550 (patch) | |
tree | 0615811c23f9434bc33289e8ecbd05365a6f1e51 | |
parent | 80645fca839ea97ee472f01ebb81f40af0f179f5 (diff) | |
download | sonarqube-c1f4d7c77fcf0e9b8d385167a7f34a68ac6c6550.tar.gz sonarqube-c1f4d7c77fcf0e9b8d385167a7f34a68ac6c6550.zip |
SONAR-9882 Implements storage of sonar.analysis.* properties
31 files changed, 1182 insertions, 19 deletions
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index b080ec9da78..a4c1e7822fb 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -152,7 +152,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION + 26 // level 1 - + 51 // content of DaoModule + + 52 // content of DaoModule + 3 // content of EsSearchModule + 66 // content of CorePropertyDefinitions + 1 // StopFlagContainer diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl index 6afd58a258b..f3bedc4ba6b 100644 --- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -197,7 +197,7 @@ CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY CREATE TABLE "RULES_METADATA" ( "RULE_ID" INTEGER NOT NULL, "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, - "NOTE_DATA" CLOB(2147483647), + "NOTE_DATA" CLOB, "NOTE_USER_LOGIN" VARCHAR(255), "NOTE_CREATED_AT" BIGINT, "NOTE_UPDATED_AT" BIGINT, @@ -255,7 +255,7 @@ CREATE TABLE "PROPERTIES" ( "USER_ID" INTEGER, "IS_EMPTY" BOOLEAN NOT NULL, "TEXT_VALUE" VARCHAR(4000), - "CLOB_VALUE" CLOB(2147483647), + "CLOB_VALUE" CLOB, "CREATED_AT" BIGINT ); CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY"); @@ -579,7 +579,7 @@ CREATE TABLE "FILE_SOURCES" ( "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "PROJECT_UUID" VARCHAR(50) NOT NULL, "FILE_UUID" VARCHAR(50) NOT NULL, - "LINE_HASHES" CLOB(2147483647), + "LINE_HASHES" CLOB, "BINARY_DATA" BLOB, "DATA_TYPE" VARCHAR(20), "DATA_HASH" VARCHAR(50), @@ -630,7 +630,7 @@ CREATE TABLE "CE_ACTIVITY" ( "UPDATED_AT" BIGINT NOT NULL, "EXECUTION_TIME_MS" BIGINT NULL, "ERROR_MESSAGE" VARCHAR(1000), - "ERROR_STACKTRACE" CLOB(2147483647), + "ERROR_STACKTRACE" CLOB, "ERROR_TYPE" VARCHAR(20) ); @@ -727,3 +727,14 @@ CREATE TABLE "PROJECT_BRANCHES" ( ); CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); + +CREATE TABLE "ANALYSIS_PROPERTIES" ( + "UUID" VARCHAR(40) NOT NULL PRIMARY KEY, + "SNAPSHOT_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(512) NOT NULL, + "TEXT_VALUE" VARCHAR(4000), + "CLOB_VALUE" CLOB, + "IS_EMPTY" BOOLEAN NOT NULL, + "CREATED_AT" BIGINT NOT NULL +); +CREATE INDEX "SNAPSHOT_UUID" ON "ANALYSIS_PROPERTIES" ("SNAPSHOT_UUID"); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java index f3b621fe326..e70920b964e 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java @@ -28,6 +28,7 @@ import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeScannerContextDao; import org.sonar.db.ce.CeTaskCharacteristicDao; import org.sonar.db.ce.CeTaskInputDao; +import org.sonar.db.component.AnalysisPropertiesDao; import org.sonar.db.component.BranchDao; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentKeyUpdaterDao; @@ -81,6 +82,7 @@ public class DaoModule extends Module { // for readability and easier merge, keep list ordered alphabetically // ===================================================================== ActiveRuleDao.class, + AnalysisPropertiesDao.class, AuthorizationDao.class, BranchDao.class, CeActivityDao.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java index ae81a02f4cf..5df791543f1 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java @@ -26,6 +26,7 @@ import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeScannerContextDao; import org.sonar.db.ce.CeTaskCharacteristicDao; import org.sonar.db.ce.CeTaskInputDao; +import org.sonar.db.component.AnalysisPropertiesDao; import org.sonar.db.component.BranchDao; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentKeyUpdaterDao; @@ -128,6 +129,7 @@ public class DbClient { private final EsQueueDao esQueueDao; private final PluginDao pluginDao; private final BranchDao branchDao; + private final AnalysisPropertiesDao analysisPropertiesDao; private final QProfileEditUsersDao qProfileEditUsersDao; private final QProfileEditGroupsDao qProfileEditGroupsDao; @@ -189,6 +191,7 @@ public class DbClient { esQueueDao = getDao(map, EsQueueDao.class); pluginDao = getDao(map, PluginDao.class); branchDao = getDao(map, BranchDao.class); + analysisPropertiesDao = getDao(map, AnalysisPropertiesDao.class); qProfileEditUsersDao = getDao(map, QProfileEditUsersDao.class); qProfileEditGroupsDao = getDao(map, QProfileEditGroupsDao.class); } @@ -245,6 +248,10 @@ public class DbClient { return snapshotDao; } + public AnalysisPropertiesDao analysisPropertiesDao() { + return analysisPropertiesDao; + } + public ComponentDao componentDao() { return componentDao; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index 7cd8e4ab309..bfb866e758d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -35,6 +35,7 @@ import org.sonar.db.ce.CeScannerContextMapper; import org.sonar.db.ce.CeTaskCharacteristicDto; import org.sonar.db.ce.CeTaskCharacteristicMapper; import org.sonar.db.ce.CeTaskInputMapper; +import org.sonar.db.component.AnalysisPropertiesMapper; import org.sonar.db.component.BranchMapper; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDtoWithSnapshotId; @@ -45,6 +46,7 @@ import org.sonar.db.component.ComponentMapper; import org.sonar.db.component.FilePathWithHashDto; import org.sonar.db.component.KeyWithUuidDto; import org.sonar.db.component.ResourceDto; +import org.sonar.db.component.ScrapAnalysisPropertyDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotMapper; import org.sonar.db.component.UuidWithProjectUuidDto; @@ -184,6 +186,7 @@ public class MyBatis implements Startable { confBuilder.loadAlias("Rule", RuleDto.class); confBuilder.loadAlias("SchemaMigration", SchemaMigrationDto.class); confBuilder.loadAlias("ScrapProperty", ScrapPropertyDto.class); + confBuilder.loadAlias("ScrapAnalysisProperty", ScrapAnalysisPropertyDto.class); confBuilder.loadAlias("Snapshot", SnapshotDto.class); confBuilder.loadAlias("UserGroup", UserGroupDto.class); confBuilder.loadAlias("UserPermission", UserPermissionDto.class); @@ -196,6 +199,7 @@ public class MyBatis implements Startable { // keep them sorted alphabetically Class<?>[] mappers = { ActiveRuleMapper.class, + AnalysisPropertiesMapper.class, AuthorizationMapper.class, BranchMapper.class, CeActivityMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java new file mode 100644 index 00000000000..3bc80676119 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java @@ -0,0 +1,78 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import java.util.List; +import javax.annotation.Nullable; +import org.sonar.api.utils.System2; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; + +import static java.util.Objects.requireNonNull; + +public class AnalysisPropertiesDao implements Dao { + private static final int VARCHAR_MAXSIZE = 4000; + + private final System2 system2; + + public AnalysisPropertiesDao(System2 system2) { + this.system2 = system2; + } + + public List<AnalysisPropertyDto> selectBySnapshotUuid(DbSession session, String snapshotUuid) { + requireNonNull(snapshotUuid); + return getMapper(session).selectBySnapshotUuid(snapshotUuid); + } + + public void insert(DbSession session, List<AnalysisPropertyDto> analysisPropertyDto) { + analysisPropertyDto.forEach(a -> insert(session, a)); + } + + public void insert(DbSession session, AnalysisPropertyDto analysisPropertyDto) { + requireNonNull(analysisPropertyDto.getUuid(), "uuid cannot be null"); + requireNonNull(analysisPropertyDto.getKey(), "key cannot be null"); + requireNonNull(analysisPropertyDto.getSnapshotUuid(), "snapshot uuid cannot be null"); + requireNonNull(analysisPropertyDto.getValue(), "value cannot be null"); + + String value = analysisPropertyDto.getValue(); + long now = system2.now(); + + if (isEmpty(value)) { + getMapper(session).insertAsEmpty(analysisPropertyDto, now); + } else if (mustBeStoredInClob(value)) { + getMapper(session).insertAsClob(analysisPropertyDto, now); + } else { + getMapper(session).insertAsText(analysisPropertyDto, now); + } + } + + private static boolean mustBeStoredInClob(String value) { + return value.length() > VARCHAR_MAXSIZE; + } + + private static boolean isEmpty(@Nullable String str) { + return str == null || str.isEmpty(); + } + + private static AnalysisPropertiesMapper getMapper(DbSession session) { + return session.getMapper(AnalysisPropertiesMapper.class); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java new file mode 100644 index 00000000000..3df83a34354 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java @@ -0,0 +1,35 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface AnalysisPropertiesMapper { + + List<AnalysisPropertyDto> selectBySnapshotUuid(@Param("snapshotUuid") String snapshotUuid); + + void insertAsEmpty(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt); + + void insertAsClob(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt); + + void insertAsText(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt); +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertyDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertyDto.java new file mode 100644 index 00000000000..d11bb18e59a --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertyDto.java @@ -0,0 +1,114 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +public class AnalysisPropertyDto { + + private String uuid; + private String snapshotUuid; + private String key; + private String value; + private Long createdAt; + + + public String getUuid() { + return uuid; + } + + public AnalysisPropertyDto setUuid(String uuid) { + requireNonNull(uuid, "uuid cannot be null"); + this.uuid = uuid; + return this; + } + + public String getSnapshotUuid() { + return snapshotUuid; + } + + public AnalysisPropertyDto setSnapshotUuid(String snapshotUuid) { + requireNonNull(snapshotUuid, "snapshotUuid cannot be null"); + this.snapshotUuid = snapshotUuid; + return this; + } + + public String getKey() { + return key; + } + + public AnalysisPropertyDto setKey(String key) { + requireNonNull(key, "key cannot be null"); + this.key = key; + return this; + } + + public String getValue() { + return value; + } + + public AnalysisPropertyDto setValue(String value) { + requireNonNull(value, "value cannot be null"); + this.value = value; + return this; + } + + public Long getCreatedAt() { + return createdAt; + } + + public AnalysisPropertyDto setCreatedAt(Long createdAt) { + this.createdAt = createdAt; + return this; + } + + @Override + public String toString() { + return "BranchDto{" + "uuid='" + uuid + '\'' + + ", snapshotUuid='" + snapshotUuid + '\'' + + ", key='" + key + '\'' + + ", value='" + value + "'" + + ", createdAt=" + createdAt + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AnalysisPropertyDto)) { + return false; + } + AnalysisPropertyDto that = (AnalysisPropertyDto) o; + return Objects.equals(uuid, that.uuid) && + Objects.equals(snapshotUuid, that.snapshotUuid) && + Objects.equals(key, that.key) && + Objects.equals(value, that.value) && + Objects.equals(createdAt, that.createdAt); + } + + @Override + public int hashCode() { + return Objects.hash(uuid, snapshotUuid, key, value, createdAt); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ScrapAnalysisPropertyDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ScrapAnalysisPropertyDto.java new file mode 100644 index 00000000000..e71061a5644 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ScrapAnalysisPropertyDto.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import javax.annotation.Nullable; + +public class ScrapAnalysisPropertyDto extends AnalysisPropertyDto { + public void setEmpty(boolean flag) { + if (flag) { + setValue(""); + } + } + + public void setTextValue(@Nullable String value) { + if (value != null) { + setValue(value); + } + } + + public void setClobValue(@Nullable String value) { + if (value != null) { + setValue(value); + } + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java index 91039c40d61..9d65a9834c8 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java @@ -76,6 +76,11 @@ class PurgeCommands { analysisUuidsPartitions.forEach(purgeMapper::deleteAnalyses); session.commit(); profiler.stop(); + + profiler.start("deleteAnalyses (analysis_properties)"); + analysisUuidsPartitions.forEach(purgeMapper::deleteAnalysisProperties); + session.commit(); + profiler.stop(); } void deleteAnalyses(PurgeSnapshotQuery... queries) { @@ -105,6 +110,11 @@ class PurgeCommands { analysisUuidsPartitions.forEach(purgeMapper::deleteAnalyses); session.commit(); profiler.stop(); + + profiler.start("deleteAnalyses (analysis_properties)"); + analysisUuidsPartitions.forEach(purgeMapper::deleteAnalysisProperties); + session.commit(); + profiler.stop(); } void purgeAnalyses(List<IdUuidPair> analysisUuids) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java index 6ea97e7aa28..3961aa6a335 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java @@ -34,6 +34,8 @@ public interface PurgeMapper { void deleteAnalyses(@Param("analysisUuids") List<String> analysisUuids); + void deleteAnalysisProperties(@Param("analysisUuids") List<String> analysisUuids); + void deleteAnalysisDuplications(@Param("analysisUuids") List<String> analysisUuids); void deleteAnalysisEvents(@Param("analysisUuids") List<String> analysisUuids); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml new file mode 100644 index 00000000000..2dcfb5bc662 --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> +<mapper namespace="org.sonar.db.component.AnalysisPropertiesMapper"> + + <sql id="columns"> + uuid as "uuid", + snapshot_uuid as "snapshotUuid", + kee as "key", + text_value as "textValue", + clob_value as "clobValue", + is_empty as "empty", + created_at as "createdAt" + </sql> + + <select id="selectBySnapshotUuid" parameterType="string" resultType="ScrapAnalysisProperty"> + SELECT + <include refid="columns"/> + FROM + analysis_properties + WHERE + snapshot_uuid = #{snapshotUuid} + </select> + + <insert id="insertAsEmpty" parameterType="map" useGeneratedKeys="false"> + INSERT INTO analysis_properties ( + uuid, + snapshot_uuid, + kee, + is_empty, + created_at + ) VALUES ( + #{analysisPropertyDto.uuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.snapshotUuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.key, jdbcType=VARCHAR}, + ${_true}, + #{createdAt} + ) + </insert> + + <insert id="insertAsText" parameterType="map" useGeneratedKeys="false"> + INSERT INTO analysis_properties ( + uuid, + snapshot_uuid, + kee, + text_value, + is_empty, + created_at + ) VALUES ( + #{analysisPropertyDto.uuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.snapshotUuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.key, jdbcType=VARCHAR}, + #{analysisPropertyDto.value, jdbcType=VARCHAR}, + ${_false}, + #{createdAt} + ) + </insert> + + <insert id="insertAsClob" parameterType="Map" useGeneratedKeys="false"> + INSERT INTO analysis_properties ( + uuid, + snapshot_uuid, + kee, + clob_value, + is_empty, + created_at + ) VALUES ( + #{analysisPropertyDto.uuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.snapshotUuid, jdbcType=VARCHAR}, + #{analysisPropertyDto.key, jdbcType=VARCHAR}, + #{analysisPropertyDto.value, jdbcType=VARCHAR}, + ${_false}, + #{createdAt} + ) + </insert> + +</mapper> diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml index 1b167408045..1316351dced 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml @@ -136,6 +136,15 @@ </foreach> </delete> + <delete id="deleteAnalysisProperties" parameterType="map"> + DELETE FROM analysis_properties + WHERE + snapshot_uuid IN + <foreach collection="analysisUuids" open="(" close=")" item="analysisUuid" separator=","> + #{analysisUuid,jdbcType=VARCHAR} + </foreach> + </delete> + <delete id="deleteAnalysisWastedMeasures" parameterType="map"> delete from project_measures <where> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java index 4fe76690889..5ff22c1e2fd 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java @@ -23,12 +23,13 @@ import org.junit.Test; import org.sonar.core.platform.ComponentContainer; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; public class DaoModuleTest { @Test public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new DaoModule().configure(container); - assertThat(container.size()).isEqualTo(2 + 51); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 52); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java new file mode 100644 index 00000000000..0295573904c --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java @@ -0,0 +1,182 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.TestSystem2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; + +public class AnalysisPropertiesDaoTest { + private static final long NOW = 1_000L; + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private final System2 system2 = new TestSystem2().setNow(NOW); + private final DbSession dbSession = dbTester.getSession(); + private final AnalysisPropertiesDao underTest = new AnalysisPropertiesDao(system2); + private final Random random = new Random(); + + @Test + public void insert_with_null_uuid_throws_NPE() { + AnalysisPropertyDto analysisPropertyDto = new AnalysisPropertyDto() + .setSnapshotUuid(randomAlphanumeric(10)) + .setKey(randomAlphanumeric(10)) + .setValue(randomAlphanumeric(10)); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("uuid cannot be null"); + + underTest.insert(dbSession, analysisPropertyDto); + } + + @Test + public void insert_with_null_key_throws_NPE() { + AnalysisPropertyDto analysisPropertyDto = new AnalysisPropertyDto() + .setSnapshotUuid(randomAlphanumeric(10)) + .setUuid(randomAlphanumeric(10)) + .setValue(randomAlphanumeric(10)); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("key cannot be null"); + + underTest.insert(dbSession, analysisPropertyDto); + } + + @Test + public void insert_with_null_snapshot_uuid_throws_NPE() { + AnalysisPropertyDto analysisPropertyDto = new AnalysisPropertyDto() + .setUuid(randomAlphanumeric(10)) + .setKey(randomAlphanumeric(10)) + .setValue(randomAlphanumeric(10)); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("snapshot uuid cannot be null"); + + underTest.insert(dbSession, analysisPropertyDto); + } + + @Test + public void insert_with_null_value_throws_NPE() { + AnalysisPropertyDto analysisPropertyDto = new AnalysisPropertyDto() + .setSnapshotUuid(randomAlphanumeric(10)) + .setUuid(randomAlphanumeric(10)) + .setKey(randomAlphanumeric(10)); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("value cannot be null"); + + underTest.insert(dbSession, analysisPropertyDto); + } + + @Test + public void insert_as_empty() { + AnalysisPropertyDto analysisPropertyDto = insertAnalysisPropertyDto(0); + + assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(1); + compareFirstValueWith(analysisPropertyDto); + } + + @Test + public void insert_as_text() { + AnalysisPropertyDto analysisPropertyDto = insertAnalysisPropertyDto(1 + random.nextInt(3999)); + + assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(1); + compareFirstValueWith(analysisPropertyDto); + } + + @Test + public void insert_as_clob() { + AnalysisPropertyDto analysisPropertyDto = insertAnalysisPropertyDto(4000 + random.nextInt(100)); + + assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(1); + compareFirstValueWith(analysisPropertyDto); + } + + @Test + public void insert_a_list() { + List<AnalysisPropertyDto> propertyDtos = Arrays.asList( + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40)), + newAnalysisPropertyDto(random.nextInt(8000), randomAlphanumeric(40))); + + underTest.insert(dbSession, propertyDtos); + assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(propertyDtos.size()); + } + + @Test + public void selectByAnalysisUuid_should_return_correct_values() { + String snapshotUuid = randomAlphanumeric(40); + + List<AnalysisPropertyDto> propertyDtos = Arrays.asList( + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid), + newAnalysisPropertyDto(random.nextInt(8000), snapshotUuid)); + + underTest.insert(dbSession, propertyDtos); + assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(propertyDtos.size()); + + List<AnalysisPropertyDto> result = underTest.selectBySnapshotUuid(dbSession, snapshotUuid); + assertThat(result).containsExactlyInAnyOrder((AnalysisPropertyDto[]) propertyDtos.toArray()); + } + + private AnalysisPropertyDto insertAnalysisPropertyDto(int valueLength) { + AnalysisPropertyDto analysisPropertyDto = newAnalysisPropertyDto(valueLength, randomAlphanumeric(40)); + underTest.insert(dbSession, analysisPropertyDto); + return analysisPropertyDto; + } + + private AnalysisPropertyDto newAnalysisPropertyDto(int valueLength, String snapshotUuid) { + return new AnalysisPropertyDto() + .setSnapshotUuid(snapshotUuid) + .setKey(randomAlphanumeric(512)) + .setUuid(randomAlphanumeric(40)) + .setValue(randomAlphanumeric(valueLength)) + .setCreatedAt( 1_000L); + } + + private void compareFirstValueWith(AnalysisPropertyDto analysisPropertyDto) { + AnalysisPropertyDto dtoFromDatabase = underTest.selectBySnapshotUuid(dbSession, analysisPropertyDto.getSnapshotUuid()).get(0); + assertThat(dtoFromDatabase).isEqualTo(analysisPropertyDto); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertyDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertyDtoTest.java new file mode 100644 index 00000000000..252df3efc52 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertyDtoTest.java @@ -0,0 +1,169 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; + +public class AnalysisPropertyDtoTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AnalysisPropertyDto underTest; + + @Test + public void null_key_should_throw_NPE() { + underTest = new AnalysisPropertyDto(); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("key cannot be null"); + + underTest.setKey(null); + } + + @Test + public void null_value_should_throw_NPE() { + underTest = new AnalysisPropertyDto(); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("value cannot be null"); + + underTest.setValue(null); + } + + @Test + public void null_uuid_should_throw_NPE() { + underTest = new AnalysisPropertyDto(); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("uuid cannot be null"); + + underTest.setUuid(null); + } + + @Test + public void null_snapshot_uuid_should_throw_NPE() { + underTest = new AnalysisPropertyDto(); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("snapshotUuid cannot be null"); + + underTest.setSnapshotUuid(null); + } + + @Test + public void test_equality() { + underTest = new AnalysisPropertyDto() + .setUuid(randomAlphanumeric(40)) + .setSnapshotUuid(randomAlphanumeric(40)) + .setKey(randomAlphanumeric(512)) + .setValue(randomAlphanumeric(10000)); + + assertThat(underTest).isEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue())); + + assertThat(underTest).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid("1" + underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue())); + + assertThat(underTest).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid("1" + underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue())); + + assertThat(underTest).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey("1" + underTest.getKey()) + .setValue(underTest.getValue())); + + assertThat(underTest).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue("1" + underTest.getValue())); + } + + @Test + public void test_hashcode() { + underTest = new AnalysisPropertyDto() + .setUuid(randomAlphanumeric(40)) + .setSnapshotUuid(randomAlphanumeric(40)) + .setKey(randomAlphanumeric(512)) + .setValue(randomAlphanumeric(10000)); + + assertThat(underTest.hashCode()).isEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue()) + .hashCode()); + + assertThat(underTest.hashCode()).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid("1" + underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue()) + .hashCode()); + + assertThat(underTest.hashCode()).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid("1" + underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue(underTest.getValue()) + .hashCode()); + + assertThat(underTest.hashCode()).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey("1" + underTest.getKey()) + .setValue(underTest.getValue()) + .hashCode()); + + assertThat(underTest.hashCode()).isNotEqualTo( + new AnalysisPropertyDto() + .setUuid(underTest.getUuid()) + .setSnapshotUuid(underTest.getSnapshotUuid()) + .setKey(underTest.getKey()) + .setValue("1" + underTest.getValue()) + .hashCode()); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ScrapAnalysisPropertyDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ScrapAnalysisPropertyDtoTest.java new file mode 100644 index 00000000000..d1ccaa5d4fe --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ScrapAnalysisPropertyDtoTest.java @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.component; + +import java.util.Random; +import org.junit.Test; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; + +public class ScrapAnalysisPropertyDtoTest { + + private Random random = new Random(); + + @Test + public void test_empty_value() { + ScrapAnalysisPropertyDto underTest = new ScrapAnalysisPropertyDto(); + underTest.setEmpty(true); + + assertThat(underTest.getValue()).isEqualTo(""); + } + + @Test + public void test_text_set() { + ScrapAnalysisPropertyDto underTest = new ScrapAnalysisPropertyDto(); + String value = randomAlphanumeric(random.nextInt(4000)); + underTest.setTextValue(value); + + assertThat(underTest.getValue()).isEqualTo(value); + } + + @Test + public void test_clob_set() { + ScrapAnalysisPropertyDto underTest = new ScrapAnalysisPropertyDto(); + String value = randomAlphanumeric(4000 + random.nextInt(4000)); + underTest.setClobValue(value); + + assertThat(underTest.getValue()).isEqualTo(value); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeCommandsTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeCommandsTest.java index 81196f56e0b..d6b7f01f9f9 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeCommandsTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeCommandsTest.java @@ -20,6 +20,7 @@ package org.sonar.db.purge; import java.util.List; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.sonar.api.utils.System2; @@ -43,6 +44,14 @@ public class PurgeCommandsTest { private PurgeProfiler profiler = new PurgeProfiler(); /** + * Required because there is no autogenerated keys for analysis_properties + */ + @After + public void resetAnalysisProperties() { + dbTester.executeUpdateSql("DELETE FROM analysis_properties"); + } + + /** * Test that SQL queries execution do not fail with a huge number of parameter */ @Test @@ -60,7 +69,7 @@ public class PurgeCommandsTest { new PurgeCommands(dbTester.getSession(), profiler).purgeAnalyses(singletonList(new IdUuidPair(1, "u1"))); - dbTester.assertDbUnit(getClass(), "shouldPurgeAnalysis-result.xml", "snapshots", "project_measures", "duplications_index", "events"); + dbTester.assertDbUnit(getClass(), "shouldPurgeAnalysis-result.xml", "snapshots", "analysis_properties", "project_measures", "duplications_index", "events"); } @Test @@ -105,6 +114,7 @@ public class PurgeCommandsTest { assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(1); assertThat(dbTester.countRowsOfTable("snapshots")).isZero(); + assertThat(dbTester.countRowsOfTable("analysis_properties")).isZero(); assertThat(dbTester.countRowsOfTable("events")).isZero(); assertThat(dbTester.countRowsOfTable("issues")).isEqualTo(1); assertThat(dbTester.countRowsOfTable("issue_changes")).isEqualTo(1); diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldDeleteResource.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldDeleteResource.xml index 330057a1b73..ba8ac69dff9 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldDeleteResource.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldDeleteResource.xml @@ -44,6 +44,15 @@ version="[null]" /> + <analysis_properties uuid="u1" + snapshot_uuid="u1" + kee="key1" + clob_value="[null]" + text_value="value1" + is_empty="[false]" + created_at="1228222680000" + /> + <events id="1" uuid="P1" analysis_uuid="u1" diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis-result.xml index 6cb45a58538..9b8cfc57b26 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis-result.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis-result.xml @@ -33,6 +33,14 @@ Note that measures, events and reviews are not deleted. build_date="1228222680000" version="[null]" /> + <analysis_properties uuid="u1" + snapshot_uuid="u1" + kee="key1" + text_value="value1" + clob_value="[null]" + is_empty="[false]" + created_at="1228222680000" + /> <!--switched_off="[null]" permanent_id="[null]" FAILURE_LEVEL="2"--> <!--MESSAGE="msg1" LINE="[null]" COST="[null]"--> @@ -98,6 +106,14 @@ Note that measures, events and reviews are not deleted. version="[null]" /> + <analysis_properties uuid="u2" + snapshot_uuid="u2" + kee="key2" + clob_value="[null]" + text_value="value2" + is_empty="[false]" + created_at="1228222680000" + /> <project_measures ID="2" component_uuid="2" diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis.xml index d086021a151..70b5a8db7c1 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis.xml @@ -26,6 +26,15 @@ version="[null]" /> + <analysis_properties uuid="u1" + snapshot_uuid="u1" + kee="key1" + clob_value="[null]" + text_value="value1" + is_empty="[false]" + created_at="1228222680000" + /> + <project_measures ID="1" component_uuid="1" analysis_uuid="u1" @@ -90,6 +99,15 @@ version="[null]" /> + <analysis_properties uuid="u2" + snapshot_uuid="u2" + kee="key2" + clob_value="[null]" + text_value="value2" + is_empty="[false]" + created_at="1228222680000" + /> + <project_measures ID="2" component_uuid="2" analysis_uuid="u2" diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisProperties.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisProperties.java new file mode 100644 index 00000000000..f683f860adc --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisProperties.java @@ -0,0 +1,88 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.server.platform.db.migration.version.v67; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef; +import org.sonar.server.platform.db.migration.def.BooleanColumnDef; +import org.sonar.server.platform.db.migration.def.ClobColumnDef; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +public class CreateTableAnalysisProperties extends DdlChange { + private static final String TABLE_NAME = "analysis_properties"; + private static final String SNAPSHOT_UUID = "snapshot_uuid"; + private static final VarcharColumnDef SNAPSHOT_UUID_COLUMN = VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName(SNAPSHOT_UUID) + .setIsNullable(false) + .setLimit(VarcharColumnDef.UUID_SIZE) + .build(); + + public CreateTableAnalysisProperties(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME) + .addPkColumn(VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName("uuid") + .setIsNullable(false) + .setLimit(VarcharColumnDef.UUID_SIZE) + .build()) + .addColumn(SNAPSHOT_UUID_COLUMN) + .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName("kee") + .setIsNullable(false) + .setLimit(512) + .build()) + .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName("text_value") + .setIsNullable(true) + .setLimit(VarcharColumnDef.MAX_SIZE) + .build()) + .addColumn(ClobColumnDef.newClobColumnDefBuilder() + .setColumnName("clob_value") + .setIsNullable(true) + .build()) + .addColumn(BooleanColumnDef.newBooleanColumnDefBuilder() + .setColumnName("is_empty") + .setIsNullable(false) + .build()) + .addColumn(BigIntegerColumnDef.newBigIntegerColumnDefBuilder() + .setColumnName("created_at") + .setIsNullable(false) + .build()) + .build() + ); + + context.execute(new CreateIndexBuilder(getDialect()) + .addColumn(SNAPSHOT_UUID_COLUMN) + .setUnique(false) + .setTable(TABLE_NAME) + .setName("ix_snapshot_uuid") + .build() + ); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67.java index e5b479e4d1d..475e3df7db0 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67.java @@ -27,6 +27,8 @@ public class DbVersion67 implements DbVersion { public void addSteps(MigrationStepRegistry registry) { registry .add(1830, "Copy deprecated server ID", CopyDeprecatedServerId.class) - .add(1831, "Add webhook_deliveries.analysis_uuid", AddAnalysisUuidToWebhookDeliveries.class); + .add(1831, "Add webhook_deliveries.analysis_uuid", AddAnalysisUuidToWebhookDeliveries.class) + .add(1832, "Create table ANALYSIS_PROPERTIES", CreateTableAnalysisProperties.class) + ; } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest.java new file mode 100644 index 00000000000..e667d96b124 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest.java @@ -0,0 +1,53 @@ +package org.sonar.server.platform.db.migration.version.v67;/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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. + */ + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CreateTableAnalysisPropertiesTest { + private static final String TABLE = "analysis_properties"; + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(CreateTableAnalysisPropertiesTest.class, "empty.sql"); + + private CreateTableAnalysisProperties underTest = new CreateTableAnalysisProperties(db.database()); + + @Test + public void creates_table_on_empty_db() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0); + + db.assertColumnDefinition(TABLE, "uuid", Types.VARCHAR, 40, false); + db.assertColumnDefinition(TABLE, "snapshot_uuid", Types.VARCHAR, 40, false); + db.assertColumnDefinition(TABLE, "kee", Types.VARCHAR, 512, false); + db.assertColumnDefinition(TABLE, "text_value", Types.VARCHAR, 4000, true); + db.assertColumnDefinition(TABLE, "clob_value", Types.CLOB, 2147483647, true); + db.assertColumnDefinition(TABLE, "is_empty", Types.BOOLEAN, null, false); + db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false); + + db.assertIndex(TABLE, "ix_snapshot_uuid", "snapshot_uuid"); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67Test.java index ada1069cc8d..4fef78d7e20 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v67/DbVersion67Test.java @@ -36,7 +36,7 @@ public class DbVersion67Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 2); + verifyMigrationCount(underTest, 3); } } diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest/empty.sql new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v67/CreateTableAnalysisPropertiesTest/empty.sql diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStep.java new file mode 100644 index 00000000000..c85504e3755 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStep.java @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.server.computation.task.projectanalysis.step; + +import java.util.ArrayList; +import java.util.List; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.component.AnalysisPropertyDto; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; +import org.sonar.server.computation.task.step.ComputationStep; + +/** + * Persist analysis properties + * Only properties starting with "sonar.analysis" will be persisted in database + */ +public class PersistAnalysisPropertiesStep implements ComputationStep { + + private static final String SONAR_ANALYSIS = "sonar.analysis."; + + private final DbClient dbClient; + private final AnalysisMetadataHolder analysisMetadataHolder; + private final BatchReportReader reportReader; + private final UuidFactory uuidFactory; + + public PersistAnalysisPropertiesStep(DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder, + BatchReportReader reportReader, UuidFactory uuidFactory) { + this.dbClient = dbClient; + this.analysisMetadataHolder = analysisMetadataHolder; + this.reportReader = reportReader; + this.uuidFactory = uuidFactory; + } + + @Override + public void execute() { + final List<AnalysisPropertyDto> analysisPropertyDtos = new ArrayList<>(); + reportReader.readContextProperties().forEachRemaining( + contextProperty -> { + if (contextProperty.getKey().startsWith(SONAR_ANALYSIS)) { + analysisPropertyDtos.add(new AnalysisPropertyDto() + .setUuid(uuidFactory.create()) + .setKey(contextProperty.getKey()) + .setValue(contextProperty.getValue()) + .setSnapshotUuid(analysisMetadataHolder.getUuid())); + } + }); + + if (analysisPropertyDtos.isEmpty()) { + return; + } + + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.analysisPropertiesDao().insert(dbSession, analysisPropertyDtos); + dbSession.commit(); + } + } + + @Override + public String getDescription() { + return "Persist analysis properties"; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java index d60f9441d46..108ca3b9d84 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java @@ -86,6 +86,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { // Persist data PersistComponentsStep.class, PersistAnalysisStep.class, + PersistAnalysisPropertiesStep.class, PersistMeasuresStep.class, PersistIssuesStep.class, PersistProjectLinksStep.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStepTest.java new file mode 100644 index 00000000000..3006fba9b41 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistAnalysisPropertiesStepTest.java @@ -0,0 +1,94 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.server.computation.task.projectanalysis.step; + +import java.util.Arrays; +import java.util.List; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.core.util.CloseableIterator; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbTester; +import org.sonar.db.component.AnalysisPropertyDto; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PersistAnalysisPropertiesStepTest { + private static final String SNAPSHOT_UUID = randomAlphanumeric(40); + private static final String SMALL_VALUE1 = randomAlphanumeric(50); + private static final String SMALL_VALUE2 = randomAlphanumeric(50); + private static final String BIG_VALUE = randomAlphanumeric(5000); + private static final List<ScannerReport.ContextProperty> PROPERTIES = Arrays.asList( + newContextProperty("key1", "value1"), + newContextProperty("key2", "value1"), + newContextProperty("sonar.analysis", SMALL_VALUE1), + newContextProperty("sonar.analysis.branch", SMALL_VALUE1), + newContextProperty("sonar.analysis.empty_string", ""), + newContextProperty("sonar.analysis.big_value", BIG_VALUE), + newContextProperty("sonar.analysis.", SMALL_VALUE2)); + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + private BatchReportReader batchReportReader = mock(BatchReportReader.class); + private AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class); + private PersistAnalysisPropertiesStep underTest = new PersistAnalysisPropertiesStep(dbTester.getDbClient(), analysisMetadataHolder, batchReportReader, UuidFactoryFast.getInstance()); + + @Before + public void setup() { + when(batchReportReader.readContextProperties()).thenReturn(CloseableIterator.from(PROPERTIES.iterator())); + when(analysisMetadataHolder.getUuid()).thenReturn(SNAPSHOT_UUID); + } + + @Test + public void persist_should_store_only_sonarDotAnalysis_properties() { + underTest.execute(); + assertThat(dbTester.countRowsOfTable("analysis_properties")).isEqualTo(4); + + List<AnalysisPropertyDto> propertyDtos = dbTester.getDbClient() + .analysisPropertiesDao().selectBySnapshotUuid(dbTester.getSession(), SNAPSHOT_UUID); + + assertThat(propertyDtos) + .extracting(AnalysisPropertyDto::getSnapshotUuid, AnalysisPropertyDto::getKey, AnalysisPropertyDto::getValue) + .containsExactlyInAnyOrder( + tuple(SNAPSHOT_UUID, "sonar.analysis.branch", SMALL_VALUE1), + tuple(SNAPSHOT_UUID, "sonar.analysis.empty_string", ""), + tuple(SNAPSHOT_UUID, "sonar.analysis.big_value", BIG_VALUE), + tuple(SNAPSHOT_UUID, "sonar.analysis.", SMALL_VALUE2) + ); + } + + private static ScannerReport.ContextProperty newContextProperty(String key, String value) { + return ScannerReport.ContextProperty.newBuilder() + .setKey(key) + .setValue(value) + .build(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistAnalysisStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistAnalysisStepTest.java index 40fbf42f133..3a3bb64bdd8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistAnalysisStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistAnalysisStepTest.java @@ -63,16 +63,11 @@ public class ReportPersistAnalysisStepTest extends BaseStepTest { public PeriodHolderRule periodsHolder = new PeriodHolderRule(); private System2 system2 = mock(System2.class); - private DbIdsRepositoryImpl dbIdsRepository; - private DbClient dbClient = dbTester.getDbClient(); - private long analysisDate; - private long now; - - PersistAnalysisStep underTest; + private PersistAnalysisStep underTest; @Before public void setup() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistAnalysisStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistAnalysisStepTest.java index ba90ba20e89..7d7434d56b3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistAnalysisStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistAnalysisStepTest.java @@ -64,13 +64,9 @@ public class ViewsPersistAnalysisStepTest extends BaseStepTest { public PeriodHolderRule periodsHolder = new PeriodHolderRule(); private System2 system2 = mock(System2.class); - private DbClient dbClient = dbTester.getDbClient(); - private long analysisDate; - private long now; - private PersistAnalysisStep underTest; @Before |