From: Julien HENRY Date: Thu, 26 Apr 2018 14:59:26 +0000 (+0200) Subject: SONAR-10515 ALM App Install table + DAO X-Git-Tag: 7.5~1297 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=358970f046428250a4b026beab982d84d0aecf02;p=sonarqube.git SONAR-10515 ALM App Install table + DAO * Add migration to create table alm_app_installs * Add dao for alm_app_installs --- 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 7afde4f1d06..d2ff2acdd1e 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 @@ -119,7 +119,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION + 26 // level 1 - + 53 // content of DaoModule + + 54 // content of DaoModule + 3 // content of EsModule + 59 // content of CorePropertyDefinitions + 1 // StopFlagContainer diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java index 1843f327d76..cf7e5586769 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java @@ -52,6 +52,7 @@ public final class SqTables { public static final Set TABLES = unmodifiableSet(new HashSet<>(asList( "active_rules", "active_rule_parameters", + "alm_app_installs", "analysis_properties", "ce_activity", "ce_queue", 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 35a9732f71a..fc72c134c97 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 @@ -790,3 +790,15 @@ CREATE UNIQUE INDEX "PK_WEBHOOK_DELIVERIES" ON "WEBHOOK_DELIVERIES" ("UUID"); CREATE INDEX "COMPONENT_UUID" ON "WEBHOOK_DELIVERIES" ("COMPONENT_UUID"); CREATE INDEX "CE_TASK_UUID" ON "WEBHOOK_DELIVERIES" ("CE_TASK_UUID"); CREATE INDEX "ANALYSIS_UUID" ON "WEBHOOK_DELIVERIES" ("ANALYSIS_UUID"); + +CREATE TABLE "ALM_APP_INSTALLS" ( + "UUID" VARCHAR(40) NOT NULL PRIMARY KEY, + "ALM_ID" VARCHAR(40) NOT NULL, + "OWNER_ID" VARCHAR(4000) NOT NULL, + "INSTALL_ID" VARCHAR(4000) NOT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + CONSTRAINT "PK_ALM_APP_INSTALLS" PRIMARY KEY ("UUID") +); +CREATE UNIQUE INDEX "ALM_APP_INSTALLS_OWNER" ON "ALM_APP_INSTALLS" ("ALM_ID", "OWNER_ID"); +CREATE UNIQUE INDEX "ALM_APP_INSTALLS_INSTALL" ON "ALM_APP_INSTALLS" ("ALM_ID", "INSTALL_ID"); 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 eeb23ef31ad..a7aeef31af0 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 @@ -39,6 +39,7 @@ import org.sonar.db.es.EsQueueDao; import org.sonar.db.event.EventDao; import org.sonar.db.issue.IssueChangeDao; import org.sonar.db.issue.IssueDao; +import org.sonar.db.alm.AlmAppInstallDao; import org.sonar.db.measure.LiveMeasureDao; import org.sonar.db.measure.MeasureDao; import org.sonar.db.measure.custom.CustomMeasureDao; @@ -102,6 +103,7 @@ public class DaoModule extends Module { GroupDao.class, GroupMembershipDao.class, GroupPermissionDao.class, + AlmAppInstallDao.class, InternalPropertiesDao.class, IssueChangeDao.class, IssueDao.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 e7b50e95bf8..99732f30f36 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 @@ -37,6 +37,7 @@ import org.sonar.db.es.EsQueueDao; import org.sonar.db.event.EventDao; import org.sonar.db.issue.IssueChangeDao; import org.sonar.db.issue.IssueDao; +import org.sonar.db.alm.AlmAppInstallDao; import org.sonar.db.measure.LiveMeasureDao; import org.sonar.db.measure.MeasureDao; import org.sonar.db.measure.custom.CustomMeasureDao; @@ -87,6 +88,7 @@ public class DbClient { private final OrganizationMemberDao organizationMemberDao; private final QualityProfileDao qualityProfileDao; private final PropertiesDao propertiesDao; + private final AlmAppInstallDao almAppInstallDao; private final InternalPropertiesDao internalPropertiesDao; private final SnapshotDao snapshotDao; private final ComponentDao componentDao; @@ -144,6 +146,7 @@ public class DbClient { for (Dao dao : daos) { map.put(dao.getClass(), dao); } + almAppInstallDao = getDao(map, AlmAppInstallDao.class); schemaMigrationDao = getDao(map, SchemaMigrationDao.class); authorizationDao = getDao(map, AuthorizationDao.class); organizationDao = getDao(map, OrganizationDao.class); @@ -207,6 +210,10 @@ public class DbClient { return database; } + public AlmAppInstallDao almAppInstallDao() { + return almAppInstallDao; + } + public SchemaMigrationDao schemaMigrationDao() { return schemaMigrationDao; } @@ -422,7 +429,7 @@ public class DbClient { } public WebhookDao webhookDao() { - return webhookDao ; + return webhookDao; } public WebhookDeliveryDao webhookDeliveryDao() { 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 269d7aef70b..bbd97e3fcfa 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 @@ -30,6 +30,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.session.TransactionIsolationLevel; import org.sonar.api.Startable; +import org.sonar.db.alm.AlmAppInstallMapper; import org.sonar.db.ce.CeActivityMapper; import org.sonar.db.ce.CeQueueMapper; import org.sonar.db.ce.CeScannerContextMapper; @@ -198,6 +199,7 @@ public class MyBatis implements Startable { Class[] mappers = { ActiveRuleMapper.class, AnalysisPropertiesMapper.class, + AlmAppInstallMapper.class, AuthorizationMapper.class, BranchMapper.class, CeActivityMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java new file mode 100644 index 00000000000..03bc10efd59 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java @@ -0,0 +1,93 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.alm; + +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; +import org.sonar.api.utils.System2; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang.StringUtils.isNotEmpty; + +/** + * Store instances of installed app in external ALM like GitHub or Bitbucket Cloud. + */ +public class AlmAppInstallDao implements Dao { + + public enum ALM { + BITBUCKETCLOUD, + GITHUB; + + String getId() { + return this.name().toLowerCase(Locale.ENGLISH); + } + } + + private final System2 system2; + private final UuidFactory uuidFactory; + + public AlmAppInstallDao(System2 system2, UuidFactory uuidFactory) { + this.system2 = system2; + this.uuidFactory = uuidFactory; + } + + /** + * @param alm Unique identifier of the ALM, like 'bitbucketcloud' or 'github', can't be null + * @param ownerId ALM specific identifier of the owner of the app, like team or user uuid for Bitbucket Cloud or organization id for Github, can't be null + * @param installId ALM specific identifier of the app installation, can't be null + */ + public void insertOrUpdate(DbSession dbSession, ALM alm, String ownerId, String installId) { + checkAlm(alm); + checkOwnerId(ownerId); + checkArgument(isNotEmpty(installId), "installId can't be null nor empty"); + + AlmAppInstallMapper mapper = getMapper(dbSession); + long now = system2.now(); + + if (mapper.update(alm.getId(), ownerId, installId, now) == 0) { + mapper.insert(uuidFactory.create(), alm.getId(), ownerId, installId, now); + } + } + + public Optional getInstallId(DbSession dbSession, ALM alm, String ownerId) { + checkAlm(alm); + checkOwnerId(ownerId); + + AlmAppInstallMapper mapper = getMapper(dbSession); + return Optional.ofNullable(mapper.selectInstallId(alm.getId(), ownerId)); + } + + private static void checkAlm(@Nullable ALM alm) { + Objects.requireNonNull(alm, "alm can't be null"); + } + + private static void checkOwnerId(@Nullable String ownerId) { + checkArgument(isNotEmpty(ownerId), "ownerId can't be null nor empty"); + } + + private static AlmAppInstallMapper getMapper(DbSession dbSession) { + return dbSession.getMapper(AlmAppInstallMapper.class); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java new file mode 100644 index 00000000000..300890d1fcf --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.alm; + +import javax.annotation.CheckForNull; +import org.apache.ibatis.annotations.Param; + +public interface AlmAppInstallMapper { + + @CheckForNull + String selectInstallId(@Param("almId") String almId, @Param("ownerId") String ownerId); + + void insert(@Param("uuid") String uuid, @Param("almId") String almId, @Param("ownerId") String ownerId, @Param("installId") String installId, @Param("now") long now); + + int update(@Param("almId") String almId, @Param("ownerId") String ownerId, @Param("installId") String installId, @Param("now") long now); + +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/package-info.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/package-info.java new file mode 100644 index 00000000000..52a5bf53dbe --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.db.alm; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml new file mode 100644 index 00000000000..d09f04d46de --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml @@ -0,0 +1,53 @@ + + + + + + + + + INSERT INTO alm_app_installs + ( + uuid, + alm_id, + owner_id, + install_id, + created_at, + updated_at + ) + VALUES ( + #{uuid, jdbcType=VARCHAR}, + #{almId, jdbcType=VARCHAR}, + #{ownerId, jdbcType=VARCHAR}, + #{installId, jdbcType=VARCHAR}, + #{now, jdbcType=BIGINT}, + #{now, jdbcType=BIGINT} + ) + + + + update alm_app_installs set + install_id = #{installId, jdbcType=VARCHAR}, + updated_at = #{now, jdbcType=BIGINT} + where + alm_id = #{almId, jdbcType=VARCHAR} + and owner_id = #{ownerId, jdbcType=VARCHAR} + + + + delete from alm_app_installs + where + alm_id = #{almId, jdbcType=VARCHAR} + and owner_id = #{ownerId, jdbcType=VARCHAR} + + + + 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 89f2e067b9a..213eeb67ccb 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 @@ -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 + 53); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 54); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java new file mode 100644 index 00000000000..c9df59cd509 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java @@ -0,0 +1,278 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.alm; + +import java.util.Map; +import java.util.Objects; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +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.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; +import static org.sonar.db.alm.AlmAppInstallDao.ALM.GITHUB; + +public class AlmAppInstallDaoTest { + + private static final String A_UUID = "abcde1234"; + private static final String A_UUID_2 = "xyz789"; + private static final String EMPTY_STRING = ""; + private static final String A_OWNER = "my_org_id"; + private static final String ANOTHER_OWNER = "another_org"; + private static final long DATE = 1_600_000_000_000L; + private static final long DATE_LATER = 1_700_000_000_000L; + private static final String AN_INSTALL = "some install id"; + private static final String OTHER_INSTALL = "other install id"; + + 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 = mock(UuidFactory.class); + private AlmAppInstallDao underTest = new AlmAppInstallDao(system2, uuidFactory); + + @Test + public void insert_throws_NPE_if_alm_is_null() { + expectAlmNPE(); + + underTest.insertOrUpdate(dbSession, null, A_OWNER, AN_INSTALL); + } + + @Test + public void insert_throws_IAE_if_owner_id_is_null() { + expectOwnerIdNullOrEmptyIAE(); + + underTest.insertOrUpdate(dbSession, GITHUB, null, AN_INSTALL); + } + + @Test + public void insert_throws_IAE_if_owner_id_is_empty() { + expectOwnerIdNullOrEmptyIAE(); + + underTest.insertOrUpdate(dbSession, GITHUB, EMPTY_STRING, AN_INSTALL); + } + + @Test + public void insert_throws_IAE_if_install_id_is_null() { + expectInstallIdNullOrEmptyIAE(); + + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, null); + } + + @Test + public void insert_throws_IAE_if_install_id_is_empty() { + expectInstallIdNullOrEmptyIAE(); + + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, EMPTY_STRING); + } + + @Test + public void insert() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(DATE); + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL); + + assertThatAlmAppInstall(GITHUB, A_OWNER) + .hasInstallId(AN_INSTALL) + .hasCreatedAt(DATE) + .hasUpdatedAt(DATE); + } + + @Test + public void update() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(DATE); + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL); + + when(system2.now()).thenReturn(DATE_LATER); + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, OTHER_INSTALL); + + assertThatAlmAppInstall(GITHUB, A_OWNER) + .hasInstallId(OTHER_INSTALL) + .hasCreatedAt(DATE) + .hasUpdatedAt(DATE_LATER); + } + + @Test + public void putMultiple() { + when(system2.now()).thenReturn(DATE); + when(uuidFactory.create()) + .thenReturn(A_UUID) + .thenReturn(A_UUID_2); + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL); + underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_OWNER, OTHER_INSTALL); + + assertThatAlmAppInstall(GITHUB, A_OWNER) + .hasInstallId(AN_INSTALL) + .hasCreatedAt(DATE) + .hasUpdatedAt(DATE); + + assertThatAlmAppInstall(GITHUB, ANOTHER_OWNER) + .hasInstallId(OTHER_INSTALL) + .hasCreatedAt(DATE) + .hasUpdatedAt(DATE); + } + + @Test + public void getInstallId_throws_NPE_when_alm_is_null() { + expectAlmNPE(); + + underTest.getInstallId(dbSession, null, A_OWNER); + } + + @Test + public void getInstallId_throws_IAE_when_owner_id_is_null() { + expectOwnerIdNullOrEmptyIAE(); + + underTest.getInstallId(dbSession, GITHUB, null); + } + + @Test + public void getInstallId_throws_IAE_when_owner_id_is_empty() { + expectOwnerIdNullOrEmptyIAE(); + + underTest.getInstallId(dbSession, GITHUB, EMPTY_STRING); + } + + @Test + public void getInstallId_returns_empty_optional_when_entry_does_not_exist_in_DB() { + assertThat(underTest.getInstallId(dbSession, GITHUB, A_OWNER)).isEmpty(); + } + + @Test + public void getInstallId_returns_install_id_when_entry_exists() { + when(uuidFactory.create()).thenReturn(A_UUID); + underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL); + + assertThat(underTest.getInstallId(dbSession, GITHUB, A_OWNER)).contains(AN_INSTALL); + } + + private void expectAlmNPE() { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("alm can't be null"); + } + + private void expectOwnerIdNullOrEmptyIAE() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("ownerId can't be null nor empty"); + } + + private void expectInstallIdNullOrEmptyIAE() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("installId can't be null nor empty"); + } + + private AlmAppInstallAssert assertThatAlmAppInstall(AlmAppInstallDao.ALM alm, String ownerId) { + return new AlmAppInstallAssert(dbTester, dbSession, alm, ownerId); + } + + private static class AlmAppInstallAssert extends AbstractAssert { + + private AlmAppInstallAssert(DbTester dbTester, DbSession dbSession, AlmAppInstallDao.ALM alm, String ownerId) { + super(asAlmAppInstall(dbTester, dbSession, alm, ownerId), AlmAppInstallAssert.class); + } + + private static AlmAppInstall asAlmAppInstall(DbTester dbTester, DbSession dbSession, AlmAppInstallDao.ALM alm, String ownerId) { + Map row = dbTester.selectFirst( + dbSession, + "select" + + " install_id as \"installId\", created_at as \"createdAt\", updated_at as \"updatedAt\"" + + " from alm_app_installs" + + " where alm_id='" + alm.getId() + "' and owner_id='" + ownerId + "'"); + return new AlmAppInstall( + (String) row.get("installId"), + (Long) row.get("createdAt"), + (Long) row.get("updatedAt")); + } + + public void doesNotExist() { + isNull(); + } + + public AlmAppInstallAssert hasInstallId(String expected) { + isNotNull(); + + if (!Objects.equals(actual.getInstallId(), expected)) { + failWithMessage("Expected ALM App Install to have column INSTALL_ID to be <%s> but was <%s>", true, actual.getInstallId()); + } + return this; + } + + public AlmAppInstallAssert hasCreatedAt(long expected) { + isNotNull(); + + if (!Objects.equals(actual.getCreatedAt(), expected)) { + failWithMessage("Expected ALM App Install to have column CREATED_AT to be <%s> but was <%s>", expected, actual.getCreatedAt()); + } + + return this; + } + + public AlmAppInstallAssert hasUpdatedAt(long expected) { + isNotNull(); + + if (!Objects.equals(actual.getUpdatedAt(), expected)) { + failWithMessage("Expected ALM App Install to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.getUpdatedAt()); + } + + return this; + } + + } + + private static final class AlmAppInstall { + private final String installId; + private final Long createdAt; + private final Long updatedAt; + + public AlmAppInstall(@Nullable String installId, @Nullable Long createdAt, @Nullable Long updatedAt) { + this.installId = installId; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + @CheckForNull + public String getInstallId() { + return installId; + } + + @CheckForNull + public Long getCreatedAt() { + return createdAt; + } + + @CheckForNull + public Long getUpdatedAt() { + return updatedAt; + } + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTable.java new file mode 100644 index 00000000000..3a3378cfbb0 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTable.java @@ -0,0 +1,109 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v72; + +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.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.MAX_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class CreateAlmAppInstallsTable extends DdlChange { + + private static final String TABLE_NAME = "alm_app_installs"; + + private static final VarcharColumnDef UUID = newVarcharColumnDefBuilder() + .setColumnName("uuid") + .setLimit(UUID_SIZE) + .setIsNullable(false) + .build(); + private static final VarcharColumnDef ALM_ID_COLUMN = newVarcharColumnDefBuilder() + .setColumnName("alm_id") + .setIsNullable(false) + .setLimit(40) + .build(); + private static final VarcharColumnDef OWNER_COLUMN = newVarcharColumnDefBuilder() + .setColumnName("owner_id") + .setIsNullable(false) + .setLimit(MAX_SIZE) + .build(); + private static final VarcharColumnDef INSTALL_COLUMN = newVarcharColumnDefBuilder() + .setColumnName("install_id") + .setIsNullable(false) + .setLimit(MAX_SIZE) + .build(); + private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder() + .setColumnName("created_at") + .setIsNullable(false) + .build(); + private static final BigIntegerColumnDef UPDATED_AT_COLUMN = newBigIntegerColumnDefBuilder() + .setColumnName("updated_at") + .setIsNullable(false) + .build(); + + public CreateAlmAppInstallsTable(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + + if (!tableExists()) { + context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME) + .addPkColumn(UUID) + .addColumn(ALM_ID_COLUMN) + .addColumn(OWNER_COLUMN) + .addColumn(INSTALL_COLUMN) + .addColumn(CREATED_AT_COLUMN) + .addColumn(UPDATED_AT_COLUMN) + .build()); + + context.execute(new CreateIndexBuilder(getDialect()) + .addColumn(ALM_ID_COLUMN) + .addColumn(OWNER_COLUMN) + .setUnique(true) + .setTable(TABLE_NAME) + .setName("alm_app_installs_owner") + .build()); + context.execute(new CreateIndexBuilder(getDialect()) + .addColumn(ALM_ID_COLUMN) + .addColumn(INSTALL_COLUMN) + .setUnique(true) + .setTable(TABLE_NAME) + .setName("alm_app_installs_install") + .build()); + } + } + + private boolean tableExists() throws SQLException { + try (Connection connection = getDatabase().getDataSource().getConnection()) { + return DatabaseUtils.tableExists(TABLE_NAME, connection); + } + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java index cb3eb5ae31e..3613d9144b3 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java @@ -31,6 +31,7 @@ public class DbVersion72 implements DbVersion { .add(2101, "Add HASH_METHOD to table users", AddHashMethodToUsersTable.class) .add(2102, "Populate HASH_METHOD on table users", PopulateHashMethodOnUsers.class) .add(2103, "Add isExternal boolean to rules", AddRuleExternal.class) - ; + .add(2104, "Create ALM_APP_INSTALLS table", CreateAlmAppInstallsTable.class) + ; } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTableTest.java new file mode 100644 index 00000000000..71d8e132e03 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTableTest.java @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v72; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.BIGINT; +import static java.sql.Types.VARCHAR; +import static org.assertj.core.api.Assertions.assertThat; + +public class CreateAlmAppInstallsTableTest { + + private static final String TABLE = "alm_app_installs"; + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(CreateAlmAppInstallsTableTest.class, "empty.sql"); + + private CreateAlmAppInstallsTable underTest = new CreateAlmAppInstallsTable(db.database()); + + @Test + public void creates_table_on_empty_db() throws SQLException { + underTest.execute(); + + checkTable(); + } + + @Test + public void migration_is_reentrant() throws SQLException { + underTest.execute(); + underTest.execute(); + + checkTable(); + } + + private void checkTable() { + assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0); + + db.assertColumnDefinition(TABLE, "uuid", VARCHAR, 40, false); + db.assertPrimaryKey(TABLE, "pk_" + TABLE, "uuid"); + db.assertColumnDefinition(TABLE, "alm_id", VARCHAR, 40, false); + db.assertColumnDefinition(TABLE, "owner_id", VARCHAR, 4000, false); + db.assertColumnDefinition(TABLE, "install_id", VARCHAR, 4000, false); + db.assertColumnDefinition(TABLE, "created_at", BIGINT, null, false); + db.assertColumnDefinition(TABLE, "updated_at", BIGINT, null, false); + + db.assertUniqueIndex(TABLE, "alm_app_installs_owner", "alm_id", "owner_id"); + db.assertUniqueIndex(TABLE, "alm_app_installs_install", "alm_id", "install_id"); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java index 7676fe52168..8e86219a76f 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java @@ -34,7 +34,7 @@ public class DbVersion72Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 4); + verifyMigrationCount(underTest, 5); } } diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTableTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateAlmAppInstallsTableTest/empty.sql new file mode 100644 index 00000000000..e69de29bb2d