assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 26 // level 1
- + 60 // content of DaoModule
+ + 61 // content of DaoModule
+ 3 // content of EsModule
+ 52 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
+CREATE TABLE "INTERNAL_COMPONENT_PROPS" (
+ "UUID" VARCHAR(40) NOT NULL,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "KEE" VARCHAR(512) NOT NULL,
+ "VALUE" VARCHAR(4000),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ CONSTRAINT "INTERNAL_COMPONENT_PROPS_UUID" PRIMARY KEY ("UUID")
+);
+CREATE UNIQUE INDEX "UNIQUE_COMPONENT_UUID_KEE" ON "INTERNAL_COMPONENT_PROPS" ("COMPONENT_UUID", "KEE");
CREATE TABLE "MANUAL_MEASURES" (
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao;
import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.plugin.PluginDao;
+import org.sonar.db.property.InternalComponentPropertiesDao;
import org.sonar.db.property.InternalPropertiesDao;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.purge.PurgeDao;
GroupPermissionDao.class,
AlmAppInstallDao.class,
ProjectAlmBindingDao.class,
+ InternalComponentPropertiesDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao;
import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.plugin.PluginDao;
+import org.sonar.db.property.InternalComponentPropertiesDao;
import org.sonar.db.property.InternalPropertiesDao;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.purge.PurgeDao;
private final PropertiesDao propertiesDao;
private final AlmAppInstallDao almAppInstallDao;
private final ProjectAlmBindingDao projectAlmBindingDao;
+ private final InternalComponentPropertiesDao internalComponentPropertiesDao;
private final InternalPropertiesDao internalPropertiesDao;
private final SnapshotDao snapshotDao;
private final ComponentDao componentDao;
webhookDeliveryDao = getDao(map, WebhookDeliveryDao.class);
projectMappingsDao = getDao(map, ProjectMappingsDao.class);
organizationAlmBindingDao = getDao(map, OrganizationAlmBindingDao.class);
+ internalComponentPropertiesDao = getDao(map, InternalComponentPropertiesDao.class);
}
public DbSession openSession(boolean batch) {
public OrganizationAlmBindingDao organizationAlmBindingDao() {
return organizationAlmBindingDao;
}
+
+ public InternalComponentPropertiesDao internalComponentPropertiesDao() {
+ return internalComponentPropertiesDao;
+ }
}
import org.sonar.db.permission.template.PermissionTemplateUserDto;
import org.sonar.db.plugin.PluginDto;
import org.sonar.db.plugin.PluginMapper;
+import org.sonar.db.property.InternalComponentPropertiesMapper;
+import org.sonar.db.property.InternalComponentPropertyDto;
import org.sonar.db.property.InternalPropertiesMapper;
import org.sonar.db.property.InternalPropertyDto;
import org.sonar.db.property.PropertiesMapper;
confBuilder.loadAlias("GroupPermission", GroupPermissionDto.class);
confBuilder.loadAlias("IdUuidPair", IdUuidPair.class);
confBuilder.loadAlias("InternalProperty", InternalPropertyDto.class);
+ confBuilder.loadAlias("InternalComponentProperty", InternalComponentPropertyDto.class);
confBuilder.loadAlias("IssueChange", IssueChangeDto.class);
confBuilder.loadAlias("KeyLongValue", KeyLongValue.class);
confBuilder.loadAlias("Issue", IssueDto.class);
GroupMapper.class,
GroupMembershipMapper.class,
GroupPermissionMapper.class,
+ InternalComponentPropertiesMapper.class,
InternalPropertiesMapper.class,
IsAliveMapper.class,
IssueChangeMapper.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.property;
+
+import java.util.Optional;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+public class InternalComponentPropertiesDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public InternalComponentPropertiesDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public void insertOrUpdate(DbSession dbSession, InternalComponentPropertyDto dto) {
+ InternalComponentPropertiesMapper mapper = getMapper(dbSession);
+
+ dto.setUpdatedAt(system2.now());
+
+ if (mapper.update(dto) == 1) {
+ return;
+ }
+
+ dto.setUuid(uuidFactory.create());
+ dto.setCreatedAt(system2.now());
+ mapper.insert(dto);
+ }
+
+ public Optional<InternalComponentPropertyDto> selectByComponentUuidAndKey(DbSession dbSession, String componentUuid, String key) {
+ return getMapper(dbSession).selectByComponentUuidAndKey(componentUuid, key);
+ }
+
+ public int deleteByComponentUuidAndKey(DbSession dbSession, String componentUuid, String key) {
+ return getMapper(dbSession).deleteByComponentUuidAndKey(componentUuid, key);
+ }
+
+ private static InternalComponentPropertiesMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(InternalComponentPropertiesMapper.class);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.property;
+
+import java.util.Optional;
+import org.apache.ibatis.annotations.Param;
+
+public interface InternalComponentPropertiesMapper {
+
+ Optional<InternalComponentPropertyDto> selectByComponentUuidAndKey(@Param("componentUuid") String componentUuid, @Param("key") String key);
+
+ void insert(@Param("dto") InternalComponentPropertyDto dto);
+
+ int update(@Param("dto") InternalComponentPropertyDto dto);
+
+ int deleteByComponentUuidAndKey(@Param("componentUuid") String componentUuid, @Param("key") String key);
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.property;
+
+import com.google.common.base.MoreObjects;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class InternalComponentPropertyDto {
+ private static final int MAX_KEY_LENGTH = 512;
+ private static final int MAX_VALUE_LENGTH = 4000;
+
+ private String uuid;
+ private String key;
+ private String value;
+ private String componentUuid;
+ private Long createdAt;
+ private Long updatedAt;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public InternalComponentPropertyDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public InternalComponentPropertyDto setKey(String key) {
+ checkArgument(key != null && !key.isEmpty(), "key can't be null nor empty");
+ checkArgument(key.length() <= MAX_KEY_LENGTH, "key length (%s) is longer than the maximum authorized (%s). '%s' was provided", key.length(), MAX_KEY_LENGTH, key);
+ this.key = key;
+ return this;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public InternalComponentPropertyDto setValue(@Nullable String value) {
+ if (value != null) {
+ checkArgument(value.length() <= MAX_VALUE_LENGTH, "value length (%s) is longer than the maximum authorized (%s). '%s' was provided", value.length(), MAX_VALUE_LENGTH, value);
+ }
+ this.value = value;
+ return this;
+ }
+
+ public String getComponentUuid() {
+ return componentUuid;
+ }
+
+ public InternalComponentPropertyDto setComponentUuid(String componentUuid) {
+ this.componentUuid = componentUuid;
+ return this;
+ }
+
+ public Long getCreatedAt() {
+ return createdAt;
+ }
+
+ public InternalComponentPropertyDto setCreatedAt(Long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public Long getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public InternalComponentPropertyDto setUpdatedAt(Long updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper("InternalComponentPropertyDto")
+ .add("uuid", this.uuid)
+ .add("key", this.key)
+ .add("value", this.value)
+ .add("componentUuid", this.componentUuid)
+ .add("updatedAt", this.updatedAt)
+ .add("createdAt", this.createdAt)
+ .toString();
+ }
+}
--- /dev/null
+<?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.property.InternalComponentPropertiesMapper">
+
+ <select id="selectByComponentUuidAndKey" parameterType="map" resultType="org.sonar.db.property.InternalComponentPropertyDto">
+ SELECT
+ p.uuid as uuid,
+ p.component_uuid as componentUuid,
+ p.kee as "key",
+ p.value as value,
+ p.updated_at as updatedAt,
+ p.created_at as createdAt
+ FROM
+ internal_component_props p
+ <where>
+ p.component_uuid = #{componentUuid, jdbcType=VARCHAR}
+ AND p.kee = #{key, jdbcType=VARCHAR}
+ </where>
+ </select>
+
+ <insert id="insert" parameterType="Map">
+ insert into internal_component_props
+ (
+ uuid,
+ component_uuid,
+ kee,
+ value,
+ updated_at,
+ created_at
+ )
+ values (
+ #{dto.uuid},
+ #{dto.componentUuid},
+ #{dto.key},
+ #{dto.value},
+ #{dto.updatedAt},
+ #{dto.createdAt}
+ )
+ </insert>
+
+ <update id="update" parameterType="map">
+ update internal_component_props
+ <set>
+ value = #{dto.value, jdbcType=VARCHAR},
+ updated_at = #{dto.updatedAt, jdbcType=BIGINT}
+ </set>
+ <where>
+ component_uuid = #{dto.componentUuid, jdbcType=VARCHAR}
+ AND kee = #{dto.key}
+ </where>
+ </update>
+
+ <delete id="deleteByComponentUuidAndKey" parameterType="map">
+ DELETE FROM internal_component_props
+ <where>
+ component_uuid = #{componentUuid, jdbcType=VARCHAR}
+ AND kee = #{key,jdbcType=VARCHAR}
+ </where>
+ </delete>
+
+</mapper>
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 60);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 61);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.property;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import org.apache.commons.lang.math.RandomUtils;
+import org.assertj.core.api.AbstractAssert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class InternalComponentPropertiesDaoTest {
+
+ private static final String SOME_KEY = "key1";
+ private static final String SOME_COMPONENT = "component1";
+ private static final String SOME_VALUE = "value";
+
+ private System2 system2 = mock(System2.class);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester dbTester = DbTester.create(system2);
+ private DbSession dbSession = dbTester.getSession();
+ private UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+ private InternalComponentPropertiesDao underTest = new InternalComponentPropertiesDao(system2, uuidFactory);
+
+ @Test
+ public void insertOrUpdate_insert_property_if_it_doesnt_already_exist() {
+ InternalComponentPropertyDto dto = new InternalComponentPropertyDto()
+ .setKey(SOME_KEY)
+ .setComponentUuid(SOME_COMPONENT)
+ .setValue(SOME_VALUE);
+
+ long now = RandomUtils.nextLong();
+ when(system2.now()).thenReturn(now);
+
+ underTest.insertOrUpdate(dbSession, dto);
+
+ assertThatInternalProperty(dto.getUuid())
+ .hasComponentUuid(SOME_COMPONENT)
+ .hasKey(SOME_KEY)
+ .hasValue(SOME_VALUE)
+ .hasUpdatedAt(now)
+ .hasCreatedAt(now);
+ }
+
+ @Test
+ public void insertOrUpdate_update_property_if_it_already_exists() {
+ long creationDate = 10L;
+ when(system2.now()).thenReturn(creationDate);
+
+ InternalComponentPropertyDto dto = saveDto();
+
+ long updateDate = 20L;
+ when(system2.now()).thenReturn(updateDate);
+
+ dto.setValue("other value");
+
+ underTest.insertOrUpdate(dbSession, dto);
+
+ assertThatInternalProperty(dto.getUuid())
+ .hasUpdatedAt(updateDate)
+ .hasValue("other value")
+ .hasCreatedAt(creationDate);
+ }
+
+ @Test
+ public void select_by_component_uuid_and_key_returns_property() {
+ saveDto();
+
+ Optional<InternalComponentPropertyDto> result = underTest.selectByComponentUuidAndKey(dbSession, SOME_COMPONENT, SOME_KEY);
+ assertThat(result.get())
+ .extracting("componentUuid", "key", "value")
+ .contains(SOME_COMPONENT, SOME_KEY, SOME_VALUE);
+ }
+
+ @Test
+ public void select_by_component_uuid_and_key_returns_empty_when_it_doesnt_exist() {
+ saveDto();
+
+ assertThat(underTest.selectByComponentUuidAndKey(dbSession, "other_component", SOME_KEY)).isEmpty();
+ assertThat(underTest.selectByComponentUuidAndKey(dbSession, SOME_COMPONENT, "other_key")).isEmpty();
+ }
+
+ @Test
+ public void delete_by_component_uuid_and_key_deletes_property() {
+ saveDto();
+
+ assertThat(underTest.deleteByComponentUuidAndKey(dbSession, SOME_COMPONENT, SOME_KEY)).isEqualTo(1);
+ assertThat(underTest.selectByComponentUuidAndKey(dbSession, SOME_COMPONENT, SOME_KEY)).isEmpty();
+ }
+
+ @Test
+ public void delete_by_component_uuid_and_key_does_nothing_if_property_doesnt_exist() {
+ saveDto();
+
+ assertThat(underTest.deleteByComponentUuidAndKey(dbSession, SOME_COMPONENT, "other_key")).isEqualTo(0);
+ assertThat(underTest.deleteByComponentUuidAndKey(dbSession, "other_component", SOME_KEY)).isEqualTo(0);
+ assertThat(underTest.selectByComponentUuidAndKey(dbSession, SOME_COMPONENT, SOME_KEY)).isNotEmpty();
+ }
+
+ private InternalComponentPropertyDto saveDto() {
+ InternalComponentPropertyDto dto = new InternalComponentPropertyDto()
+ .setKey(SOME_KEY)
+ .setComponentUuid(SOME_COMPONENT)
+ .setValue(SOME_VALUE);
+
+ underTest.insertOrUpdate(dbSession, dto);
+ return dto;
+ }
+
+ private InternalComponentPropertyAssert assertThatInternalProperty(String uuid) {
+ return new InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert(dbTester, dbSession, uuid);
+ }
+
+ private static class InternalComponentPropertyAssert extends AbstractAssert<InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert, InternalComponentPropertyDto> {
+
+ public InternalComponentPropertyAssert(DbTester dbTester, DbSession dbSession, String uuid) {
+ super(asInternalProperty(dbTester, dbSession, uuid), InternalComponentPropertyAssert.class);
+ }
+
+ private static InternalComponentPropertyDto asInternalProperty(DbTester dbTester, DbSession dbSession, String uuid) {
+ Map<String, Object> row = dbTester.selectFirst(
+ dbSession,
+ "select" +
+ " uuid as \"uuid\", component_uuid as \"componentUuid\", kee as \"key\", value as \"value\", updated_at as \"updatedAt\", created_at as \"createdAt\"" +
+ " from internal_component_props" +
+ " where uuid='" + uuid+ "'");
+ return new InternalComponentPropertyDto()
+ .setUuid((String) row.get("uuid"))
+ .setComponentUuid((String) row.get("componentUuid"))
+ .setKey((String) row.get("key"))
+ .setValue((String) row.get("value"))
+ .setUpdatedAt((Long) row.get("updatedAt"))
+ .setCreatedAt((Long) row.get("createdAt"));
+ }
+
+ public void doesNotExist() {
+ isNull();
+ }
+
+ public InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert hasKey(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getKey(), expected)) {
+ failWithMessage("Expected Internal property to have column KEY to be <%s> but was <%s>", true, actual.getKey());
+ }
+
+ return this;
+ }
+
+ public InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert hasComponentUuid(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getComponentUuid(), expected)) {
+ failWithMessage("Expected Internal property to have column COMPONENT_UUID to be <%s> but was <%s>", true, actual.getComponentUuid());
+ }
+
+ return this;
+ }
+
+ public InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert hasValue(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getValue(), expected)) {
+ failWithMessage("Expected Internal property to have column VALUE to be <%s> but was <%s>", true, actual.getValue());
+ }
+
+ return this;
+ }
+
+ public InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert hasCreatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getCreatedAt(), expected)) {
+ failWithMessage("Expected Internal property to have column CREATED_AT to be <%s> but was <%s>", expected, actual.getCreatedAt());
+ }
+
+ return this;
+ }
+
+ public InternalComponentPropertiesDaoTest.InternalComponentPropertyAssert hasUpdatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getUpdatedAt(), expected)) {
+ failWithMessage("Expected Internal property to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.getUpdatedAt());
+ }
+
+ return this;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.property;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(DataProviderRunner.class)
+public class InternalComponentPropertyDtoTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void setter_and_getter() {
+ InternalComponentPropertyDto underTest = new InternalComponentPropertyDto()
+ .setComponentUuid("component1")
+ .setKey("key1")
+ .setValue("value1")
+ .setUuid("uuid1")
+ .setCreatedAt(10L)
+ .setUpdatedAt(15L);
+
+ assertThat(underTest.getComponentUuid()).isEqualTo("component1");
+ assertThat(underTest.getKey()).isEqualTo("key1");
+ assertThat(underTest.getValue()).isEqualTo("value1");
+ assertThat(underTest.getUuid()).isEqualTo("uuid1");
+ assertThat(underTest.getCreatedAt()).isEqualTo(10L);
+ assertThat(underTest.getUpdatedAt()).isEqualTo(15L);
+ }
+
+ @Test
+ @DataProvider({"null", ""})
+ public void setKey_throws_IAE_if_key_is_null_or_empty(String key) {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("key can't be null nor empty");
+
+ new InternalComponentPropertyDto().setKey(key);
+ }
+
+ @Test
+ public void setKey_throws_IAE_if_key_is_too_long() {
+ String veryLongKey = StringUtils.repeat("a", 513);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage(String.format("key length (513) is longer than the maximum authorized (512). '%s' was provided", veryLongKey));
+
+ new InternalComponentPropertyDto().setKey(veryLongKey);
+ }
+
+ @Test
+ public void setValue_throws_IAE_if_value_is_too_long() {
+ String veryLongValue = StringUtils.repeat("a", 4001);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage(String.format("value length (4001) is longer than the maximum authorized (4000). '%s' was provided", veryLongValue));
+
+ new InternalComponentPropertyDto().setValue(veryLongValue);
+ }
+
+ @Test
+ public void setValue_accept_null_value() {
+ InternalComponentPropertyDto underTest = new InternalComponentPropertyDto().setValue(null);
+
+ assertThat(underTest.getValue()).isNull();
+ }
+
+ @Test
+ public void test_toString() {
+ InternalComponentPropertyDto underTest = new InternalComponentPropertyDto()
+ .setUuid("uuid1")
+ .setComponentUuid("component1")
+ .setKey("key1")
+ .setValue("value1")
+ .setCreatedAt(10L)
+ .setUpdatedAt(15L);
+
+ assertThat(underTest.toString()).isEqualTo("InternalComponentPropertyDto{uuid=uuid1, key=key1, value=value1, componentUuid=component1, updatedAt=15, createdAt=10}");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.v78;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef;
+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;
+
+import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+@SupportsBlueGreen
+public class CreateInternalComponentPropertiesTable extends DdlChange {
+
+ private static final String TABLE_NAME = "internal_component_props";
+
+ private static final VarcharColumnDef UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+
+ private static final VarcharColumnDef COMPONENT_UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("component_uuid")
+ .setIsNullable(false)
+ .setLimit(50)
+ .build();
+
+ private static final VarcharColumnDef KEE_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("kee")
+ .setIsNullable(false)
+ .setLimit(512)
+ .build();
+
+ private static final VarcharColumnDef VALUE_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("value")
+ .setIsNullable(true)
+ .setLimit(4000)
+ .build();
+
+ private static final BigIntegerColumnDef UPDATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("updated_at")
+ .setIsNullable(false)
+ .build();
+
+ private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("created_at")
+ .setIsNullable(false)
+ .build();
+
+ public CreateInternalComponentPropertiesTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ if (!tableExists()) {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(UUID_COLUMN)
+ .addColumn(COMPONENT_UUID_COLUMN)
+ .addColumn(KEE_COLUMN)
+ .addColumn(VALUE_COLUMN)
+ .addColumn(UPDATED_AT_COLUMN)
+ .addColumn(CREATED_AT_COLUMN)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(COMPONENT_UUID_COLUMN)
+ .addColumn(KEE_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("unique_component_uuid_kee")
+ .build());
+ }
+ }
+
+ private boolean tableExists() throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ return DatabaseUtils.tableExists(TABLE_NAME, connection);
+ }
+ }
+}
.add(2700, "Drop overall subscriptions on notifications about new and resolved issues", DeleteOverallSubscriptionsOnNewAndResolvedIssuesNotifications.class)
.add(2701, "Add index to org_qprofile.parent_uuid", AddIndexToOrgQProfileParentUuid.class)
.add(2702, "Add column webhooks.secret", AddWebhooksSecret.class)
- .add(2703, "Add security fields to Elasticsearch indices", AddSecurityFieldsToElasticsearchIndices.class);
+ .add(2703, "Add security fields to Elasticsearch indices", AddSecurityFieldsToElasticsearchIndices.class)
+ .add(2704, "Add InternalComponentProperties table", CreateInternalComponentPropertiesTable.class);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.v78;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class CreateInternalComponentPropertiesTableTest {
+
+ private static final String TABLE = "internal_component_props";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createEmpty();
+
+ private CreateInternalComponentPropertiesTable underTest = new CreateInternalComponentPropertiesTable(db.database());
+
+ @Test
+ public void creates_table() throws SQLException {
+ underTest.execute();
+
+ checkTable();
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+ underTest.execute();
+
+ checkTable();
+ }
+
+ private void checkTable() {
+ db.assertColumnDefinition(TABLE, "uuid", Types.VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "component_uuid", Types.VARCHAR, 50, false);
+ db.assertColumnDefinition(TABLE, "kee", Types.VARCHAR, 512, false);
+ db.assertColumnDefinition(TABLE, "value", Types.VARCHAR, 4000, true);
+ db.assertColumnDefinition(TABLE, "updated_at", Types.BIGINT, null, false);
+ db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false);
+
+ db.assertUniqueIndex(TABLE, "unique_component_uuid_kee", "component_uuid", "kee");
+ }
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 4);
+ verifyMigrationCount(underTest, 5);
}
}