From: Benjamin Campomenosi Date: Tue, 30 May 2023 10:07:04 +0000 (+0200) Subject: SONAR-19407 Fix ComponentUuidFactory to load uuid for portfolio from `portfolio`... X-Git-Tag: 10.1.0.73491~172 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9bc77e5b117af186e37aff6e22a0ed6da96d5ae5;p=sonarqube.git SONAR-19407 Fix ComponentUuidFactory to load uuid for portfolio from `portfolio` table --- diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImplIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImplIT.java index 6b3ee0a9d70..6da6104b038 100644 --- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImplIT.java +++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImplIT.java @@ -26,6 +26,8 @@ import org.sonar.ce.task.projectanalysis.analysis.Branch; import org.sonar.db.DbTester; import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; +import org.sonar.db.portfolio.PortfolioDto; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -84,4 +86,28 @@ public class ComponentUuidFactoryImplIT { // uuid is kept in memory for further calls with same key assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey); } + + @Test + public void getOrCreateForKey_whenExistingComponentsInDbForPortfolioAndSubPortfolio_shouldLoadUuidsFromComponentTable() { + ComponentDto portfolioDto = db.components().insertPublicPortfolio("pft1", p -> p.setKey("root_portfolio")); + ComponentDto subView = db.components().insertSubView(portfolioDto, s -> s.setKey("sub_portfolio").setUuid("subPtf1")); + ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), portfolioDto.getKey(), mockedBranch); + + assertThat(underTest.getOrCreateForKey("root_portfolio")).isEqualTo(portfolioDto.uuid()); + assertThat(underTest.getOrCreateForKey("sub_portfolio")).isEqualTo(subView.uuid()); + } + + @Test + public void getOrCreateForKey_whenNoExistingComponentsInDbForPortfolioAndSubPortfolio_shouldLoadUuidFromPortfolioTable() { + PortfolioDto portfolioDto = ComponentTesting.newPortfolioDto("uuid_ptf1", "ptf1", "Portfolio1", null); + db.getDbClient().portfolioDao().insert(db.getSession(), portfolioDto); + PortfolioDto subPortfolio = ComponentTesting.newPortfolioDto("subPtf1", "sub_ptf_1", "portfolio", portfolioDto); + db.getDbClient().portfolioDao().insert(db.getSession(), subPortfolio); + + ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), portfolioDto.getKey()); + + assertThat(underTest.getOrCreateForKey("ptf1")).isEqualTo(portfolioDto.getUuid()); + assertThat(underTest.getOrCreateForKey("sub_ptf_1")).isEqualTo(subPortfolio.getUuid()); + } + } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImpl.java index 9d3e6352744..c2bef0e1f0f 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactoryImpl.java @@ -32,9 +32,19 @@ import org.sonar.db.component.KeyWithUuidDto; public class ComponentUuidFactoryImpl implements ComponentUuidFactory { private final Map uuidsByKey = new HashMap<>(); + /** For the sake of consistency it is important that sub-portfolios have the same uuid as the associated component. + * As sub-portfolio have no component associated with their creation, it is necessary to look search for their uuid. + * see SONAR-19407 for more info + * + * @param dbClient + * @param dbSession + * @param rootKey + */ public ComponentUuidFactoryImpl(DbClient dbClient, DbSession dbSession, String rootKey) { - List keys = dbClient.componentDao().selectUuidsByKeyFromProjectKey(dbSession, rootKey); - keys.forEach(dto -> uuidsByKey.put(dto.key(), dto.uuid())); + List projectKeys = dbClient.componentDao().selectUuidsByKeyFromProjectKey(dbSession, rootKey); + List portFolioKeys = dbClient.portfolioDao().selectUuidsByKey(dbSession, rootKey); + projectKeys.forEach(dto -> uuidsByKey.put(dto.key(), dto.uuid())); + portFolioKeys.forEach(dto -> uuidsByKey.putIfAbsent(dto.key(), dto.uuid())); } public ComponentUuidFactoryImpl(DbClient dbClient, DbSession dbSession, String rootKey, Branch branch) { diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/portfolio/PortfolioDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/portfolio/PortfolioDaoIT.java index 70865740051..c46c401c87f 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/portfolio/PortfolioDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/portfolio/PortfolioDaoIT.java @@ -19,6 +19,8 @@ */ package org.sonar.db.portfolio; +import java.util.Arrays; +import java.util.List; import java.util.Set; import org.junit.Rule; import org.junit.Test; @@ -29,6 +31,8 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.audit.AuditPersister; import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentTesting; +import org.sonar.db.component.KeyWithUuidDto; import org.sonar.db.component.ProjectData; import org.sonar.db.project.ApplicationProjectDto; import org.sonar.db.project.ProjectDto; @@ -138,6 +142,27 @@ public class PortfolioDaoIT { tuple("NAME_name2", "KEY_name2", "name2", "DESCRIPTION_name2", "name2", null, "NONE", null)); } + @Test + public void selectUuidsByKeyFromPortfolioKey_returns_all_uuidByKeyForPortfoliosLinkedToRootKey() { + PortfolioDto portfolio1 = ComponentTesting.newPortfolioDto("uuid1", "ptf1", "Portfolio 1", null); + PortfolioDto subPortfolio1 = ComponentTesting.newPortfolioDto("sub_uuid11", "sub_ptf1", "SubPortfolio 1", portfolio1); + PortfolioDto subSubPortfolio1 = ComponentTesting.newPortfolioDto("sub_uuid12", "sub_sub_ptf1", "SubSubPortfolio 1", portfolio1); + PortfolioDto portfolio2 = ComponentTesting.newPortfolioDto("uuid2", "ptf2", "Portfolio 2", null); + PortfolioDto subPortfolio2 = ComponentTesting.newPortfolioDto("sub_uuid21", "sub_ptd2", "SubPortfolio 2", portfolio2); + Arrays.asList(portfolio1, subPortfolio1, subSubPortfolio1, portfolio2, subPortfolio2) + .forEach(portfolio -> portfolioDao.insert(db.getSession(), portfolio)); + + List keyWithUuidDtos = portfolioDao.selectUuidsByKey(db.getSession(), portfolio1.getKey()); + + KeyWithUuidDto[] expectedKey = { + new KeyWithUuidDto(portfolio1.getKee(), portfolio1.getUuid()), + new KeyWithUuidDto(subPortfolio1.getKee(), subPortfolio1.getUuid()), + new KeyWithUuidDto(subSubPortfolio1.getKee(), subSubPortfolio1.getUuid()) + }; + + assertThat(keyWithUuidDtos).containsExactlyInAnyOrder(expectedKey); + } + @Test public void insert_fails_if_root_is_inconsistent_with_parent() { PortfolioDto portfolio = new PortfolioDto() diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/KeyWithUuidDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/KeyWithUuidDto.java index f1fb7fa36a9..97cd6cb128d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/KeyWithUuidDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/KeyWithUuidDto.java @@ -22,21 +22,9 @@ package org.sonar.db.component; import javax.annotation.concurrent.Immutable; @Immutable -public class KeyWithUuidDto { - - private final String kee; - private final String uuid; - - public KeyWithUuidDto(String kee, String uuid) { - this.kee = kee; - this.uuid = uuid; - } +public record KeyWithUuidDto(String kee, String uuid) { public String key() { return kee; } - - public String uuid() { - return uuid; - } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java index 500701b1388..d2a4b97e99d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java @@ -30,6 +30,7 @@ import org.sonar.db.Dao; import org.sonar.db.DbSession; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.model.ComponentNewValue; +import org.sonar.db.component.KeyWithUuidDto; import org.sonar.db.project.ApplicationProjectDto; import static com.google.common.base.Preconditions.checkArgument; @@ -90,6 +91,10 @@ public class PortfolioDao implements Dao { return mapper(dbSession).selectByUuids(uuids); } + public List selectUuidsByKey(DbSession dbSession, String rootKey) { + return mapper(dbSession).selectUuidsByKey(rootKey); + } + /* * Modify portfolios */ @@ -223,8 +228,8 @@ public class PortfolioDao implements Dao { } public PortfolioProjectDto selectPortfolioProjectOrFail(DbSession dbSession, String portfolioUuid, String projectUuid) { - return Optional.ofNullable(mapper(dbSession).selectPortfolioProject(portfolioUuid, projectUuid)).orElseThrow(() -> - new IllegalArgumentException(format("Project '%s' not selected in portfolio '%s'", projectUuid, portfolioUuid))); + return Optional.ofNullable(mapper(dbSession).selectPortfolioProject(portfolioUuid, projectUuid)) + .orElseThrow(() -> new IllegalArgumentException(format("Project '%s' not selected in portfolio '%s'", projectUuid, portfolioUuid))); } public String addProject(DbSession dbSession, String portfolioUuid, String projectUuid) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java index cc44a51adbb..93b7db68f5a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.ibatis.annotations.Param; +import org.sonar.db.component.KeyWithUuidDto; import org.sonar.db.project.ApplicationProjectDto; public interface PortfolioMapper { @@ -111,4 +112,6 @@ public interface PortfolioMapper { List selectAllReferencesToApplicationsInHierarchy(String rootUuid); List selectRootOfReferencersToAppBranch(@Param("appUuid") String appUuid, @Param("appBranchKey") String appBranchKey); + + List selectUuidsByKey(@Param("rootKey") String rootKey); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 5435920ae11..136b85e5ba5 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -631,8 +631,8 @@ when b_qualifier = 'DIR' THEN 'DIR' when b_qualifier = 'FIL' THEN 'FIL' when b_qualifier = 'UTS' THEN 'FIL' - - else scope + + else scope end ), b_changed = ${_false}, diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/portfolio/PortfolioMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/portfolio/PortfolioMapper.xml index ea2c9dcb735..0264a211032 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/portfolio/PortfolioMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/portfolio/PortfolioMapper.xml @@ -293,6 +293,14 @@ AND target.kee=#{referenceKey,jdbcType=VARCHAR} + + INSERT INTO portfolios ( kee, diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentTesting.java index 2b607e0c894..f1a34854528 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentTesting.java @@ -24,6 +24,7 @@ import javax.annotation.Nullable; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Scopes; import org.sonar.core.util.Uuids; +import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; import static com.google.common.base.Preconditions.checkArgument; @@ -32,6 +33,7 @@ import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME; import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; import static org.sonar.db.component.ComponentDto.formatUuidPathFromParent; import static org.sonar.db.component.ComponentDto.generateBranchKey; +import static org.sonar.db.portfolio.PortfolioDto.SelectionMode.NONE; public class ComponentTesting { @@ -156,6 +158,19 @@ public class ComponentTesting { .setPrivate(false); } + public static PortfolioDto newPortfolioDto(String uuid, String key, String name, @Nullable PortfolioDto parent) { + return new PortfolioDto() + .setUuid(uuid) + .setKey(key) + .setParentUuid(parent == null ? null : parent.getUuid()) + .setRootUuid(parent == null ? uuid : parent.getRootUuid()) + .setSelectionMode(NONE.name()) + .setCreatedAt(1L) + .setUpdatedAt(1L) + .setPrivate(false) + .setName(name); + } + public static ComponentDto newApplication() { return newPortfolio(Uuids.createFast()).setQualifier(Qualifiers.APP); }