"rule_repositories",
"scanner_analysis_cache",
"schema_migrations",
+ "scim_groups",
"scim_users",
"session_tokens",
"snapshots",
import org.sonar.db.rule.RuleRepositoryDao;
import org.sonar.db.scannercache.ScannerAnalysisCacheDao;
import org.sonar.db.schemamigration.SchemaMigrationDao;
+import org.sonar.db.scim.ScimGroupDao;
import org.sonar.db.scim.ScimUserDao;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.user.GroupDao;
SamlMessageIdDao.class,
ScannerAnalysisCacheDao.class,
SchemaMigrationDao.class,
+ ScimGroupDao.class,
ScimUserDao.class,
SnapshotDao.class,
SessionTokensDao.class,
import org.sonar.db.rule.RuleRepositoryDao;
import org.sonar.db.scannercache.ScannerAnalysisCacheDao;
import org.sonar.db.schemamigration.SchemaMigrationDao;
+import org.sonar.db.scim.ScimGroupDao;
import org.sonar.db.scim.ScimUserDao;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.user.GroupDao;
private final ProjectBadgeTokenDao projectBadgeTokenDao;
private final ScannerAnalysisCacheDao scannerAnalysisCacheDao;
private final ScimUserDao scimUserDao;
+ private final ScimGroupDao scimGroupDao;
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) {
this.database = database;
applicationProjectsDao = getDao(map, ApplicationProjectsDao.class);
scannerAnalysisCacheDao = getDao(map, ScannerAnalysisCacheDao.class);
scimUserDao = getDao(map, ScimUserDao.class);
+ scimGroupDao = getDao(map, ScimGroupDao.class);
}
public DbSession openSession(boolean batch) {
public ScimUserDao scimUserDao() {
return scimUserDao;
}
+
+ public ScimGroupDao scimGroupDao() {
+ return scimGroupDao;
+ }
}
+
import org.sonar.db.scannercache.ScannerAnalysisCacheMapper;
import org.sonar.db.schemamigration.SchemaMigrationDto;
import org.sonar.db.schemamigration.SchemaMigrationMapper;
+import org.sonar.db.scim.ScimGroupMapper;
import org.sonar.db.scim.ScimUserMapper;
import org.sonar.db.source.FileSourceMapper;
import org.sonar.db.user.GroupDto;
SamlMessageIdMapper.class,
ScannerAnalysisCacheMapper.class,
SchemaMigrationMapper.class,
+ ScimGroupMapper.class,
ScimUserMapper.class,
SessionTokenMapper.class,
SnapshotMapper.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scim;
+
+import java.util.List;
+import java.util.Optional;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+public class ScimGroupDao implements Dao {
+ private final UuidFactory uuidFactory;
+
+ public ScimGroupDao(UuidFactory uuidFactory) {
+ this.uuidFactory = uuidFactory;
+ }
+
+ public List<ScimGroupDto> findAll(DbSession dbSession) {
+ return mapper(dbSession).findAll();
+ }
+
+ public Optional<ScimGroupDto> findByScimUuid(DbSession dbSession, String scimGroupUuid) {
+ return Optional.ofNullable(mapper(dbSession).findByScimUuid(scimGroupUuid));
+ }
+
+ public Optional<ScimGroupDto> findByGroupUuid(DbSession dbSession, String groupUuid) {
+ return Optional.ofNullable(mapper(dbSession).findByGroupUuid(groupUuid));
+ }
+
+ public ScimGroupDto enableScimForGroup(DbSession dbSession, String groupUuid) {
+ ScimGroupDto scimGroupDto = new ScimGroupDto(uuidFactory.create(), groupUuid);
+ mapper(dbSession).insert(scimGroupDto);
+ return scimGroupDto;
+ }
+
+ public void deleteByGroupUuid(DbSession dbSession, String groupUuid) {
+ mapper(dbSession).deleteByGroupUuid(groupUuid);
+ }
+
+ public void deleteByScimUuid(DbSession dbSession, String scimUuid) {
+ mapper(dbSession).deleteByScimUuid(scimUuid);
+ }
+
+ private static ScimGroupMapper mapper(DbSession session) {
+ return session.getMapper(ScimGroupMapper.class);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scim;
+
+public class ScimGroupDto {
+
+ private final String scimGroupUuid;
+ private final String groupUuid;
+
+ public ScimGroupDto(String scimGroupUuid, String groupUuid) {
+ this.scimGroupUuid = scimGroupUuid;
+ this.groupUuid = groupUuid;
+ }
+
+ public String getScimGroupUuid() {
+ return scimGroupUuid;
+ }
+
+ public String getGroupUuid() {
+ return groupUuid;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scim;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+
+public interface ScimGroupMapper {
+
+ List<ScimGroupDto> findAll();
+
+ @CheckForNull
+ ScimGroupDto findByScimUuid(@Param("scimGroupUuid") String scimGroupUuid);
+
+ @CheckForNull
+ ScimGroupDto findByGroupUuid(@Param("groupUuid") String groupUuid);
+
+ void insert(@Param("scimGroupDto") ScimGroupDto scimGroupDto);
+
+ void deleteByGroupUuid(@Param("groupUuid") String groupUuid);
+
+ void deleteByScimUuid(@Param("scimUuid") String scimUuid);
+}
--- /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.scim.ScimGroupMapper">
+
+ <sql id="scimGroupsColumns">
+ scim_uuid as scimGroupUuid,
+ group_uuid as groupUuid
+ </sql>
+
+ <select id="findAll" resultType="org.sonar.db.scim.ScimGroupDto">
+ select
+ <include refid="scimGroupsColumns"/>
+ from scim_groups
+ </select>
+
+ <select id="findByScimUuid" parameterType="String" resultType="org.sonar.db.scim.ScimGroupDto">
+ select
+ <include refid="scimGroupsColumns"/>
+ from scim_groups
+ where
+ scim_uuid = #{scimGroupUuid,jdbcType=VARCHAR}
+ </select>
+
+ <select id="findByGroupUuid" parameterType="String" resultType="org.sonar.db.scim.ScimGroupDto">
+ select
+ <include refid="scimGroupsColumns"/>
+ from scim_groups
+ where
+ group_uuid = #{groupUuid,jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="map" useGeneratedKeys="false">
+ insert into scim_groups (
+ scim_uuid,
+ group_uuid
+ ) values (
+ #{scimGroupDto.scimGroupUuid,jdbcType=VARCHAR},
+ #{scimGroupDto.groupUuid,jdbcType=VARCHAR}
+ )
+ </insert>
+
+ <delete id="deleteByGroupUuid" parameterType="String">
+ delete from scim_groups where group_uuid = #{groupUuid, jdbcType=VARCHAR}
+ </delete>
+
+ <delete id="deleteByScimUuid" parameterType="String">
+ delete from scim_groups where scim_uuid = #{scimUuid, jdbcType=VARCHAR}
+ </delete>
+
+</mapper>
+
);
ALTER TABLE "SCANNER_ANALYSIS_CACHE" ADD CONSTRAINT "PK_SCANNER_ANALYSIS_CACHE" PRIMARY KEY("BRANCH_UUID");
+CREATE TABLE "SCIM_GROUPS"(
+ "SCIM_UUID" CHARACTER VARYING(40) NOT NULL,
+ "GROUP_UUID" CHARACTER VARYING(40) NOT NULL
+);
+ALTER TABLE "SCIM_GROUPS" ADD CONSTRAINT "PK_SCIM_GROUPS" PRIMARY KEY("SCIM_UUID");
+CREATE UNIQUE INDEX "UNIQ_SCIM_GROUP_UUID" ON "SCIM_GROUPS"("GROUP_UUID" NULLS FIRST);
+
CREATE TABLE "SCIM_USERS"(
"SCIM_UUID" CHARACTER VARYING(40) NOT NULL,
"USER_UUID" CHARACTER VARYING(40) NOT NULL
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scim;
+
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.db.DbTester;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Fail.fail;
+import static org.assertj.core.groups.Tuple.tuple;
+
+@RunWith(DataProviderRunner.class)
+public class ScimGroupDaoTest {
+ @Rule
+ public DbTester db = DbTester.create();
+ private final ScimGroupDao scimGroupDao = db.getDbClient().scimGroupDao();
+
+ @Test
+ public void findAll_ifNoData_returnsEmptyList() {
+ assertThat(scimGroupDao.findAll(db.getSession())).isEmpty();
+ }
+
+ @Test
+ public void findAll_returnsAllEntries() {
+ ScimGroupDto scimGroup1 = insertScimGroup();
+ ScimGroupDto scimGroup2 = insertScimGroup();
+
+ List<ScimGroupDto> underTest = scimGroupDao.findAll(db.getSession());
+
+ assertThat(underTest).hasSize(2)
+ .extracting(ScimGroupDto::getGroupUuid, ScimGroupDto::getScimGroupUuid)
+ .containsExactlyInAnyOrder(
+ tuple(scimGroup1.getGroupUuid(), scimGroup1.getScimGroupUuid()),
+ tuple(scimGroup2.getGroupUuid(), scimGroup2.getScimGroupUuid())
+ );
+ }
+
+ @Test
+ public void findByScimUuid_whenScimUuidNotFound_shouldReturnEmptyOptional() {
+ assertThat(scimGroupDao.findByScimUuid(db.getSession(), "unknownId")).isEmpty();
+ }
+
+ @Test
+ public void findByScimUuid_whenScimUuidFound_shouldReturnDto() {
+ ScimGroupDto scimGroupDto = insertScimGroup();
+ insertScimGroup();
+
+ ScimGroupDto underTest = scimGroupDao.findByScimUuid(db.getSession(), scimGroupDto.getScimGroupUuid())
+ .orElseGet(() -> fail("Group not found"));
+
+ assertThat(underTest.getScimGroupUuid()).isEqualTo(scimGroupDto.getScimGroupUuid());
+ assertThat(underTest.getGroupUuid()).isEqualTo(scimGroupDto.getGroupUuid());
+ }
+
+ @Test
+ public void findByGroupUuid_whenScimUuidNotFound_shouldReturnEmptyOptional() {
+ assertThat(scimGroupDao.findByGroupUuid(db.getSession(), "unknownId")).isEmpty();
+ }
+
+ @Test
+ public void findByGroupUuid_whenScimUuidFound_shouldReturnDto() {
+ ScimGroupDto scimGroupDto = insertScimGroup();
+ insertScimGroup();
+
+ ScimGroupDto underTest = scimGroupDao.findByGroupUuid(db.getSession(), scimGroupDto.getGroupUuid())
+ .orElseGet(() -> fail("Group not found"));
+
+ assertThat(underTest.getScimGroupUuid()).isEqualTo(scimGroupDto.getScimGroupUuid());
+ assertThat(underTest.getGroupUuid()).isEqualTo(scimGroupDto.getGroupUuid());
+ }
+
+ @Test
+ public void enableScimForGroup_addsGroupToScimGroups() {
+ ScimGroupDto underTest = scimGroupDao.enableScimForGroup(db.getSession(), "sqGroup1");
+
+ assertThat(underTest.getScimGroupUuid()).isNotBlank();
+ ScimGroupDto scimGroupDto = scimGroupDao.findByScimUuid(db.getSession(), underTest.getScimGroupUuid()).orElseThrow();
+ assertThat(underTest.getScimGroupUuid()).isEqualTo(scimGroupDto.getScimGroupUuid());
+ assertThat(underTest.getGroupUuid()).isEqualTo(scimGroupDto.getGroupUuid());
+ }
+
+ @Test
+ public void deleteByGroupUuid_shouldDeleteScimGroup() {
+ ScimGroupDto scimGroupDto = insertScimGroup();
+
+ scimGroupDao.deleteByGroupUuid(db.getSession(), scimGroupDto.getGroupUuid());
+
+ assertThat(scimGroupDao.findAll(db.getSession())).isEmpty();
+ }
+
+ @Test
+ public void deleteByScimUuid_shouldDeleteScimGroup() {
+ ScimGroupDto scimGroupDto1 = insertScimGroup();
+ ScimGroupDto scimGroupDto2 = insertScimGroup();
+
+ scimGroupDao.deleteByScimUuid(db.getSession(), scimGroupDto1.getScimGroupUuid());
+
+ List<ScimGroupDto> remainingGroups = scimGroupDao.findAll(db.getSession());
+ assertThat(remainingGroups).hasSize(1);
+
+ ScimGroupDto remainingGroup = remainingGroups.get(0);
+ assertThat(remainingGroup.getScimGroupUuid()).isEqualTo(scimGroupDto2.getScimGroupUuid());
+ assertThat(remainingGroup.getGroupUuid()).isEqualTo(scimGroupDto2.getGroupUuid());
+ }
+
+ @Test
+ public void deleteFromGroupUuid_shouldNotFail_whenNoGroup() {
+ assertThatCode(() -> scimGroupDao.deleteByGroupUuid(db.getSession(), randomAlphanumeric(6))).doesNotThrowAnyException();
+ }
+
+ private ScimGroupDto insertScimGroup() {
+ return scimGroupDao.enableScimForGroup(db.getSession(), randomAlphanumeric(40));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;
+import org.sonar.server.platform.db.migration.step.CreateTableChange;
+
+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 CreateScimGroupsTable extends CreateTableChange {
+ static final String TABLE_NAME = "scim_groups";
+
+ public CreateScimGroupsTable(Database db) {
+ super(db, TABLE_NAME);
+ }
+
+ @Override
+ public void execute(Context context, String tableName) throws SQLException {
+ context.execute(new CreateTableBuilder(getDialect(), tableName)
+ .addPkColumn(newVarcharColumnDefBuilder().setColumnName("scim_uuid").setIsNullable(false).setLimit(UUID_SIZE).build())
+ .addColumn(newVarcharColumnDefBuilder().setColumnName("group_uuid").setIsNullable(false).setLimit(UUID_SIZE).build())
+ .build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import com.google.common.annotations.VisibleForTesting;
+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.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.version.v100.CreateScimGroupsTable.TABLE_NAME;
+
+public class CreateUniqueIndexForScimGroupsUuid extends DdlChange {
+
+ @VisibleForTesting
+ static final String COLUMN_NAME = "group_uuid";
+
+ @VisibleForTesting
+ static final String INDEX_NAME = "uniq_scim_group_uuid";
+
+ public CreateUniqueIndexForScimGroupsUuid(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ createUserUuidUniqueIndex(context, connection);
+ }
+ }
+
+ private static void createUserUuidUniqueIndex(Context context, Connection connection) {
+ if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
+ context.execute(new CreateIndexBuilder()
+ .setTable(TABLE_NAME)
+ .setName(INDEX_NAME)
+ .addColumn(COLUMN_NAME)
+ .setUnique(true)
+ .build());
+ }
+ }
+}
.add(10_0_007, "Drop column 'root_uuid' in the 'Components' table", DropRootUuidInComponents.class)
.add(10_0_008, "Update value of 'user_local' in the 'users' table", UpdateUserLocalValueInUsers.class)
.add(10_0_009, "Make column 'user_local' not nullable in the 'users' table", MakeColumnUserLocalNotNullableInUsers.class)
+ .add(10_0_010, "Create 'scim_groups' table", CreateScimGroupsTable.class)
+ .add(10_0_011, "Create unique index on scim_groups.group_uuid", CreateUniqueIndexForScimGroupsUuid.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.version.v100.CreateScimGroupsTable.TABLE_NAME;
+
+public class CreateScimGroupsTableTest {
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createEmpty();
+
+ private final DdlChange underTest = new CreateScimGroupsTable(db.database());
+
+ @Test
+ public void migration_should_create_a_table() throws SQLException {
+ db.assertTableDoesNotExist(TABLE_NAME);
+
+ underTest.execute();
+
+ db.assertTableExists(TABLE_NAME);
+ db.assertColumnDefinition(TABLE_NAME, "scim_uuid", Types.VARCHAR, UUID_SIZE, false);
+ db.assertColumnDefinition(TABLE_NAME, "group_uuid", Types.VARCHAR, UUID_SIZE, false);
+ db.assertPrimaryKey(TABLE_NAME, "pk_scim_groups", "scim_uuid");
+ }
+
+ @Test
+ public void migration_should_be_reentrant() throws SQLException {
+ db.assertTableDoesNotExist(TABLE_NAME);
+
+ underTest.execute();
+ // re-entrant
+ underTest.execute();
+
+ db.assertTableExists(TABLE_NAME);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.version.v100.CreateScimGroupsTable.TABLE_NAME;
+import static org.sonar.server.platform.db.migration.version.v100.CreateUniqueIndexForScimGroupsUuid.COLUMN_NAME;
+import static org.sonar.server.platform.db.migration.version.v100.CreateUniqueIndexForScimGroupsUuid.INDEX_NAME;
+
+public class CreateUniqueIndexForScimGroupsUuidTest {
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(CreateUniqueIndexForScimGroupsUuidTest.class, "schema.sql");
+
+ private final DdlChange underTest = new CreateUniqueIndexForScimGroupsUuid(db.database());
+
+ @Test
+ public void migration_should_create_index() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+
+ underTest.execute();
+
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME);
+ }
+
+ @Test
+ public void migration_should_be_reentrant() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+
+ underTest.execute();
+ underTest.execute();
+
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME);
+ }
+}
--- /dev/null
+CREATE TABLE "SCIM_GROUPS"(
+ "SCIM_UUID" CHARACTER VARYING(40) NOT NULL,
+ "GROUP_UUID" CHARACTER VARYING(40) NOT NULL
+);
+ALTER TABLE "SCIM_GROUPS" ADD CONSTRAINT "PK_SCIM_GROUPS" PRIMARY KEY("SCIM_UUID");