Browse Source

SONAR-12061 Create 'INTERNAL_COMPONENT_PROPS' table

tags/7.8
Benoît Gianinetti 5 years ago
parent
commit
5e41f4d0ce
16 changed files with 791 additions and 4 deletions
  1. 1
    1
      server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
  2. 10
    0
      server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
  3. 2
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
  4. 7
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
  5. 4
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
  6. 63
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertiesDao.java
  7. 35
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertiesMapper.java
  8. 108
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertyDto.java
  9. 62
    0
      server/sonar-db-dao/src/main/resources/org/sonar/db/property/InternalComponentPropertiesMapper.xml
  10. 1
    1
      server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
  11. 223
    0
      server/sonar-db-dao/src/test/java/org/sonar/db/property/InternalComponentPropertiesDaoTest.java
  12. 104
    0
      server/sonar-db-dao/src/test/java/org/sonar/db/property/InternalComponentPropertyDtoTest.java
  13. 106
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v78/CreateInternalComponentPropertiesTable.java
  14. 2
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v78/DbVersion78.java
  15. 62
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v78/CreateInternalComponentPropertiesTableTest.java
  16. 1
    1
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v78/DbVersion78Test.java

+ 1
- 1
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java View File

@@ -122,7 +122,7 @@ public class ComputeEngineContainerImplTest {
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

+ 10
- 0
server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl View File

@@ -451,6 +451,16 @@ CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
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),

+ 2
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java View File

@@ -58,6 +58,7 @@ import org.sonar.db.permission.UserPermissionDao;
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;
@@ -113,6 +114,7 @@ public class DaoModule extends Module {
GroupPermissionDao.class,
AlmAppInstallDao.class,
ProjectAlmBindingDao.class,
InternalComponentPropertiesDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,

+ 7
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java View File

@@ -56,6 +56,7 @@ import org.sonar.db.permission.UserPermissionDao;
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;
@@ -96,6 +97,7 @@ public class DbClient {
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;
@@ -218,6 +220,7 @@ public class DbClient {
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) {
@@ -477,4 +480,8 @@ public class DbClient {
public OrganizationAlmBindingDao organizationAlmBindingDao() {
return organizationAlmBindingDao;
}

public InternalComponentPropertiesDao internalComponentPropertiesDao() {
return internalComponentPropertiesDao;
}
}

+ 4
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java View File

@@ -99,6 +99,8 @@ import org.sonar.db.permission.template.PermissionTemplateMapper;
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;
@@ -180,6 +182,7 @@ public class MyBatis implements Startable {
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);
@@ -241,6 +244,7 @@ public class MyBatis implements Startable {
GroupMapper.class,
GroupMembershipMapper.class,
GroupPermissionMapper.class,
InternalComponentPropertiesMapper.class,
InternalPropertiesMapper.class,
IsAliveMapper.class,
IssueChangeMapper.class,

+ 63
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertiesDao.java View File

@@ -0,0 +1,63 @@
/*
* 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);
}
}

+ 35
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertiesMapper.java View File

@@ -0,0 +1,35 @@
/*
* 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);

}

+ 108
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalComponentPropertyDto.java View File

@@ -0,0 +1,108 @@
/*
* 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();
}
}

+ 62
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/property/InternalComponentPropertiesMapper.xml View File

@@ -0,0 +1,62 @@
<?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>

+ 1
- 1
server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java View File

@@ -30,6 +30,6 @@ public class DaoModuleTest {
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);
}
}

+ 223
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/property/InternalComponentPropertiesDaoTest.java View File

@@ -0,0 +1,223 @@
/*
* 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;
}

}

}

+ 104
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/property/InternalComponentPropertyDtoTest.java View File

@@ -0,0 +1,104 @@
/*
* 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}");
}
}

+ 106
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v78/CreateInternalComponentPropertiesTable.java View File

@@ -0,0 +1,106 @@
/*
* 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);
}
}
}

+ 2
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v78/DbVersion78.java View File

@@ -30,6 +30,7 @@ public class DbVersion78 implements DbVersion {
.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);
}
}

+ 62
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v78/CreateInternalComponentPropertiesTableTest.java View File

@@ -0,0 +1,62 @@
/*
* 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");
}
}

+ 1
- 1
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v78/DbVersion78Test.java View File

@@ -35,7 +35,7 @@ public class DbVersion78Test {

@Test
public void verify_migration_count() {
verifyMigrationCount(underTest, 4);
verifyMigrationCount(underTest, 5);
}

}

Loading…
Cancel
Save