From 0b24d4b1fa9066719f974624545ef447a6698d2d Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 28 Jun 2023 08:04:11 -0500 Subject: [PATCH] SONAR-19558 Refactor Project Indexers --- .../step/IndexAnalysisStepIT.java | 19 +- .../purge/IndexPurgeListener.java | 10 +- .../step/IndexAnalysisStep.java | 14 +- .../purge/IndexPurgeListenerTest.java | 8 +- .../container/ComputeEngineContainerImpl.java | 8 +- .../java/org/sonar/db/entity/EntityDaoIT.java | 29 +-- .../java/org/sonar/db/entity/EntityDao.java | 4 +- .../org/sonar/db/entity/EntityMapper.java | 2 +- .../main/java/org/sonar/db/user/UserDao.java | 4 - .../org/sonar/db/entity/EntityMapper.xml | 12 +- ...IT.java => EntityDefinitionIndexerIT.java} | 58 +++--- .../server/issue/index/IssueIndexerIT.java | 185 ++++++++++-------- .../index/ProjectMeasuresIndexerIT.java | 33 ++-- ...exer.java => EntityDefinitionIndexer.java} | 61 +++--- .../org/sonar/server/es/AnalysisIndexer.java | 43 ++++ ...ProjectIndexer.java => BranchIndexer.java} | 25 +-- .../org/sonar/server/es/EventIndexer.java} | 31 ++- .../java/org/sonar/server/es/Indexers.java | 81 ++++++++ .../org/sonar/server/es/IndexersImpl.java | 76 +++++++ .../org/sonar/server/es/ProjectIndexers.java | 64 ------ .../sonar/server/es/ProjectIndexersImpl.java | 48 ----- .../org/sonar/server/es/ResilientIndexer.java | 4 +- .../org/sonar/server/es/StartupIndexer.java | 4 +- .../server/issue/index/IssueIndexer.java | 129 ++++++++---- .../measure/index/ProjectMeasuresIndexer.java | 66 ++++--- .../permission/index/AuthorizationDoc.java | 6 +- .../permission/index/AuthorizationScope.java | 12 +- .../index/NeedAuthorizationIndexer.java | 4 +- .../org/sonar/server/es/IndexersImplTest.java | 103 ++++++++++ .../server/es/ProjectIndexersImplTest.java | 55 ------ .../sonar/server/es/ProjectIndexersTest.java | 120 ------------ .../sonar/server/es/StartupIndexerTest.java | 8 +- .../index/AuthorizationDocTest.java | 4 +- .../org/sonar/server/es/TestIndexers.java | 65 ++++++ .../issue/index/AsyncIssueIndexingImpl.java | 1 - .../permission/index/PermissionIndexer.java | 36 ++-- .../index/ComponentIndexSearchTest.java | 2 +- .../component/index/ComponentIndexTest.java | 2 +- .../server/permission/index/FooIndexer.java | 30 +-- .../index/PermissionIndexerTest.java | 32 ++- .../ws/azure/ImportAzureProjectActionIT.java | 4 +- .../ImportBitbucketCloudRepoActionIT.java | 4 +- .../ImportBitbucketServerProjectActionIT.java | 5 +- .../github/ImportGithubProjectActionIT.java | 4 +- .../gitlab/ImportGitLabProjectActionIT.java | 8 +- .../server/branch/ws/DeleteActionIT.java | 6 +- .../ce/queue/BranchReportSubmitterIT.java | 4 +- .../server/ce/queue/ReportSubmitterIT.java | 4 +- .../component/ComponentCleanerServiceIT.java | 71 +++---- .../ComponentServiceUpdateKeyIT.java | 11 +- .../server/component/ComponentUpdaterIT.java | 36 +--- .../server/component/ws/SearchActionIT.java | 5 +- .../component/ws/SearchProjectsActionIT.java | 2 +- .../component/ws/SuggestionsActionIT.java | 52 ++--- .../live/LiveMeasureComputerImplIT.java | 4 +- .../PermissionTemplateServiceIT.java | 8 +- .../permission/ws/BasePermissionWsIT.java | 4 +- .../ws/template/ApplyTemplateActionIT.java | 4 +- .../template/BulkApplyTemplateActionIT.java | 8 +- .../server/project/ws/BulkDeleteActionIT.java | 6 +- .../server/project/ws/CreateActionIT.java | 13 +- .../server/project/ws/DeleteActionIT.java | 26 +-- .../server/project/ws/UpdateKeyActionIT.java | 8 +- .../project/ws/UpdateVisibilityActionIT.java | 10 +- .../server/projecttag/ws/SetActionIT.java | 18 +- .../ws/azure/ImportAzureProjectAction.java | 6 +- .../ImportBitbucketCloudRepoAction.java | 5 +- .../ImportBitbucketServerProjectAction.java | 5 +- .../ws/github/ImportGithubProjectAction.java | 5 +- .../ws/gitlab/ImportGitLabProjectAction.java | 5 +- .../server/ce/queue/ReportSubmitter.java | 16 +- .../component/ComponentCleanerService.java | 33 ++-- .../component/ComponentCreationData.java | 3 +- .../server/component/ComponentService.java | 12 +- .../server/component/ComponentUpdater.java | 65 +++--- .../sonar/server/issue/ws/AuthorsAction.java | 17 +- .../measure/live/LiveMeasureComputerImpl.java | 14 +- .../permission/PermissionTemplateService.java | 12 +- .../server/permission/PermissionUpdater.java | 11 +- .../server/project/ws/BulkDeleteAction.java | 5 +- .../sonar/server/project/ws/CreateAction.java | 27 +-- .../sonar/server/project/ws/DeleteAction.java | 2 +- .../project/ws/UpdateVisibilityAction.java | 12 +- .../server/projecttag/TagsWsSupport.java | 12 +- .../platformlevel/PlatformLevel4.java | 8 +- 85 files changed, 1059 insertions(+), 1039 deletions(-) rename server/sonar-server-common/src/it/java/org/sonar/server/component/index/{ComponentIndexerIT.java => EntityDefinitionIndexerIT.java} (83%) rename server/sonar-server-common/src/main/java/org/sonar/server/component/index/{ComponentIndexer.java => EntityDefinitionIndexer.java} (79%) create mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/es/AnalysisIndexer.java rename server/sonar-server-common/src/main/java/org/sonar/server/es/{ProjectIndexer.java => BranchIndexer.java} (58%) rename server/sonar-server-common/src/{testFixtures/java/org/sonar/server/es/TestProjectIndexers.java => main/java/org/sonar/server/es/EventIndexer.java} (54%) create mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/es/Indexers.java create mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/es/IndexersImpl.java delete mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java delete mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java create mode 100644 server/sonar-server-common/src/test/java/org/sonar/server/es/IndexersImplTest.java delete mode 100644 server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java delete mode 100644 server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java create mode 100644 server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestIndexers.java diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStepIT.java index 342ffe9c14c..dd7ba03a873 100644 --- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStepIT.java +++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStepIT.java @@ -34,7 +34,7 @@ import org.sonar.ce.task.step.TestComputationStepContext; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.BranchDao; -import org.sonar.server.es.ProjectIndexer; +import org.sonar.server.es.AnalysisIndexer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -53,16 +53,11 @@ public class IndexAnalysisStepIT extends BaseStepTest { public BatchReportReaderRule reportReader = new BatchReportReaderRule(); private final DbClient dbClient = mock(DbClient.class); - private final FileStatuses fileStatuses = mock(FileStatuses.class); - - private final ProjectIndexer projectIndexer = mock(ProjectIndexer.class); - + private final AnalysisIndexer analysisIndexer = mock(AnalysisIndexer.class); private final DbSession dbSession = mock(DbSession.class); - private final BranchDao branchDao = mock(BranchDao.class); - - private final IndexAnalysisStep underTest = new IndexAnalysisStep(treeRootHolder, fileStatuses, dbClient, projectIndexer); + private final IndexAnalysisStep underTest = new IndexAnalysisStep(treeRootHolder, fileStatuses, dbClient, analysisIndexer); private TestComputationStepContext testComputationStepContext; @@ -81,7 +76,7 @@ public class IndexAnalysisStepIT extends BaseStepTest { underTest.execute(testComputationStepContext); - verify(projectIndexer).indexOnAnalysis(PROJECT_UUID, Set.of()); + verify(analysisIndexer).indexOnAnalysis(PROJECT_UUID, Set.of()); } @Test @@ -91,7 +86,7 @@ public class IndexAnalysisStepIT extends BaseStepTest { underTest.execute(testComputationStepContext); - verify(projectIndexer).indexOnAnalysis(PROJECT_UUID, Set.of()); + verify(analysisIndexer).indexOnAnalysis(PROJECT_UUID, Set.of()); } @Test @@ -103,7 +98,7 @@ public class IndexAnalysisStepIT extends BaseStepTest { underTest.execute(testComputationStepContext); - verify(projectIndexer).indexOnAnalysis(PROJECT_UUID, anyUuids); + verify(analysisIndexer).indexOnAnalysis(PROJECT_UUID, anyUuids); } @Test @@ -114,7 +109,7 @@ public class IndexAnalysisStepIT extends BaseStepTest { underTest.execute(testComputationStepContext); - verify(projectIndexer).indexOnAnalysis(PROJECT_UUID); + verify(analysisIndexer).indexOnAnalysis(PROJECT_UUID); } @Override diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java index d0dfa266685..a77b11cf80f 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java @@ -23,22 +23,22 @@ import java.util.Collection; import java.util.List; import org.sonar.api.server.ServerSide; import org.sonar.db.purge.PurgeListener; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.issue.index.IssueIndexer; @ServerSide public class IndexPurgeListener implements PurgeListener { private final IssueIndexer issueIndexer; - private final ComponentIndexer componentIndexer; + private final EntityDefinitionIndexer entityDefinitionIndexer; - public IndexPurgeListener(IssueIndexer issueIndexer, ComponentIndexer componentIndexer) { + public IndexPurgeListener(IssueIndexer issueIndexer, EntityDefinitionIndexer entityDefinitionIndexer) { this.issueIndexer = issueIndexer; - this.componentIndexer = componentIndexer; + this.entityDefinitionIndexer = entityDefinitionIndexer; } @Override public void onComponentsDisabling(String projectUuid, Collection disabledComponentUuids) { - componentIndexer.delete(projectUuid, disabledComponentUuids); + entityDefinitionIndexer.delete(projectUuid, disabledComponentUuids); } @Override diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStep.java index fc47c64a739..7ede8d9dd03 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStep.java @@ -28,7 +28,7 @@ import org.sonar.ce.task.projectanalysis.component.TreeRootHolder; import org.sonar.ce.task.step.ComputationStep; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.server.es.ProjectIndexer; +import org.sonar.server.es.AnalysisIndexer; public class IndexAnalysisStep implements ComputationStep { @@ -36,10 +36,10 @@ public class IndexAnalysisStep implements ComputationStep { private final TreeRootHolder treeRootHolder; private final FileStatuses fileStatuses; - private final ProjectIndexer[] indexers; + private final AnalysisIndexer[] indexers; private final DbClient dbClient; - public IndexAnalysisStep(TreeRootHolder treeRootHolder, FileStatuses fileStatuses, DbClient dbClient, ProjectIndexer... indexers) { + public IndexAnalysisStep(TreeRootHolder treeRootHolder, FileStatuses fileStatuses, DbClient dbClient, AnalysisIndexer... indexers) { this.treeRootHolder = treeRootHolder; this.fileStatuses = fileStatuses; this.indexers = indexers; @@ -49,14 +49,14 @@ public class IndexAnalysisStep implements ComputationStep { @Override public void execute(ComputationStep.Context context) { String branchUuid = treeRootHolder.getRoot().getUuid(); - Consumer projectIndexerConsumer = getProjectIndexerConsumer(branchUuid); - for (ProjectIndexer indexer : indexers) { + Consumer analysisIndexerConsumer = getAnalysisIndexerConsumer(branchUuid); + for (AnalysisIndexer indexer : indexers) { LOGGER.debug("Call {}", indexer); - projectIndexerConsumer.accept(indexer); + analysisIndexerConsumer.accept(indexer); } } - private Consumer getProjectIndexerConsumer(String branchUuid) { + private Consumer getAnalysisIndexerConsumer(String branchUuid) { Set fileUuidsMarkedAsUnchanged = fileStatuses.getFileUuidsMarkedAsUnchanged(); return isBranchNeedIssueSync(branchUuid) ? (indexer -> indexer.indexOnAnalysis(branchUuid)) diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java index 556387bf0f5..a5d9ad2e54e 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java @@ -21,7 +21,7 @@ package org.sonar.ce.task.projectanalysis.purge; import java.util.List; import org.junit.Test; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.issue.index.IssueIndexer; import static java.util.Arrays.asList; @@ -32,9 +32,9 @@ import static org.mockito.Mockito.verify; public class IndexPurgeListenerTest { private IssueIndexer issueIndexer = mock(IssueIndexer.class); - private ComponentIndexer componentIndexer = mock(ComponentIndexer.class); + private EntityDefinitionIndexer entityDefinitionIndexer = mock(EntityDefinitionIndexer.class); - private IndexPurgeListener underTest = new IndexPurgeListener(issueIndexer, componentIndexer); + private IndexPurgeListener underTest = new IndexPurgeListener(issueIndexer, entityDefinitionIndexer); @Test public void test_onComponentDisabling() { @@ -43,7 +43,7 @@ public class IndexPurgeListenerTest { List uuids = singletonList(uuid); underTest.onComponentsDisabling(projectUuid, uuids); - verify(componentIndexer).delete(projectUuid, uuids); + verify(entityDefinitionIndexer).delete(projectUuid, uuids); } @Test diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 182942cd836..0716d8aa40a 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -89,10 +89,10 @@ import org.sonar.db.purge.PurgeProfiler; import org.sonar.process.NetworkUtilsImpl; import org.sonar.process.Props; import org.sonar.process.logging.LogbackHelper; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.config.ConfigurationProvider; import org.sonar.server.es.EsModule; -import org.sonar.server.es.ProjectIndexersImpl; +import org.sonar.server.es.IndexersImpl; import org.sonar.server.extension.CoreExtensionBootstraper; import org.sonar.server.extension.CoreExtensionStopper; import org.sonar.server.favorite.FavoriteUpdater; @@ -381,11 +381,11 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { // components, FavoriteUpdater.class, - ProjectIndexersImpl.class, + IndexersImpl.class, QGChangeNotificationHandler.class, QGChangeNotificationHandler.newMetadata(), ProjectMeasuresIndexer.class, - ComponentIndexer.class, + EntityDefinitionIndexer.class, // views ViewIndexer.class, diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java index 3f6276ac35c..02f74e5c0c5 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java @@ -162,36 +162,9 @@ public class EntityDaoIT { List result = new LinkedList<>(); ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); - entityDao.scrollForIndexing(db.getSession(), null, handler); + entityDao.scrollForIndexing(db.getSession(), handler); assertThat(result).extracting(EntityDto::getUuid) .containsOnly(project.projectUuid(), application.projectUuid(), portfolio.getUuid()); } - - @Test - public void scrollEntitiesForIndexing_whenEntityUuidSpecified_shouldReturnSpecificEntity() { - ProjectData application = db.components().insertPrivateApplication(); - ProjectData project = db.components().insertPrivateProject(); - PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); - - List result = new LinkedList<>(); - ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); - entityDao.scrollForIndexing(db.getSession(), project.projectUuid(), handler); - - assertThat(result).extracting(EntityDto::getUuid) - .containsOnly(project.projectUuid()); - } - - @Test - public void scrollEntitiesForIndexing_whenNonExistingUuidSpecified_shouldReturnEmpty() { - ProjectData application = db.components().insertPrivateApplication(); - ProjectData project = db.components().insertPrivateProject(); - PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); - - List result = new LinkedList<>(); - ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); - entityDao.scrollForIndexing(db.getSession(), "unknown", handler); - - assertThat(result).isEmpty(); - } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java index d61cdcaf4fd..69a1830266f 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java @@ -58,8 +58,8 @@ public class EntityDao implements Dao { return Optional.ofNullable(mapper(dbSession).selectByComponentUuid(componentUuid)); } - public void scrollForIndexing(DbSession session, @Nullable String entityUuid, ResultHandler handler) { - mapper(session).scrollForIndexing(entityUuid, handler); + public void scrollForIndexing(DbSession session, ResultHandler handler) { + mapper(session).scrollForIndexing(handler); } private static EntityMapper mapper(DbSession session) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java index 1131ef12ad4..1b704d290ab 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java @@ -40,5 +40,5 @@ public interface EntityMapper { List selectByKeys(@Param("keys") Collection keys); - void scrollForIndexing(@Param("entityUuid") @Nullable String entityUuid, ResultHandler handler); + void scrollForIndexing(ResultHandler handler); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java index bdd569bb24b..adda1d6215c 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java @@ -171,10 +171,6 @@ public class UserDao implements Dao { mapper(dbSession).clearHomepages("PROJECT", entityDto.getUuid(), system2.now()); } - public void cleanHomepage(DbSession dbSession, ComponentDto component) { - mapper(dbSession).clearHomepages("PROJECT", component.uuid(), system2.now()); - } - public void cleanHomepage(DbSession dbSession, UserDto user) { mapper(dbSession).clearHomepage(user.getLogin(), system2.now()); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml index 5b04f607600..e501244617d 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml @@ -85,17 +85,11 @@ ) - (select - from projects p - - where p.uuid = #{entityUuid,jdbcType=VARCHAR} - ) + from projects p) UNION (select - from portfolios p - - where p.uuid = #{entityUuid,jdbcType=VARCHAR} - ) + from portfolios p) diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/component/index/EntityDefinitionIndexerIT.java similarity index 83% rename from server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java rename to server/sonar-server-common/src/it/java/org/sonar/server/component/index/EntityDefinitionIndexerIT.java index 0a005850b94..a3bdaa863e6 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/component/index/EntityDefinitionIndexerIT.java @@ -30,14 +30,15 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectData; import org.sonar.db.entity.EntityDto; import org.sonar.db.es.EsQueueDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsTester; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingResult; -import org.sonar.server.es.ProjectIndexer; import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; @@ -46,11 +47,13 @@ import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_NAME; import static org.sonar.server.component.index.ComponentIndexDefinition.TYPE_COMPONENT; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_CREATION; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; +import static org.sonar.server.es.Indexers.EntityEvent.PERMISSION_CHANGE; +import static org.sonar.server.es.Indexers.EntityEvent.CREATION; +import static org.sonar.server.es.Indexers.EntityEvent.DELETION; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_TAGS_UPDATE; import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SORTABLE_ANALYZER; -public class ComponentIndexerIT { +public class EntityDefinitionIndexerIT { private System2 system2 = System2.INSTANCE; @@ -61,7 +64,7 @@ public class ComponentIndexerIT { private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); - private ComponentIndexer underTest = new ComponentIndexer(db.getDbClient(), es.client()); + private EntityDefinitionIndexer underTest = new EntityDefinitionIndexer(db.getDbClient(), es.client()); @Test public void test_getIndexTypes() { @@ -152,7 +155,7 @@ public class ComponentIndexerIT { public void do_not_update_index_on_project_tag_update() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - indexEntity(project, ProjectIndexer.Cause.PROJECT_TAGS_UPDATE); + indexProject(project, PROJECT_TAGS_UPDATE); assertThatIndexHasSize(0); } @@ -161,7 +164,7 @@ public class ComponentIndexerIT { public void do_not_update_index_on_permission_change() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - indexEntity(project, ProjectIndexer.Cause.PERMISSION_CHANGE); + indexProject(project, PERMISSION_CHANGE); assertThatIndexHasSize(0); } @@ -170,7 +173,7 @@ public class ComponentIndexerIT { public void update_index_on_project_creation() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - IndexingResult result = indexEntity(project, PROJECT_CREATION); + IndexingResult result = indexProject(project, CREATION); assertThatIndexContainsOnly(project); assertThat(result.getTotal()).isOne(); @@ -180,7 +183,7 @@ public class ComponentIndexerIT { @Test public void delete_some_components() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - indexEntity(project, PROJECT_CREATION); + indexProject(project, CREATION); underTest.delete(project.getUuid(), emptySet()); @@ -190,43 +193,42 @@ public class ComponentIndexerIT { @Test public void delete_project() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - indexEntity(project, PROJECT_CREATION); + indexProject(project, CREATION); assertThatIndexHasSize(1); db.getDbClient().purgeDao().deleteProject(db.getSession(), project.getUuid(), PROJECT, project.getName(), project.getKey()); - indexEntity(project, PROJECT_DELETION); + indexProject(project, DELETION); assertThatIndexHasSize(0); } @Test public void indexOnAnalysis_updates_index_on_changes() { - ProjectData project = db.components().insertPrivateProject(); - underTest.indexOnAnalysis(project.getMainBranchComponent().uuid()); - assertThatEntityHasName(project.projectUuid(), project.getProjectDto().getName()); - - // modify - ProjectDto projectDto = project.getProjectDto(); - projectDto.setName("NewName"); + ProjectData project = db.components().insertPrivateProject(); + ProjectDto projectDto = project.getProjectDto(); - db.getDbClient().projectDao().update(dbSession, projectDto); - db.commit(); + underTest.indexOnAnalysis(project.getMainBranchDto().getUuid()); + assertThatEntityHasName(projectDto.getUuid(), projectDto.getName()); - // verify that index is updated - underTest.indexOnAnalysis(project.getMainBranchComponent().uuid()); + // modify + projectDto.setName("NewName"); - assertThatIndexContainsOnly(projectDto.getUuid()); - assertThatEntityHasName(projectDto.getUuid(), "NewName"); -} + db.getDbClient().projectDao().update(dbSession, projectDto); + db.commit(); + // verify that index is updated + underTest.indexOnAnalysis(project.getMainBranchDto().getUuid()); + assertThatIndexContainsOnly(projectDto.getUuid()); + assertThatEntityHasName(projectDto.getUuid(), "NewName"); + } @Test public void errors_during_indexing_are_recovered() { ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); es.lockWrites(TYPE_COMPONENT); - IndexingResult result = indexEntity(project1, PROJECT_CREATION); + IndexingResult result = indexProject(project1, CREATION); assertThat(result.getTotal()).isOne(); assertThat(result.getFailures()).isOne(); @@ -244,9 +246,9 @@ public class ComponentIndexerIT { assertThatIndexContainsOnly(project1); } - private IndexingResult indexEntity(EntityDto entity, ProjectIndexer.Cause cause) { + private IndexingResult indexProject(ProjectDto project, Indexers.EntityEvent cause) { DbSession dbSession = db.getSession(); - Collection items = underTest.prepareForRecovery(dbSession, singletonList(entity.getUuid()), cause); + Collection items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(project.getUuid()), cause); dbSession.commit(); return underTest.index(dbSession, items); } diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java index ef6166a1226..6634ed703fa 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java @@ -43,11 +43,13 @@ import org.sonar.db.component.ProjectData; import org.sonar.db.es.EsQueueDto; import org.sonar.db.issue.IssueDto; import org.sonar.db.issue.IssueTesting; +import org.sonar.db.project.ProjectDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.es.EsTester; import org.sonar.server.es.IndexType; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.Indexers.EntityEvent; import org.sonar.server.es.IndexingResult; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.es.StartupIndexer; import org.sonar.server.permission.index.AuthorizationScope; import org.sonar.server.permission.index.IndexPermissions; @@ -62,6 +64,9 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.sonar.db.component.ComponentTesting.newFileDto; +import static org.sonar.server.es.Indexers.BranchEvent.DELETION; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_KEY_UPDATE; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_TAGS_UPDATE; import static org.sonar.server.issue.IssueDocTesting.newDoc; import static org.sonar.server.issue.index.IssueIndexDefinition.TYPE_ISSUE; import static org.sonar.server.permission.index.IndexAuthorizationConstants.TYPE_AUTHORIZATION; @@ -79,17 +84,17 @@ public class IssueIndexerIT { private final IssueIndexer underTest = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), null); @Test - public void test_getIndexTypes() { + public void getIndexTypes_shouldReturnTypeIssue() { assertThat(underTest.getIndexTypes()).containsExactly(TYPE_ISSUE); } @Test - public void test_getAuthorizationScope() { + public void getAuthorizationScope_shouldBeProject() { AuthorizationScope scope = underTest.getAuthorizationScope(); assertThat(scope.getIndexType().getIndex()).isEqualTo(IssueIndexDefinition.DESCRIPTOR); assertThat(scope.getIndexType().getType()).isEqualTo(TYPE_AUTHORIZATION); - Predicate projectPredicate = scope.getProjectPredicate(); + Predicate projectPredicate = scope.getEntityPredicate(); IndexPermissions project = new IndexPermissions("P1", Qualifiers.PROJECT); IndexPermissions file = new IndexPermissions("F1", Qualifiers.FILE); assertThat(projectPredicate.test(project)).isTrue(); @@ -97,7 +102,7 @@ public class IssueIndexerIT { } @Test - public void indexOnStartup_scrolls_db_and_adds_all_issues_to_index() { + public void indexAllIssues_shouldIndexAllIssues() { IssueDto issue1 = db.issues().insert(); IssueDto issue2 = db.issues().insert(); @@ -107,7 +112,7 @@ public class IssueIndexerIT { } @Test - public void verify_indexed_fields() { + public void indexAllIssues_shouldIndexAllIssueFields() { RuleDto rule = db.rules().insert(); ProjectData projectData = db.components().insertPrivateProject(); ComponentDto project = projectData.getMainBranchComponent(); @@ -142,7 +147,7 @@ public class IssueIndexerIT { } @Test - public void verify_security_standards_indexation() { + public void indexAllIssues_shouldIndexSecurityStandards() { RuleDto rule = db.rules().insert(r -> r.setSecurityStandards(new HashSet<>(Arrays.asList("cwe:123", "owaspTop10:a3", "cwe:863", "owaspAsvs-4.0:2.1.1")))); ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo")); @@ -166,7 +171,7 @@ public class IssueIndexerIT { Set uninitializedIndexTypes = emptySet(); assertThatThrownBy(() -> underTest.indexOnStartup(uninitializedIndexTypes)) .isInstanceOf(IllegalStateException.class) - .hasMessage("SYNCHRONE StartupIndexer must implement indexOnStartup"); + .hasMessage("SYNCHRONOUS StartupIndexer must implement indexOnStartup"); assertThatIndexHasSize(0); assertThatEsQueueTableHasSize(0); es.unlockWrites(TYPE_ISSUE); @@ -175,13 +180,13 @@ public class IssueIndexerIT { @Test public void indexOnAnalysis_indexes_the_issues_of_project() { RuleDto rule = db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - IssueDto issue = db.issues().insert(rule, project, file); + ComponentDto branchComponent = db.components().insertPrivateProject().getMainBranchComponent(); + ComponentDto file = db.components().insertComponent(newFileDto(branchComponent)); + IssueDto issue = db.issues().insert(rule, branchComponent, file); ComponentDto otherProject = db.components().insertPrivateProject().getMainBranchComponent(); db.components().insertComponent(newFileDto(otherProject)); - underTest.indexOnAnalysis(project.uuid()); + underTest.indexOnAnalysis(branchComponent.uuid()); assertThatIndexHasOnly(issue); } @@ -189,14 +194,14 @@ public class IssueIndexerIT { @Test public void indexOnAnalysis_does_not_delete_orphan_docs() { RuleDto rule = db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - IssueDto issue = db.issues().insert(rule, project, file); + ProjectData projectData = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(newFileDto(projectData.getMainBranchComponent())); + IssueDto issue = db.issues().insert(rule, projectData.getMainBranchComponent(), file); // orphan in the project - addIssueToIndex(project.uuid(), "orphan"); + addIssueToIndex(projectData.projectUuid(), projectData.getMainBranchComponent().uuid(), "orphan"); - underTest.indexOnAnalysis(project.uuid()); + underTest.indexOnAnalysis(projectData.getMainBranchComponent().uuid()); assertThat(es.getDocuments(TYPE_ISSUE)) .extracting(SearchHit::getId) @@ -222,43 +227,51 @@ public class IssueIndexerIT { } @Test - public void index_is_not_updated_when_creating_project() { - // it's impossible to already have an issue on a project - // that is being created, but it's just to verify that - // indexing is disabled + public void index_is_not_updated_when_updating_project_key() { + // issue is inserted to verify that indexing of project is not triggered IssueDto issue = db.issues().insert(); - IndexingResult result = indexProject(issue.getProjectUuid(), ProjectIndexer.Cause.PROJECT_CREATION); + IndexingResult result = indexProject(issue.getProjectUuid(), PROJECT_KEY_UPDATE); assertThat(result.getTotal()).isZero(); assertThatIndexHasSize(0); } @Test - public void index_is_not_updated_when_updating_project_key() { + public void index_is_not_updated_when_updating_tags() { // issue is inserted to verify that indexing of project is not triggered IssueDto issue = db.issues().insert(); - IndexingResult result = indexProject(issue.getProjectUuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE); + IndexingResult result = indexProject(issue.getProjectUuid(), PROJECT_TAGS_UPDATE); assertThat(result.getTotal()).isZero(); assertThatIndexHasSize(0); } @Test - public void index_is_not_updated_when_updating_tags() { - // issue is inserted to verify that indexing of project is not triggered - IssueDto issue = db.issues().insert(); + public void index_is_updated_when_deleting_branch() { + ProjectDto project = db.components().insertPublicProject().getProjectDto(); + BranchDto branch1 = db.components().insertProjectBranch(project); + BranchDto branch2 = db.components().insertProjectBranch(project); - IndexingResult result = indexProject(issue.getProjectUuid(), ProjectIndexer.Cause.PROJECT_TAGS_UPDATE); - assertThat(result.getTotal()).isZero(); - assertThatIndexHasSize(0); + addIssueToIndex(project.getUuid(), branch1.getUuid(), "I1"); + addIssueToIndex(project.getUuid(), branch1.getUuid(), "I2"); + addIssueToIndex(project.getUuid(), branch2.getUuid(), "I3"); + + assertThatIndexHasSize(3); + + IndexingResult result = indexBranch(branch1.getUuid(), DELETION); + + assertThat(result.getTotal()).isEqualTo(2); + assertThat(result.getSuccess()).isEqualTo(2); + assertThatIndexHasOnly("I3"); } @Test public void index_is_updated_when_deleting_project() { - addIssueToIndex("P1", "I1"); + BranchDto branch = db.components().insertPrivateProject().getMainBranchDto(); + addIssueToIndex(branch.getProjectUuid(), branch.getUuid(), "I1"); assertThatIndexHasSize(1); - IndexingResult result = indexProject("P1", ProjectIndexer.Cause.PROJECT_DELETION); + IndexingResult result = indexProject(branch.getProjectUuid(), EntityEvent.DELETION); assertThat(result.getTotal()).isOne(); assertThat(result.getSuccess()).isOne(); @@ -267,24 +280,26 @@ public class IssueIndexerIT { @Test public void errors_during_project_deletion_are_recovered() { - addIssueToIndex("P1", "I1"); - assertThatIndexHasSize(1); + addIssueToIndex("P1", "B1", "I1"); + addIssueToIndex("P1", "B2", "I2"); + + assertThatIndexHasSize(2); es.lockWrites(TYPE_ISSUE); - IndexingResult result = indexProject("P1", ProjectIndexer.Cause.PROJECT_DELETION); - assertThat(result.getTotal()).isOne(); - assertThat(result.getFailures()).isOne(); + IndexingResult result = indexProject("P1", EntityEvent.DELETION); + assertThat(result.getTotal()).isEqualTo(2); + assertThat(result.getFailures()).isEqualTo(2); // index is still read-only, fail to recover result = recover(); - assertThat(result.getTotal()).isOne(); - assertThat(result.getFailures()).isOne(); - assertThatIndexHasSize(1); + assertThat(result.getTotal()).isEqualTo(2); + assertThat(result.getFailures()).isEqualTo(2); + assertThatIndexHasSize(2); es.unlockWrites(TYPE_ISSUE); result = recover(); - assertThat(result.getTotal()).isOne(); + assertThat(result.getTotal()).isEqualTo(2); assertThat(result.getFailures()).isZero(); assertThatIndexHasSize(0); } @@ -310,8 +325,8 @@ public class IssueIndexerIT { @Test public void commitAndIndexIssues_removes_issue_from_index_if_it_does_not_exist_in_db() { - IssueDto issue1 = new IssueDto().setKee("I1").setProjectUuid("P1"); - addIssueToIndex(issue1.getProjectUuid(), issue1.getKey()); + IssueDto issue1 = new IssueDto().setKee("I1").setProjectUuid("B1"); + addIssueToIndex("B1", issue1.getProjectUuid(), issue1.getKey()); IssueDto issue2 = db.issues().insert(); underTest.commitAndIndexIssues(db.getSession(), asList(issue1, issue2)); @@ -400,7 +415,7 @@ public class IssueIndexerIT { es.lockWrites(TYPE_ISSUE); - IndexingResult result = indexProject(project.uuid(), ProjectIndexer.Cause.PROJECT_DELETION); + IndexingResult result = indexBranch(project.uuid(), DELETION); assertThat(result.getTotal()).isEqualTo(2L); assertThat(result.getFailures()).isEqualTo(2L); @@ -419,18 +434,24 @@ public class IssueIndexerIT { assertThatEsQueueTableHasSize(0); } - private IndexingResult indexProject(String projectUuid, ProjectIndexer.Cause cause) { - Collection items = underTest.prepareForRecovery(db.getSession(), singletonList(projectUuid), cause); + private IndexingResult indexBranch(String branchUuid, Indexers.BranchEvent cause) { + Collection items = underTest.prepareForRecoveryOnBranchEvent(db.getSession(), singletonList(branchUuid), cause); + db.commit(); + return underTest.index(db.getSession(), items); + } + + private IndexingResult indexProject(String projectUuid, EntityEvent cause) { + Collection items = underTest.prepareForRecoveryOnEntityEvent(db.getSession(), singletonList(projectUuid), cause); db.commit(); return underTest.index(db.getSession(), items); } @Test - public void deleteByKeys_deletes_docs_by_keys() { - addIssueToIndex("P1", "Issue1"); - addIssueToIndex("P1", "Issue2"); - addIssueToIndex("P1", "Issue3"); - addIssueToIndex("P2", "Issue4"); + public void deleteByKeys_shouldDeleteDocsByKeys() { + addIssueToIndex("P1", "B1", "Issue1"); + addIssueToIndex("P1", "B1", "Issue2"); + addIssueToIndex("P1", "B1", "Issue3"); + addIssueToIndex("P2", "B2", "Issue4"); assertThatIndexHasOnly("Issue1", "Issue2", "Issue3", "Issue4"); @@ -440,8 +461,8 @@ public class IssueIndexerIT { } @Test - public void deleteByKeys_does_not_recover_from_errors() { - addIssueToIndex("P1", "Issue1"); + public void deleteByKeys_shouldNotRecoverFromErrors() { + addIssueToIndex("P1", "B1","Issue1"); es.lockWrites(TYPE_ISSUE); List issues = List.of("Issue1"); @@ -454,12 +475,12 @@ public class IssueIndexerIT { } @Test - public void nothing_to_do_when_delete_issues_on_empty_list() { - addIssueToIndex("P1", "Issue1"); - addIssueToIndex("P1", "Issue2"); - addIssueToIndex("P1", "Issue3"); + public void deleteByKeys_whenEmptyList_shouldDoNothing() { + addIssueToIndex("P1", "B1", "Issue1"); + addIssueToIndex("P1", "B1", "Issue2"); + addIssueToIndex("P1", "B1", "Issue3"); - underTest.deleteByKeys("P1", emptyList()); + underTest.deleteByKeys("B1", emptyList()); assertThatIndexHasOnly("Issue1", "Issue2", "Issue3"); } @@ -533,14 +554,14 @@ public class IssueIndexerIT { @Test public void issue_on_project_has_main_code_scope() { RuleDto rule = db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - IssueDto issue = db.issues().insert(rule, project, project); + ComponentDto mainBranchComponent = db.components().insertPrivateProject().getMainBranchComponent(); + IssueDto issue = db.issues().insert(rule, mainBranchComponent, mainBranchComponent); underTest.indexAllIssues(); IssueDoc doc = es.getDocuments(TYPE_ISSUE, IssueDoc.class).get(0); assertThat(doc.getId()).isEqualTo(issue.getKey()); - assertThat(doc.componentUuid()).isEqualTo(project.uuid()); + assertThat(doc.componentUuid()).isEqualTo(mainBranchComponent.uuid()); assertThat(doc.scope()).isEqualTo(IssueScope.MAIN); } @@ -552,17 +573,17 @@ public class IssueIndexerIT { @Test public void indexOnAnalysis_whenChangedComponents_shouldReindexOnlyChangedComponents() { RuleDto rule = db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto changedComponent1 = db.components().insertComponent(newFileDto(project)); - ComponentDto unchangedComponent = db.components().insertComponent(newFileDto(project)); - ComponentDto ChangedComponent2 = db.components().insertComponent(newFileDto(project)); - IssueDto changedIssue1 = db.issues().insert(rule, project, changedComponent1); - IssueDto changedIssue2 = db.issues().insert(rule, project, changedComponent1); - IssueDto changedIssue3 = db.issues().insert(rule, project, ChangedComponent2); - db.issues().insert(rule, project, unchangedComponent); - db.issues().insert(rule, project, unchangedComponent); - - underTest.indexOnAnalysis(project.uuid(), Set.of(unchangedComponent.uuid())); + ComponentDto mainBranchComponent = db.components().insertPrivateProject().getMainBranchComponent(); + ComponentDto changedComponent1 = db.components().insertComponent(newFileDto(mainBranchComponent)); + ComponentDto unchangedComponent = db.components().insertComponent(newFileDto(mainBranchComponent)); + ComponentDto ChangedComponent2 = db.components().insertComponent(newFileDto(mainBranchComponent)); + IssueDto changedIssue1 = db.issues().insert(rule, mainBranchComponent, changedComponent1); + IssueDto changedIssue2 = db.issues().insert(rule, mainBranchComponent, changedComponent1); + IssueDto changedIssue3 = db.issues().insert(rule, mainBranchComponent, ChangedComponent2); + db.issues().insert(rule, mainBranchComponent, unchangedComponent); + db.issues().insert(rule, mainBranchComponent, unchangedComponent); + + underTest.indexOnAnalysis(mainBranchComponent.uuid(), Set.of(unchangedComponent.uuid())); assertThatIndexHasOnly(changedIssue1, changedIssue2, changedIssue3); } @@ -570,12 +591,12 @@ public class IssueIndexerIT { @Test public void indexOnAnalysis_whenEmptyUnchangedComponents_shouldReindexEverything() { RuleDto rule = db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto changedComponent = db.components().insertComponent(newFileDto(project)); - IssueDto changedIssue1 = db.issues().insert(rule, project, changedComponent); - IssueDto changedIssue2 = db.issues().insert(rule, project, changedComponent); + ComponentDto mainBranchComponent = db.components().insertPrivateProject().getMainBranchComponent(); + ComponentDto changedComponent = db.components().insertComponent(newFileDto(mainBranchComponent)); + IssueDto changedIssue1 = db.issues().insert(rule, mainBranchComponent, changedComponent); + IssueDto changedIssue2 = db.issues().insert(rule, mainBranchComponent, changedComponent); - underTest.indexOnAnalysis(project.uuid(), Set.of()); + underTest.indexOnAnalysis(mainBranchComponent.uuid(), Set.of()); assertThatIndexHasOnly(changedIssue1, changedIssue2); } @@ -583,17 +604,17 @@ public class IssueIndexerIT { @Test public void indexOnAnalysis_whenChangedComponentWithoutIssue_shouldReindexNothing() { db.rules().insert(); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - db.components().insertComponent(newFileDto(project)); + ComponentDto mainBranchComponent = db.components().insertPrivateProject().getMainBranchComponent(); + db.components().insertComponent(newFileDto(mainBranchComponent)); - underTest.indexOnAnalysis(project.uuid(), Set.of()); + underTest.indexOnAnalysis(mainBranchComponent.uuid(), Set.of()); assertThat(es.getDocuments(TYPE_ISSUE)).isEmpty(); } - private void addIssueToIndex(String projectUuid, String issueKey) { + private void addIssueToIndex(String projectUuid, String branchUuid, String issueKey) { es.putDocuments(TYPE_ISSUE, - newDoc().setKey(issueKey).setProjectUuid(projectUuid)); + newDoc().setKey(issueKey).setProjectUuid(projectUuid).setBranchUuid(branchUuid)); } private void assertThatIndexHasSize(long expectedSize) { diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/measure/index/ProjectMeasuresIndexerIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/measure/index/ProjectMeasuresIndexerIT.java index be0271154ee..c186dc93fac 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/measure/index/ProjectMeasuresIndexerIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/measure/index/ProjectMeasuresIndexerIT.java @@ -37,8 +37,8 @@ import org.sonar.db.component.SnapshotDto; import org.sonar.db.es.EsQueueDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.es.EsTester; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingResult; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.permission.index.AuthorizationScope; import org.sonar.server.permission.index.IndexPermissions; @@ -52,10 +52,10 @@ import static org.elasticsearch.index.query.QueryBuilders.termsQuery; import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.server.es.EsClient.prepareSearch; import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_CREATION; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_KEY_UPDATE; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_TAGS_UPDATE; +import static org.sonar.server.es.Indexers.EntityEvent.CREATION; +import static org.sonar.server.es.Indexers.EntityEvent.DELETION; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_KEY_UPDATE; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_TAGS_UPDATE; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_QUALIFIER; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_TAGS; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_UUID; @@ -74,12 +74,12 @@ public class ProjectMeasuresIndexerIT { private final ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(db.getDbClient(), es.client()); @Test - public void test_getAuthorizationScope() { + public void getAuthorizationScope_shouldReturnTrueForProjectAndApp() { AuthorizationScope scope = underTest.getAuthorizationScope(); assertThat(scope.getIndexType().getIndex()).isEqualTo(ProjectMeasuresIndexDefinition.DESCRIPTOR); assertThat(scope.getIndexType().getType()).isEqualTo(TYPE_AUTHORIZATION); - Predicate projectPredicate = scope.getProjectPredicate(); + Predicate projectPredicate = scope.getEntityPredicate(); IndexPermissions project = new IndexPermissions("P1", Qualifiers.PROJECT); IndexPermissions app = new IndexPermissions("P1", Qualifiers.APP); IndexPermissions file = new IndexPermissions("F1", Qualifiers.FILE); @@ -89,14 +89,14 @@ public class ProjectMeasuresIndexerIT { } @Test - public void index_nothing() { + public void indexOnStartup_whenNoEntities_shouldNotIndexAnything() { underTest.indexOnStartup(emptySet()); assertThat(es.countDocuments(TYPE_PROJECT_MEASURES)).isZero(); } @Test - public void indexOnStartup_indexes_all_projects() { + public void indexOnStartup_shouldIndexAllProjects() { SnapshotDto project1 = db.components().insertProjectAndSnapshot(newPrivateProjectDto()); SnapshotDto project2 = db.components().insertProjectAndSnapshot(newPrivateProjectDto()); SnapshotDto project3 = db.components().insertProjectAndSnapshot(newPrivateProjectDto()); @@ -205,7 +205,7 @@ public class ProjectMeasuresIndexerIT { public void update_index_when_project_is_created() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - IndexingResult result = indexProject(project, PROJECT_CREATION); + IndexingResult result = indexProject(project, CREATION); assertThatIndexContainsOnly(project); assertThat(result.getTotal()).isOne(); @@ -215,12 +215,11 @@ public class ProjectMeasuresIndexerIT { @Test public void update_index_when_project_tags_are_updated() { ProjectDto project = db.components().insertPrivateProject(defaults(), p -> p.setTagsString("foo")).getProjectDto(); - indexProject(project, PROJECT_CREATION); + indexProject(project, CREATION); assertThatProjectHasTag(project, "foo"); project.setTagsString("bar"); db.getDbClient().projectDao().updateTags(db.getSession(), project); - // TODO change indexing? IndexingResult result = indexProject(project, PROJECT_TAGS_UPDATE); assertThatProjectHasTag(project, "bar"); @@ -231,11 +230,11 @@ public class ProjectMeasuresIndexerIT { @Test public void delete_doc_from_index_when_project_is_deleted() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - indexProject(project, PROJECT_CREATION); + indexProject(project, CREATION); assertThatIndexContainsOnly(project); db.getDbClient().purgeDao().deleteProject(db.getSession(), project.getUuid(), Qualifiers.PROJECT, project.getName(), project.getKey()); - IndexingResult result = indexProject(project, PROJECT_DELETION); + IndexingResult result = indexProject(project, DELETION); assertThat(es.countDocuments(TYPE_PROJECT_MEASURES)).isZero(); assertThat(result.getTotal()).isOne(); @@ -258,7 +257,7 @@ public class ProjectMeasuresIndexerIT { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); es.lockWrites(TYPE_PROJECT_MEASURES); - IndexingResult result = indexProject(project, PROJECT_CREATION); + IndexingResult result = indexProject(project, CREATION); assertThat(result.getTotal()).isOne(); assertThat(result.getFailures()).isOne(); @@ -288,9 +287,9 @@ public class ProjectMeasuresIndexerIT { assertThat(es.countDocuments(TYPE_PROJECT_MEASURES)).isZero(); } - private IndexingResult indexProject(ProjectDto project, ProjectIndexer.Cause cause) { + private IndexingResult indexProject(ProjectDto project, Indexers.EntityEvent cause) { DbSession dbSession = db.getSession(); - Collection items = underTest.prepareForRecovery(dbSession, singletonList(project.getUuid()), cause); + Collection items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(project.getUuid()), cause); dbSession.commit(); return underTest.index(dbSession, items); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/EntityDefinitionIndexer.java similarity index 79% rename from server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java rename to server/sonar-server-common/src/main/java/org/sonar/server/component/index/EntityDefinitionIndexer.java index 1fbda41ee1d..3f7a7f2e9c5 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/EntityDefinitionIndexer.java @@ -35,14 +35,16 @@ import org.sonar.db.DbSession; import org.sonar.db.component.BranchDto; import org.sonar.db.entity.EntityDto; import org.sonar.db.es.EsQueueDto; +import org.sonar.server.es.AnalysisIndexer; import org.sonar.server.es.BaseDoc; import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.BulkIndexer.Size; import org.sonar.server.es.EsClient; +import org.sonar.server.es.EventIndexer; import org.sonar.server.es.IndexType; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingResult; import org.sonar.server.es.OneToManyResilientIndexingListener; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.permission.index.AuthorizationDoc; import org.sonar.server.permission.index.AuthorizationScope; import org.sonar.server.permission.index.NeedAuthorizationIndexer; @@ -50,15 +52,18 @@ import org.sonar.server.permission.index.NeedAuthorizationIndexer; import static java.util.Collections.emptyList; import static org.sonar.server.component.index.ComponentIndexDefinition.TYPE_COMPONENT; -public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexer { +/** + * Indexes the definition of all entities: projects, applications, portfolios and sub-portfolios. + */ +public class EntityDefinitionIndexer implements EventIndexer, AnalysisIndexer, NeedAuthorizationIndexer { - private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_COMPONENT, project -> true); + private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_COMPONENT, entity -> true); private static final Set INDEX_TYPES = Set.of(TYPE_COMPONENT); private final DbClient dbClient; private final EsClient esClient; - public ComponentIndexer(DbClient dbClient, EsClient esClient) { + public EntityDefinitionIndexer(DbClient dbClient, EsClient esClient) { this.dbClient = dbClient; this.esClient = esClient; } @@ -91,7 +96,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe return; } EntityDto entity = dbClient.entityDao().selectByComponentUuid(dbSession, branchUuid) - .orElseThrow(() -> new IllegalStateException("Can't find entity " + branchUuid)); + .orElseThrow(() -> new IllegalStateException("Can't find entity for branch " + branchUuid)); doIndexByEntityUuid(entity); } } @@ -102,20 +107,23 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe } @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, Cause cause) { - switch (cause) { - case MEASURE_CHANGE, PROJECT_TAGS_UPDATE, PERMISSION_CHANGE: - // measures, tags and permissions are not part of type components/component - return emptyList(); - case PROJECT_CREATION, PROJECT_DELETION, PROJECT_KEY_UPDATE: - List items = projectUuids.stream() - .map(projectUuid -> EsQueueDto.create(TYPE_COMPONENT.format(), projectUuid, null, projectUuid)) - .collect(MoreCollectors.toArrayList(projectUuids.size())); - return dbClient.esQueueDao().insert(dbSession, items); - default: - // defensive case - throw new IllegalStateException("Unsupported cause: " + cause); - } + public Collection prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection entityUuids, Indexers.EntityEvent cause) { + return switch (cause) { + case PROJECT_TAGS_UPDATE, PERMISSION_CHANGE -> + // measures, tags and permissions does not affect the definition of entities + emptyList(); + case CREATION, DELETION, PROJECT_KEY_UPDATE -> { + List items = entityUuids.stream() + .map(entityUuid -> EsQueueDto.create(TYPE_COMPONENT.format(), entityUuid, null, entityUuid)) + .collect(MoreCollectors.toArrayList(entityUuids.size())); + yield dbClient.esQueueDao().insert(dbSession, items); + } + }; + } + + @Override + public Collection prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection branchUuids, Indexers.BranchEvent cause) { + return emptyList(); } @Override @@ -130,13 +138,10 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe Set entityUuids = items.stream().map(EsQueueDto::getDocId).collect(MoreCollectors.toHashSet(items.size())); Set remaining = new HashSet<>(entityUuids); - for (String entityUuid : entityUuids) { - dbClient.entityDao().scrollForIndexing(dbSession, entityUuid, context -> { - EntityDto dto = context.getResultObject(); - remaining.remove(dto.getUuid()); - bulkIndexer.add(toDocument(dto).toIndexRequest()); - }); - } + dbClient.entityDao().selectByUuids(dbSession, entityUuids).forEach(dto -> { + remaining.remove(dto.getUuid()); + bulkIndexer.add(toDocument(dto).toIndexRequest()); + }); // the remaining uuids reference projects that don't exist in db. They must // be deleted from index. @@ -169,7 +174,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe BulkIndexer bulk = new BulkIndexer(esClient, TYPE_COMPONENT, bulkSize); bulk.start(); try (DbSession dbSession = dbClient.openSession(false)) { - dbClient.entityDao().scrollForIndexing(dbSession, null, context -> { + dbClient.entityDao().scrollForIndexing(dbSession, context -> { EntityDto dto = context.getResultObject(); bulk.add(toDocument(dto).toIndexRequest()); }); @@ -197,7 +202,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe BulkIndexer bulk = new BulkIndexer(esClient, TYPE_COMPONENT, Size.REGULAR); bulk.start(); Arrays.stream(docs) - .map(ComponentIndexer::toDocument) + .map(EntityDefinitionIndexer::toDocument) .map(BaseDoc::toIndexRequest) .forEach(bulk::add); bulk.stop(); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/AnalysisIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/AnalysisIndexer.java new file mode 100644 index 00000000000..a37ce7ec7ed --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/AnalysisIndexer.java @@ -0,0 +1,43 @@ +/* + * 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.es; + +import java.util.Set; + +/** + * Indexers that should be called when a project branch is analyzed + */ +public interface AnalysisIndexer { + /** + * This method is called when an analysis must be indexed. + * + * @param branchUuid UUID of a project or application branch + */ + void indexOnAnalysis(String branchUuid); + + /** + * This method is called when an analysis must be indexed. + * + * @param branchUuid UUID of a project or application branch + * @param unchangedComponentUuids UUIDs of components that didn't change in this analysis. + * Indexers can be optimized by not re-indexing data related to these components. + */ + void indexOnAnalysis(String branchUuid, Set unchangedComponentUuids); +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/BranchIndexer.java similarity index 58% rename from server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexer.java rename to server/sonar-server-common/src/main/java/org/sonar/server/es/BranchIndexer.java index 1db14f06614..5aafc9039a1 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/BranchIndexer.java @@ -24,24 +24,11 @@ import java.util.Set; import org.sonar.db.DbSession; import org.sonar.db.es.EsQueueDto; -/** - * A {@link ProjectIndexer} populates an Elasticsearch index - * containing project-related documents, for instance issues - * or tests. This interface allows to quickly integrate new - * indices in the lifecycle of projects. - * - * If the related index handles verification of authorization, - * then the implementation of {@link ProjectIndexer} must - * also implement {@link org.sonar.server.permission.index.NeedAuthorizationIndexer} - */ -public interface ProjectIndexer extends ResilientIndexer { +public interface BranchIndexer extends ResilientIndexer { enum Cause { - PROJECT_CREATION, - PROJECT_DELETION, - PROJECT_KEY_UPDATE, - PROJECT_TAGS_UPDATE, - PERMISSION_CHANGE, + CREATION, + DELETION, MEASURE_CHANGE } @@ -50,9 +37,9 @@ public interface ProjectIndexer extends ResilientIndexer { * * @param branchUuid UUID of a project or application branch, or the UUID of a portfolio. */ - void indexOnAnalysis(String branchUuid); + void indexBranchOnAnalysis(String branchUuid); - void indexOnAnalysis(String branchUuid, Set unchangedComponentUuids); + void indexBranchOnAnalysis(String branchUuid, Set unchangedComponentUuids); - Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause); + Collection prepareBranchIndexForRecovery(DbSession dbSession, Collection branchUuids, BranchIndexer.Cause cause); } diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/EventIndexer.java similarity index 54% rename from server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java rename to server/sonar-server-common/src/main/java/org/sonar/server/es/EventIndexer.java index 6b6f617c1d9..3b1718cf2cc 100644 --- a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/EventIndexer.java @@ -19,27 +19,22 @@ */ package org.sonar.server.es; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; import java.util.Collection; import org.sonar.db.DbSession; +import org.sonar.db.es.EsQueueDto; -public class TestProjectIndexers implements ProjectIndexers { - - private final ListMultimap calls = ArrayListMultimap.create(); - - @Override - public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - dbSession.commit(); - projectUuids.forEach(projectUuid -> calls.put(projectUuid, cause)); - - } +/** + * A {@link EventIndexer} populates an Elasticsearch index + * based on events related to entities and branches. This interface allows to quickly integrate new + * indices in the lifecycle of entities and branches. + * + * If the related index handles verification of authorization, + * then the implementation of {@link EventIndexer} must + * also implement {@link org.sonar.server.permission.index.NeedAuthorizationIndexer} + */ +public interface EventIndexer extends ResilientIndexer { + Collection prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection entityUuids, Indexers.EntityEvent cause); - public boolean hasBeenCalled(String projectUuid, ProjectIndexer.Cause expectedCause) { - return calls.get(projectUuid).contains(expectedCause); - } + Collection prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection branchUuids, Indexers.BranchEvent cause); - public boolean hasBeenCalled(String projectUuid) { - return calls.containsKey(projectUuid); - } } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/Indexers.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/Indexers.java new file mode 100644 index 00000000000..78bf19cf2d3 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/Indexers.java @@ -0,0 +1,81 @@ +/* + * 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.es; + +import java.util.Collection; +import java.util.stream.Collectors; +import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; +import org.sonar.db.entity.EntityDto; + +public interface Indexers { + enum EntityEvent { + CREATION, + DELETION, + PROJECT_KEY_UPDATE, + PROJECT_TAGS_UPDATE, + PERMISSION_CHANGE + } + + enum BranchEvent { + // Note that when a project/app is deleted, no events are sent for each branch removed as part of that process + DELETION, + MEASURE_CHANGE + } + + /** + * Re-index data based on the event. It commits the DB session once any indexation request was written in the same session, + * ensuring consistency between the DB and the indexes. Therefore, DB data changes that cause the indexation event should + * be done using the same DB session and the session should be uncommitted. + */ + void commitAndIndexOnEntityEvent(DbSession dbSession, Collection entityUuids, EntityEvent cause); + + /** + * Re-index data based on the event. It commits the DB session once any indexation request was written in the same session, + * ensuring consistency between the DB and the indexes. Therefore, DB data changes that cause the indexation event should + * be done using the same DB session and the session should be uncommitted. + */ + void commitAndIndexOnBranchEvent(DbSession dbSession, Collection branchUuids, BranchEvent cause); + + /** + * Re-index data based on the event. It commits the DB session once any indexation request was written in the same session, + * ensuring consistency between the DB and the indexes. Therefore, DB data changes that cause the indexation event should + * be done using the same DB session and the session should be uncommitted. + */ + default void commitAndIndexEntities(DbSession dbSession, Collection entities, EntityEvent cause) { + Collection entityUuids = entities.stream() + .map(EntityDto::getUuid) + .collect(MoreCollectors.toSet(entities.size())); + commitAndIndexOnEntityEvent(dbSession, entityUuids, cause); + } + + /** + * Re-index data based on the event. It commits the DB session once any indexation request was written in the same session, + * ensuring consistency between the DB and the indexes. Therefore, DB data changes that cause the indexation event should + * be done using the same DB session and the session should be uncommitted. + */ + default void commitAndIndexBranches(DbSession dbSession, Collection branches, BranchEvent cause) { + Collection branchUuids = branches.stream() + .map(BranchDto::getUuid) + .collect(Collectors.toSet()); + commitAndIndexOnBranchEvent(dbSession, branchUuids, cause); + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/IndexersImpl.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/IndexersImpl.java new file mode 100644 index 00000000000..4df20b7287b --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/IndexersImpl.java @@ -0,0 +1,76 @@ +/* + * 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.es; + +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.sonar.db.DbSession; +import org.sonar.db.es.EsQueueDto; + +import static java.util.Arrays.asList; + +/** + * Delegates events to indexers, that may want to reindex something based on the event. + */ +public class IndexersImpl implements Indexers { + + private final List indexers; + + public IndexersImpl(EventIndexer... indexers) { + this.indexers = asList(indexers); + } + + /** + * Asks all indexers to queue an indexation request in the DB to index the specified entities, if needed (according to + * "cause" parameter), then call all indexers to index the requests. + * The idea is that the indexation requests are committed into the DB at the same time as the data that caused those requests + * to be created, for consistency. + * If the indexation fails, the indexation requests will still be in the DB and can be processed again later. + */ + @Override + public void commitAndIndexOnEntityEvent(DbSession dbSession, Collection entityUuids, EntityEvent cause) { + indexOnEvent(dbSession, indexer -> indexer.prepareForRecoveryOnEntityEvent(dbSession, entityUuids, cause)); + } + + /** + * Asks all indexers to queue an indexation request in the DB to index the specified branches, if needed (according to + * "cause" parameter), then call all indexers to index the requests. + * The idea is that the indexation requests are committed into the DB at the same time as the data that caused those requests + * to be created, for consistency. + * If the indexation fails, the indexation requests will still be in the DB and can be processed again later. + */ + @Override + public void commitAndIndexOnBranchEvent(DbSession dbSession, Collection branchUuids, BranchEvent cause) { + indexOnEvent(dbSession, indexer -> indexer.prepareForRecoveryOnBranchEvent(dbSession, branchUuids, cause)); + } + + + private void indexOnEvent(DbSession dbSession, Function> esQueueSupplier) { + Map> itemsByIndexer = new IdentityHashMap<>(); + indexers.forEach(i -> itemsByIndexer.put(i, esQueueSupplier.apply(i))); + dbSession.commit(); + + // ensure that indexer#index() is called only with the item type that it supports + itemsByIndexer.forEach((indexer, items) -> indexer.index(dbSession, items)); + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java deleted file mode 100644 index abcbebb0d05..00000000000 --- a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.es; - -import java.util.Collection; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.entity.EntityDto; -import org.sonar.db.project.ProjectDto; - -public interface ProjectIndexers { - - /** - * Commits the DB transaction and indexes the specified projects, if needed (according to - * "cause" parameter). - * IMPORTANT - UUIDs must relate to applications and projects only. Modules, directories and files are forbidden - * and will lead to lack of indexing. - */ - void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause); - - default void commitAndIndexEntities(DbSession dbSession, Collection entities, ProjectIndexer.Cause cause) { - Collection entityUuids = entities.stream() - .map(EntityDto::getUuid) - .collect(MoreCollectors.toSet(entities.size())); - commitAndIndexByProjectUuids(dbSession, entityUuids, cause); - } - - default void commitAndIndexProjects(DbSession dbSession, Collection projects, ProjectIndexer.Cause cause) { - commitAndIndexEntities(dbSession, projects, cause); - } - - default void commitAndIndexComponents(DbSession dbSession, Collection projects, ProjectIndexer.Cause cause) { - Collection projectUuids = projects.stream() - .map(ComponentDto::branchUuid) - .collect(MoreCollectors.toSet(projects.size())); - commitAndIndexByProjectUuids(dbSession, projectUuids, cause); - } - - default void commitAndIndexBranches(DbSession dbSession, Collection branches, ProjectIndexer.Cause cause) { - Collection branchUuids = branches.stream() - .map(BranchDto::getUuid) - .toList(); - commitAndIndexByProjectUuids(dbSession, branchUuids, cause); - } -} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java deleted file mode 100644 index 5b35fdd20a7..00000000000 --- a/server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.es; - -import java.util.Collection; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import org.sonar.db.DbSession; -import org.sonar.db.es.EsQueueDto; - -import static java.util.Arrays.asList; - -public class ProjectIndexersImpl implements ProjectIndexers { - - private final List indexers; - - public ProjectIndexersImpl(ProjectIndexer... indexers) { - this.indexers = asList(indexers); - } - - @Override - public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - Map> itemsByIndexer = new IdentityHashMap<>(); - indexers.forEach(i -> itemsByIndexer.put(i, i.prepareForRecovery(dbSession, projectUuids, cause))); - dbSession.commit(); - - // ensure that indexer#index() is called only with the item type that it supports - itemsByIndexer.forEach((indexer, items) -> indexer.index(dbSession, items)); - } -} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/ResilientIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/ResilientIndexer.java index 6727f89825c..3ec60e95236 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/es/ResilientIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/ResilientIndexer.java @@ -24,13 +24,13 @@ import org.sonar.db.DbSession; import org.sonar.db.es.EsQueueDto; /** - * Indexers that are resilient + * Indexers that are resilient. These indexers handle indexation items that are queued in the DB. */ public interface ResilientIndexer extends StartupIndexer { /** * Index the items and delete them from es_queue DB table when the indexation - * is done, keeping them if there is a failure on the item of the collection + * is done. If there is a failure, the items are kept in DB to be re-processed later. * * @param dbSession the db session * @param items the items to be indexed diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java index 9dc5e06a2ff..497adf2b28e 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java @@ -34,7 +34,7 @@ public interface StartupIndexer { } default void triggerAsyncIndexOnStartup(Set uninitializedIndexTypes) { - throw new IllegalStateException("ASYNCHRONE StartupIndexer must implement initAsyncIndexOnStartup"); + throw new IllegalStateException("ASYNCHRONOUS StartupIndexer must implement initAsyncIndexOnStartup"); } /** @@ -42,7 +42,7 @@ public interface StartupIndexer { * if there is at least one uninitialized type. */ default void indexOnStartup(Set uninitializedIndexTypes) { - throw new IllegalStateException("SYNCHRONE StartupIndexer must implement indexOnStartup"); + throw new IllegalStateException("SYNCHRONOUS StartupIndexer must implement indexOnStartup"); } Set getIndexTypes(); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexer.java index d446c4e491d..a058dfdb287 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexer.java @@ -25,27 +25,31 @@ import com.google.common.collect.ListMultimap; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.search.builder.SearchSourceBuilder; -import org.sonar.api.resources.Qualifiers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.api.resources.Qualifiers; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; import org.sonar.db.es.EsQueueDto; import org.sonar.db.issue.IssueDto; +import org.sonar.server.es.AnalysisIndexer; import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.BulkIndexer.Size; import org.sonar.server.es.EsClient; +import org.sonar.server.es.EventIndexer; import org.sonar.server.es.IndexType; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingListener; import org.sonar.server.es.IndexingResult; import org.sonar.server.es.OneToManyResilientIndexingListener; import org.sonar.server.es.OneToOneResilientIndexingListener; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.permission.index.AuthorizationDoc; import org.sonar.server.permission.index.AuthorizationScope; import org.sonar.server.permission.index.NeedAuthorizationIndexer; @@ -53,21 +57,31 @@ import org.sonar.server.permission.index.NeedAuthorizationIndexer; import static java.util.Collections.emptyList; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID; import static org.sonar.server.issue.index.IssueIndexDefinition.TYPE_ISSUE; -public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { +/** + * Indexes issues. All issues belong directly to a project branch, so they only change when a project branch changes. + */ +public class IssueIndexer implements EventIndexer, AnalysisIndexer, NeedAuthorizationIndexer { /** * Indicates that es_queue.doc_id references an issue. Only this issue must be indexed. */ private static final String ID_TYPE_ISSUE_KEY = "issueKey"; /** - * Indicates that es_queue.doc_id references a project. All the issues of the project must be indexed. + * Indicates that es_queue.doc_id references a branch. All the issues of the branch must be indexed. + * Note that the constant is misleading, but we can't update it since there might some items in the DB during the upgrade. + */ + private static final String ID_TYPE_BRANCH_UUID = "projectUuid"; + /** + * Indicates that es_queue.doc_id references a project and that all issues in it should be delete. */ - private static final String ID_TYPE_PROJECT_UUID = "projectUuid"; + private static final String ID_TYPE_DELETE_PROJECT_UUID = "deleteProjectUuid"; + private static final Logger LOGGER = LoggerFactory.getLogger(IssueIndexer.class); - private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_ISSUE, project -> Qualifiers.PROJECT.equals(project.getQualifier())); + private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_ISSUE, entity -> Qualifiers.PROJECT.equals(entity.getQualifier())); private static final Set INDEX_TYPES = Set.of(TYPE_ISSUE); private final EsClient esClient; @@ -127,23 +141,44 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { } @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - switch (cause) { - case PROJECT_CREATION, MEASURE_CHANGE, PROJECT_KEY_UPDATE, PROJECT_TAGS_UPDATE, PERMISSION_CHANGE: + public Collection prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection entityUuids, Indexers.EntityEvent cause) { + return switch (cause) { + case CREATION, PROJECT_KEY_UPDATE, PROJECT_TAGS_UPDATE, PERMISSION_CHANGE -> // Nothing to do, issues do not exist at project creation // Measures, permissions, project key and tags are not used in type issues/issue - return emptyList(); + emptyList(); - case PROJECT_DELETION: - List items = projectUuids.stream() - .map(projectUuid -> createQueueDto(projectUuid, ID_TYPE_PROJECT_UUID, projectUuid)) - .collect(MoreCollectors.toArrayList(projectUuids.size())); - return dbClient.esQueueDao().insert(dbSession, items); + case DELETION -> { + List items = createProjectDeleteRecoveryItems(entityUuids); + yield dbClient.esQueueDao().insert(dbSession, items); + } + }; + } - default: - // defensive case - throw new IllegalStateException("Unsupported cause: " + cause); - } + @Override + public Collection prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection branchUuids, Indexers.BranchEvent cause) { + return switch (cause) { + case MEASURE_CHANGE -> + // Measures, permissions, project key and tags are not used in type issues/issue + emptyList(); + + case DELETION -> { + List items = createBranchRecoveryItems(branchUuids); + yield dbClient.esQueueDao().insert(dbSession, items); + } + }; + } + + private List createProjectDeleteRecoveryItems(Collection entityUuids) { + return entityUuids.stream() + .map(entityUuid -> createQueueDto(entityUuid, ID_TYPE_DELETE_PROJECT_UUID, entityUuid)) + .collect(Collectors.toList()); + } + + private List createBranchRecoveryItems(Collection branchUuids) { + return branchUuids.stream() + .map(branchUuid -> createQueueDto(branchUuid, ID_TYPE_BRANCH_UUID, branchUuid)) + .collect(Collectors.toList()); } /** @@ -170,12 +205,16 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { @Override public IndexingResult index(DbSession dbSession, Collection items) { ListMultimap itemsByIssueKey = ArrayListMultimap.create(); - ListMultimap itemsByProjectUuid = ArrayListMultimap.create(); + ListMultimap itemsByBranchUuid = ArrayListMultimap.create(); + ListMultimap itemsByDeleteProjectUuid = ArrayListMultimap.create(); + items.forEach(i -> { if (ID_TYPE_ISSUE_KEY.equals(i.getDocIdType())) { itemsByIssueKey.put(i.getDocId(), i); - } else if (ID_TYPE_PROJECT_UUID.equals(i.getDocIdType())) { - itemsByProjectUuid.put(i.getDocId(), i); + } else if (ID_TYPE_BRANCH_UUID.equals(i.getDocIdType())) { + itemsByBranchUuid.put(i.getDocId(), i); + } else if (ID_TYPE_DELETE_PROJECT_UUID.equals(i.getDocIdType())) { + itemsByDeleteProjectUuid.put(i.getDocId(), i); } else { LOGGER.error("Unsupported es_queue.doc_id_type for issues. Manual fix is required: " + i); } @@ -183,7 +222,8 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { IndexingResult result = new IndexingResult(); result.add(doIndexIssueItems(dbSession, itemsByIssueKey)); - result.add(doIndexProjectItems(dbSession, itemsByProjectUuid)); + result.add(doIndexBranchItems(dbSession, itemsByBranchUuid)); + result.add(doDeleteProjectIndexItems(dbSession, itemsByDeleteProjectUuid)); return result; } @@ -211,28 +251,38 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { return bulkIndexer.stop(); } - private IndexingResult doIndexProjectItems(DbSession dbSession, ListMultimap itemsByProjectUuid) { - if (itemsByProjectUuid.isEmpty()) { + private IndexingResult doDeleteProjectIndexItems(DbSession dbSession, ListMultimap itemsByDeleteProjectUuid) { + IndexingListener listener = new OneToManyResilientIndexingListener(dbClient, dbSession, itemsByDeleteProjectUuid.values()); + BulkIndexer bulkIndexer = createBulkIndexer(listener); + bulkIndexer.start(); + for (String projectUuid : itemsByDeleteProjectUuid.keySet()) { + addProjectDeletionToBulkIndexer(bulkIndexer, projectUuid); + } + return bulkIndexer.stop(); + } + + private IndexingResult doIndexBranchItems(DbSession dbSession, ListMultimap itemsByBranchUuid) { + if (itemsByBranchUuid.isEmpty()) { return new IndexingResult(); } - // one project, referenced by es_queue.doc_id = many issues - IndexingListener listener = new OneToManyResilientIndexingListener(dbClient, dbSession, itemsByProjectUuid.values()); + // one branch, referenced by es_queue.doc_id = many issues + IndexingListener listener = new OneToManyResilientIndexingListener(dbClient, dbSession, itemsByBranchUuid.values()); BulkIndexer bulkIndexer = createBulkIndexer(listener); bulkIndexer.start(); - for (String projectUuid : itemsByProjectUuid.keySet()) { - // TODO support loading of multiple projects in a single SQL request - try (IssueIterator issues = issueIteratorFactory.createForBranch(projectUuid)) { + for (String branchUuid : itemsByBranchUuid.keySet()) { + try (IssueIterator issues = issueIteratorFactory.createForBranch(branchUuid)) { if (issues.hasNext()) { do { IssueDoc doc = issues.next(); bulkIndexer.add(newIndexRequest(doc)); } while (issues.hasNext()); } else { - // project does not exist or has no issues. In both case - // all the documents related to this project are deleted. - addProjectDeletionToBulkIndexer(bulkIndexer, projectUuid); + // branch does not exist or has no issues. In both cases, + // all the documents related to this branch are deleted. + Optional branch = dbClient.branchDao().selectByUuid(dbSession, branchUuid); + branch.ifPresent(b -> addBranchDeletionToBulkIndexer(bulkIndexer, b.getProjectUuid(), b.getUuid())); } } } @@ -288,6 +338,17 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer { bulkIndexer.addDeletion(search); } + private static void addBranchDeletionToBulkIndexer(BulkIndexer bulkIndexer, String projectUUid, String branchUuid) { + SearchRequest search = EsClient.prepareSearch(TYPE_ISSUE.getMainType()) + // routing is based on the parent (See BaseDoc#getRouting). + // The parent is set to the projectUUid when an issue is indexed (See IssueDoc#setProjectUuid). We need to set it here + // so that the search finds the indexed docs to be deleted. + .routing(AuthorizationDoc.idOf(projectUUid)) + .source(new SearchSourceBuilder().query(boolQuery().must(termQuery(FIELD_ISSUE_BRANCH_UUID, branchUuid)))); + + bulkIndexer.addDeletion(search); + } + private static EsQueueDto createQueueDto(String docId, String docIdType, String projectUuid) { return EsQueueDto.create(TYPE_ISSUE.format(), docId, docIdType, AuthorizationDoc.idOf(projectUuid)); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java index 4ffeaca7bbc..7bedc634001 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java @@ -26,32 +26,41 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.sonar.api.resources.Qualifiers; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; import org.sonar.db.es.EsQueueDto; import org.sonar.db.measure.ProjectMeasuresIndexerIterator; import org.sonar.db.measure.ProjectMeasuresIndexerIterator.ProjectMeasures; +import org.sonar.server.es.AnalysisIndexer; import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.BulkIndexer.Size; import org.sonar.server.es.EsClient; +import org.sonar.server.es.EventIndexer; import org.sonar.server.es.IndexType; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingListener; import org.sonar.server.es.IndexingResult; import org.sonar.server.es.OneToOneResilientIndexingListener; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.permission.index.AuthorizationDoc; import org.sonar.server.permission.index.AuthorizationScope; import org.sonar.server.permission.index.NeedAuthorizationIndexer; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES; -public class ProjectMeasuresIndexer implements ProjectIndexer, NeedAuthorizationIndexer { +/** + * Indexes data related to projects and applications. + * The name is a bit misleading - it indexes a lot more data than just measures. + * We index by project/app UUID, but we get a lot of the data from their main branches. + */ +public class ProjectMeasuresIndexer implements EventIndexer, AnalysisIndexer, NeedAuthorizationIndexer { private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_PROJECT_MEASURES, - project -> Qualifiers.PROJECT.equals(project.getQualifier()) || Qualifiers.APP.equals(project.getQualifier())); + entity -> Qualifiers.PROJECT.equals(entity.getQualifier()) || Qualifiers.APP.equals(entity.getQualifier())); private static final Set INDEX_TYPES = Set.of(TYPE_PROJECT_MEASURES); private final DbClient dbClient; @@ -82,33 +91,46 @@ public class ProjectMeasuresIndexer implements ProjectIndexer, NeedAuthorization } @Override - public void indexOnAnalysis(String projectUuid) { - indexOnAnalysis(projectUuid, Set.of()); + public void indexOnAnalysis(String branchUuid) { + indexOnAnalysis(branchUuid, Set.of()); } @Override - public void indexOnAnalysis(String projectUuid, Set unchangedComponentUuids) { - doIndex(Size.REGULAR, projectUuid); + public void indexOnAnalysis(String branchUuid, Set unchangedComponentUuids) { + doIndex(Size.REGULAR, branchUuid); } @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - switch (cause) { - case PERMISSION_CHANGE: - // nothing to do, permissions are not used in type projectmeasures/projectmeasure - return Collections.emptyList(); - case MEASURE_CHANGE, PROJECT_KEY_UPDATE, PROJECT_CREATION, PROJECT_TAGS_UPDATE, PROJECT_DELETION: + public Collection prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection entityUuids, Indexers.EntityEvent cause) { + return switch (cause) { + case PERMISSION_CHANGE -> + // nothing to do, permissions are not used in index type projectmeasures/projectmeasure + Collections.emptyList(); + case PROJECT_KEY_UPDATE, CREATION, PROJECT_TAGS_UPDATE, DELETION -> // when MEASURE_CHANGE or PROJECT_KEY_UPDATE project must be re-indexed because key is used in this index // when PROJECT_CREATION provisioned projects are supported by WS api/components/search_projects - List items = projectUuids.stream() - .map(projectUuid -> EsQueueDto.create(TYPE_PROJECT_MEASURES.format(), projectUuid, null, projectUuid)) - .collect(MoreCollectors.toArrayList(projectUuids.size())); - return dbClient.esQueueDao().insert(dbSession, items); - - default: - // defensive case - throw new IllegalStateException("Unsupported cause: " + cause); - } + prepareForRecovery(dbSession, entityUuids); + }; + } + + @Override + public Collection prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection branchUuids, Indexers.BranchEvent cause) { + return switch (cause) { + case DELETION -> Collections.emptyList(); + case MEASURE_CHANGE -> { + Set entityUuids = dbClient.branchDao().selectByUuids(dbSession, branchUuids) + .stream().map(BranchDto::getProjectUuid) + .collect(Collectors.toSet()); + yield prepareForRecovery(dbSession, entityUuids); + } + }; + } + + private Collection prepareForRecovery(DbSession dbSession, Collection entityUuids) { + List items = entityUuids.stream() + .map(entityUuid -> EsQueueDto.create(TYPE_PROJECT_MEASURES.format(), entityUuid, null, entityUuid)) + .collect(MoreCollectors.toArrayList(entityUuids.size())); + return dbClient.esQueueDao().insert(dbSession, items); } public IndexingResult commitAndIndex(DbSession dbSession, Collection projectUuids) { diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationDoc.java b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationDoc.java index 45769e0fd59..8a6bc2217ba 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationDoc.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationDoc.java @@ -51,9 +51,9 @@ public class AuthorizationDoc extends BaseDoc { return idOf(entityUuid); } - public static String idOf(String projectUuid) { - requireNonNull(projectUuid, "projectUuid can't be null"); - return ID_PREFIX + projectUuid; + public static String idOf(String entityUuid) { + requireNonNull(entityUuid, "entityUuid can't be null"); + return ID_PREFIX + entityUuid; } public static String entityUuidOf(String id) { diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationScope.java b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationScope.java index 46f94bc1fa0..2a32cd0fa33 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationScope.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationScope.java @@ -31,11 +31,11 @@ import static org.sonar.server.permission.index.IndexAuthorizationConstants.TYPE @Immutable public final class AuthorizationScope { private final IndexMainType indexType; - private final Predicate projectPredicate; + private final Predicate entityPredicate; - public AuthorizationScope(IndexRelationType functionalType, Predicate projectPredicate) { + public AuthorizationScope(IndexRelationType functionalType, Predicate entityPredicate) { this.indexType = getAuthorizationIndexType(functionalType); - this.projectPredicate = requireNonNull(projectPredicate); + this.entityPredicate = requireNonNull(entityPredicate); } /** @@ -59,9 +59,9 @@ public final class AuthorizationScope { } /** - * Predicates that filters the projects to be involved in authorization. + * Predicates that filters the entities to be involved in authorization. */ - public Predicate getProjectPredicate() { - return projectPredicate; + public Predicate getEntityPredicate() { + return entityPredicate; } } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/NeedAuthorizationIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/NeedAuthorizationIndexer.java index a3dcc0ecdcb..94e65d410f1 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/NeedAuthorizationIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/permission/index/NeedAuthorizationIndexer.java @@ -19,9 +19,11 @@ */ package org.sonar.server.permission.index; +import org.sonar.server.es.EventIndexer; + /** * An {@link NeedAuthorizationIndexer} defines how - * a {@link org.sonar.server.es.ProjectIndexer} populates + * a {@link EventIndexer} populates * the type named {@link WebAuthorizationTypeSupport#TYPE_AUTHORIZATION}, which * is used to verify that a user can access to projects. */ diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/IndexersImplTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/IndexersImplTest.java new file mode 100644 index 00000000000..7c4b3dded89 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/es/IndexersImplTest.java @@ -0,0 +1,103 @@ +/* + * 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.es; + +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentTesting; +import org.sonar.db.es.EsQueueDto; +import org.sonar.db.project.ProjectDto; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.server.es.Indexers.BranchEvent.DELETION; +import static org.sonar.server.es.Indexers.EntityEvent.CREATION; + +public class IndexersImplTest { + + @Test + public void commitAndIndexOnEntityEvent_shouldCallIndexerWithSupportedItems() { + List items1 = List.of(EsQueueDto.create("fake/fake1", "P1"), EsQueueDto.create("fake/fake1", "P1")); + List items2 = List.of(EsQueueDto.create("fake/fake2", "P1")); + + EventIndexer indexer1 = mock(EventIndexer.class); + EventIndexer indexer2 = mock(EventIndexer.class); + + DbSession dbSession = mock(DbSession.class); + + IndexersImpl underTest = new IndexersImpl(indexer1, indexer2); + when(indexer1.prepareForRecoveryOnEntityEvent(dbSession, Set.of("P1"), CREATION)).thenReturn(items1); + when(indexer2.prepareForRecoveryOnEntityEvent(dbSession, Set.of("P1"), CREATION)).thenReturn(items2); + + underTest.commitAndIndexOnEntityEvent(dbSession, Set.of("P1"), CREATION); + + verify(indexer1).index(dbSession, items1); + verify(indexer2).index(dbSession, items2); + } + + @Test + public void commitAndIndexOnBranchEvent_shouldCallIndexerWithSupportedItems() { + List items1 = List.of(EsQueueDto.create("fake/fake1", "P1"), EsQueueDto.create("fake/fake1", "P1")); + List items2 = List.of(EsQueueDto.create("fake/fake2", "P1")); + + EventIndexer indexer1 = mock(EventIndexer.class); + EventIndexer indexer2 = mock(EventIndexer.class); + + DbSession dbSession = mock(DbSession.class); + + IndexersImpl underTest = new IndexersImpl(indexer1, indexer2); + when(indexer1.prepareForRecoveryOnBranchEvent(dbSession, Set.of("P1"), DELETION)).thenReturn(items1); + when(indexer2.prepareForRecoveryOnBranchEvent(dbSession, Set.of("P1"), DELETION)).thenReturn(items2); + + underTest.commitAndIndexOnBranchEvent(dbSession, Set.of("P1"), DELETION); + + verify(indexer1).index(dbSession, items1); + verify(indexer2).index(dbSession, items2); + } + + @Test + public void commitAndIndexEntities_shouldIndexAllUuids() { + EventIndexer indexer1 = mock(EventIndexer.class); + DbSession dbSession = mock(DbSession.class); + + IndexersImpl underTest = new IndexersImpl(indexer1); + + ProjectDto p1 = ComponentTesting.newProjectDto(); + underTest.commitAndIndexEntities(dbSession, Set.of(p1), CREATION); + + verify(indexer1).prepareForRecoveryOnEntityEvent(dbSession, Set.of(p1.getUuid()), CREATION); + } + + @Test + public void commitAndIndexBranches_shouldIndexAllBranchUuids() { + EventIndexer indexer1 = mock(EventIndexer.class); + DbSession dbSession = mock(DbSession.class); + + IndexersImpl underTest = new IndexersImpl(indexer1); + + BranchDto b1 = new BranchDto().setUuid("b1"); + underTest.commitAndIndexBranches(dbSession, Set.of(b1), DELETION); + verify(indexer1).prepareForRecoveryOnBranchEvent(dbSession, Set.of(b1.getUuid()), DELETION); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java deleted file mode 100644 index 8ed1a664a7c..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.es; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import org.junit.Test; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.server.es.ProjectIndexer.Cause; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -public class ProjectIndexersImplTest { - - @Test - public void commitAndIndex_indexes_project() { - ComponentDto project = ComponentTesting.newPublicProjectDto(); - - FakeIndexers underTest = new FakeIndexers(); - underTest.commitAndIndexComponents(mock(DbSession.class), singletonList(project), Cause.PROJECT_CREATION); - - assertThat(underTest.calls).containsExactly(project.uuid()); - } - - private static class FakeIndexers implements ProjectIndexers { - private final List calls = new ArrayList<>(); - - @Override - public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, Cause cause) { - calls.addAll(projectUuids); - } - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java deleted file mode 100644 index ce69963e127..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.es; - -import java.util.Collection; -import java.util.List; -import java.util.Set; -import org.junit.Test; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.es.EsQueueDto; -import org.sonar.db.project.ProjectDto; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -public class ProjectIndexersTest { - - @Test - public void commitAndIndexByProjectUuids_calls_indexer_with_only_its_supported_items() { - EsQueueDto item1a = EsQueueDto.create("fake/fake1", "P1"); - EsQueueDto item1b = EsQueueDto.create("fake/fake1", "P1"); - EsQueueDto item2 = EsQueueDto.create("fake/fake2", "P1"); - FakeIndexer indexer1 = new FakeIndexer(asList(item1a, item1b)); - FakeIndexer indexer2 = new FakeIndexer(singletonList(item2)); - DbSession dbSession = mock(DbSession.class); - - ProjectIndexersImpl underTest = new ProjectIndexersImpl(indexer1, indexer2); - underTest.commitAndIndexByProjectUuids(dbSession, singletonList("P1"), ProjectIndexer.Cause.PROJECT_CREATION); - - assertThat(indexer1.calledItems).containsExactlyInAnyOrder(item1a, item1b); - assertThat(indexer2.calledItems).containsExactlyInAnyOrder(item2); - } - - @Test - public void commitAndIndexByEntityUuids_calls_indexer_with_only_its_supported_items() { - ProjectIndexersTestImpl projectIndexers = new ProjectIndexersTestImpl(); - ProjectDto p1 = ComponentTesting.newProjectDto(); - ProjectDto p2 = ComponentTesting.newProjectDto(); - p1.setUuid("p1"); - p2.setUuid("p2"); - - projectIndexers.commitAndIndexEntities(null, List.of(p1, p2), ProjectIndexer.Cause.PROJECT_CREATION); - - assertThat(projectIndexers.cause).isEqualTo(ProjectIndexer.Cause.PROJECT_CREATION); - assertThat(projectIndexers.calledProjectUuids).containsOnly("p1", "p2"); - } - - private static class ProjectIndexersTestImpl implements ProjectIndexers { - - Collection calledProjectUuids; - ProjectIndexer.Cause cause; - - @Override - public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - this.calledProjectUuids = projectUuids; - this.cause = cause; - } - } - - private static class FakeIndexer implements ProjectIndexer { - - private final List items; - private Collection calledItems; - - private FakeIndexer(List items) { - this.items = items; - } - - @Override - public void indexOnStartup(Set uninitializedIndexTypes) { - throw new UnsupportedOperationException(); - } - - @Override - public Set getIndexTypes() { - throw new UnsupportedOperationException(); - } - - @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, Cause cause) { - return items; - } - - @Override - public IndexingResult index(DbSession dbSession, Collection items) { - this.calledItems = items; - return new IndexingResult(); - } - - @Override - public void indexOnAnalysis(String branchUuid) { - throw new UnsupportedOperationException(); - } - - @Override - public void indexOnAnalysis(String branchUuid, Set unchangedComponentUuids) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/StartupIndexerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/StartupIndexerTest.java index bc93ebf253e..4fcfb76add5 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/StartupIndexerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/es/StartupIndexerTest.java @@ -27,9 +27,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.sonar.server.es.StartupIndexer.Type.SYNCHRONOUS; public class StartupIndexerTest { - - - private StartupIndexer underTest = () -> null; + private final StartupIndexer underTest = () -> null; @Test public void getType() { @@ -40,14 +38,14 @@ public class StartupIndexerTest { public void triggerAsyncIndexOnStartup() { assertThatThrownBy(() -> underTest.triggerAsyncIndexOnStartup(Collections.emptySet())) .isInstanceOf(IllegalStateException.class) - .hasMessage("ASYNCHRONE StartupIndexer must implement initAsyncIndexOnStartup"); + .hasMessage("ASYNCHRONOUS StartupIndexer must implement initAsyncIndexOnStartup"); } @Test public void indexOnStartup() { assertThatThrownBy(() -> underTest.indexOnStartup(Collections.emptySet())) .isInstanceOf(IllegalStateException.class) - .hasMessage("SYNCHRONE StartupIndexer must implement indexOnStartup"); + .hasMessage("SYNCHRONOUS StartupIndexer must implement indexOnStartup"); } } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/permission/index/AuthorizationDocTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/permission/index/AuthorizationDocTest.java index 9eedb55c79b..8de943432a5 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/permission/index/AuthorizationDocTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/permission/index/AuthorizationDocTest.java @@ -49,7 +49,7 @@ public class AuthorizationDocTest { public void idOf_fails_with_NPE_if_argument_is_null() { assertThatThrownBy(() -> AuthorizationDoc.idOf(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("projectUuid can't be null"); + .hasMessage("entityUuid can't be null"); } @Test @@ -81,7 +81,7 @@ public class AuthorizationDocTest { assertThatThrownBy(() -> underTest.getId()) .isInstanceOf(NullPointerException.class) - .hasMessage("projectUuid can't be null"); + .hasMessage("entityUuid can't be null"); } @Test diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestIndexers.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestIndexers.java new file mode 100644 index 00000000000..7b0eb796aad --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestIndexers.java @@ -0,0 +1,65 @@ +/* + * 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.es; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import java.util.Collection; +import org.sonar.db.DbSession; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestIndexers implements Indexers { + + private final ListMultimap entityCalls = ArrayListMultimap.create(); + private final ListMultimap branchCalls = ArrayListMultimap.create(); + + @Override + public void commitAndIndexOnEntityEvent(DbSession dbSession, Collection entityUuids, EntityEvent cause) { + dbSession.commit(); + entityUuids.forEach(entityUuid -> entityCalls.put(entityUuid, cause)); + } + + @Override + public void commitAndIndexOnBranchEvent(DbSession dbSession, Collection branchUuids, BranchEvent cause) { + dbSession.commit(); + branchUuids.forEach(branchUuid -> branchCalls.put(branchUuid, cause)); + } + + public boolean hasBeenCalledForEntity(String entityUuid, EntityEvent expectedCause) { + assertThat(branchCalls.keySet()).isEmpty(); + return entityCalls.get(entityUuid).contains(expectedCause); + } + + public boolean hasBeenCalledForEntity(String projectUuid) { + assertThat(branchCalls.keySet()).isEmpty(); + return entityCalls.containsKey(projectUuid); + } + + public boolean hasBeenCalledForBranch(String branchUuid, BranchEvent expectedCause) { + assertThat(entityCalls.keySet()).isEmpty(); + return branchCalls.get(branchUuid).contains(expectedCause); + } + + public boolean hasBeenCalledForBranch(String branchUuid) { + assertThat(entityCalls.keySet()).isEmpty(); + return branchCalls.containsKey(branchUuid); + } +} diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java index 4338423164a..f3d025177c6 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java @@ -47,7 +47,6 @@ import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY; import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST; import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; -@ServerSide public class AsyncIssueIndexingImpl implements AsyncIssueIndexing { private static final Logger LOG = LoggerFactory.getLogger(AsyncIssueIndexingImpl.class); diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java index 3fc534a420a..4ea1228322c 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java @@ -35,21 +35,21 @@ import org.sonar.db.es.EsQueueDto; import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.BulkIndexer.Size; import org.sonar.server.es.EsClient; +import org.sonar.server.es.EventIndexer; import org.sonar.server.es.IndexType; +import org.sonar.server.es.Indexers; import org.sonar.server.es.IndexingResult; import org.sonar.server.es.OneToOneResilientIndexingListener; -import org.sonar.server.es.ProjectIndexer; import org.springframework.beans.factory.annotation.Autowired; import static java.util.Collections.emptyList; import static org.sonar.core.util.stream.MoreCollectors.toArrayList; /** - * Populates the types "authorization" of each index requiring project + * Populates the types "authorization" of each index requiring entity * authorization. */ -public class PermissionIndexer implements ProjectIndexer { - +public class PermissionIndexer implements EventIndexer { private final DbClient dbClient; private final EsClient esClient; private final Collection authorizationScopes; @@ -99,28 +99,20 @@ public class PermissionIndexer implements ProjectIndexer { } @Override - public void indexOnAnalysis(String branchUuid) { - // nothing to do, permissions don't change during an analysis - } - - @Override - public void indexOnAnalysis(String branchUuid, Set unchangedComponentUuids) { - // nothing to do, permissions don't change during an analysis - } - - @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { + public Collection prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection entityUuids, Indexers.EntityEvent cause) { return switch (cause) { - case MEASURE_CHANGE, PROJECT_KEY_UPDATE, PROJECT_TAGS_UPDATE -> + case PROJECT_KEY_UPDATE, PROJECT_TAGS_UPDATE -> // nothing to change. Measures, project key and tags are not part of this index emptyList(); - case PROJECT_CREATION, PROJECT_DELETION, PERMISSION_CHANGE -> insertIntoEsQueue(dbSession, projectUuids); - default -> - // defensive case - throw new IllegalStateException("Unsupported cause: " + cause); + case CREATION, DELETION, PERMISSION_CHANGE -> insertIntoEsQueue(dbSession, entityUuids); }; } + @Override + public Collection prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection branchUuids, Indexers.BranchEvent cause) { + return emptyList(); + } + private Collection insertIntoEsQueue(DbSession dbSession, Collection projectUuids) { List items = indexTypeByFormat.values().stream() .flatMap(indexType -> projectUuids.stream().map(projectUuid -> EsQueueDto.create(indexType.format(), AuthorizationDoc.idOf(projectUuid), null, projectUuid))) @@ -143,7 +135,7 @@ public class PermissionIndexer implements ProjectIndexer { bulkIndexer.start(); authorizations.stream() - .filter(scope.getProjectPredicate()) + .filter(scope.getEntityPredicate()) .map(dto -> AuthorizationDoc.fromDto(indexType, dto).toIndexRequest()) .forEach(bulkIndexer::add); @@ -179,7 +171,7 @@ public class PermissionIndexer implements ProjectIndexer { }); // the remaining references on entities that don't exist in db. They must - // be deleted from index. + // be deleted from the index. remainingEntityUuids.forEach(entityUuid -> bulkIndexers.forEach(bi -> { String authorizationDocId = AuthorizationDoc.idOf(entityUuid); bi.addDeletion(bi.getIndexType(), authorizationDocId, authorizationDocId); diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexSearchTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexSearchTest.java index 9f0414d5e4b..bc98d029d74 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexSearchTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexSearchTest.java @@ -52,7 +52,7 @@ public class ComponentIndexSearchTest { @Rule public ComponentTextSearchFeatureRule features = new ComponentTextSearchFeatureRule(); - private final ComponentIndexer indexer = new ComponentIndexer(db.getDbClient(), es.client()); + private final EntityDefinitionIndexer indexer = new EntityDefinitionIndexer(db.getDbClient(), es.client()); private final PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, indexer); private final ComponentIndex underTest = new ComponentIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE); diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java index 6755e90309f..7ccbf3d3f41 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java @@ -52,7 +52,7 @@ public abstract class ComponentIndexTest { @Rule public ComponentTextSearchFeatureRule features = new ComponentTextSearchFeatureRule(); - protected ComponentIndexer indexer = new ComponentIndexer(db.getDbClient(), es.client()); + protected EntityDefinitionIndexer indexer = new EntityDefinitionIndexer(db.getDbClient(), es.client()); protected ComponentIndex index = new ComponentIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE); protected PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, indexer); diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/FooIndexer.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/FooIndexer.java index b25b742318b..4e20afb0870 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/FooIndexer.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/FooIndexer.java @@ -19,21 +19,15 @@ */ package org.sonar.server.permission.index; -import com.google.common.collect.ImmutableSet; -import java.util.Collection; import java.util.Set; import org.elasticsearch.action.index.IndexRequest; -import org.sonar.db.DbSession; -import org.sonar.db.es.EsQueueDto; +import org.sonar.server.es.AnalysisIndexer; import org.sonar.server.es.BaseDoc; import org.sonar.server.es.EsClient; -import org.sonar.server.es.IndexType; -import org.sonar.server.es.IndexingResult; -import org.sonar.server.es.ProjectIndexer; import static org.sonar.server.permission.index.FooIndexDefinition.TYPE_FOO; -public class FooIndexer implements ProjectIndexer, NeedAuthorizationIndexer { +public class FooIndexer implements AnalysisIndexer, NeedAuthorizationIndexer { private static final AuthorizationScope AUTHORIZATION_SCOPE = new AuthorizationScope(TYPE_FOO, p -> true); @@ -59,11 +53,6 @@ public class FooIndexer implements ProjectIndexer, NeedAuthorizationIndexer { addToIndex(branchUuid, "baz"); } - @Override - public Collection prepareForRecovery(DbSession dbSession, Collection projectUuids, Cause cause) { - throw new UnsupportedOperationException(); - } - private void addToIndex(String projectUuid, String name) { FooDoc fooDoc = new FooDoc(projectUuid, name); esClient.index(new IndexRequest(TYPE_FOO.getMainType().getIndex().getName()) @@ -92,19 +81,4 @@ public class FooIndexer implements ProjectIndexer, NeedAuthorizationIndexer { } } - - @Override - public void indexOnStartup(Set uninitializedIndexTypes) { - throw new UnsupportedOperationException(); - } - - @Override - public Set getIndexTypes() { - return ImmutableSet.of(TYPE_FOO); - } - - @Override - public IndexingResult index(DbSession dbSession, Collection items) { - throw new UnsupportedOperationException(); - } } diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java index be278b496c0..afbcfbc64b0 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java @@ -34,8 +34,8 @@ import org.sonar.db.user.UserDto; import org.sonar.server.es.EsTester; import org.sonar.server.es.IndexType; import org.sonar.server.es.IndexType.IndexMainType; +import org.sonar.server.es.Indexers.EntityEvent; import org.sonar.server.es.IndexingResult; -import org.sonar.server.es.ProjectIndexer; import org.sonar.server.tester.UserSessionRule; import static java.util.Arrays.asList; @@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.USER; -import static org.sonar.server.es.ProjectIndexer.Cause.PERMISSION_CHANGE; +import static org.sonar.server.es.Indexers.EntityEvent.PERMISSION_CHANGE; import static org.sonar.server.permission.index.IndexAuthorizationConstants.TYPE_AUTHORIZATION; public class PermissionIndexerTest { @@ -98,7 +98,7 @@ public class PermissionIndexerTest { // Simulate a indexation issue db.getDbClient().purgeDao().deleteProject(db.getSession(), project1.getUuid(), PROJECT, project1.getName(), project1.getKey()); - underTest.prepareForRecovery(db.getSession(), asList(project1.getUuid()), ProjectIndexer.Cause.PROJECT_DELETION); + underTest.prepareForRecoveryOnEntityEvent(db.getSession(), asList(project1.getUuid()), EntityEvent.DELETION); assertThat(db.countRowsOfTable(db.getSession(), "es_queue")).isOne(); Collection esQueueDtos = db.getDbClient().esQueueDao().selectForRecovery(db.getSession(), Long.MAX_VALUE, 2); @@ -246,21 +246,11 @@ public class PermissionIndexerTest { verifyAuthorized(projectOnOrg1, user); } - @Test - public void indexOnAnalysis_does_nothing_because_CE_does_not_touch_permissions() { - ProjectDto project = createAndIndexPublicProject(); - - underTest.indexOnAnalysis(project.getUuid()); - - assertThatAuthIndexHasSize(0); - verifyAnyoneNotAuthorized(project); - } - @Test public void permissions_are_not_updated_on_project_tags_update() { ProjectDto project = createAndIndexPublicProject(); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_TAGS_UPDATE); + indexPermissions(project, EntityEvent.PROJECT_TAGS_UPDATE); assertThatAuthIndexHasSize(0); verifyAnyoneNotAuthorized(project); @@ -270,7 +260,7 @@ public class PermissionIndexerTest { public void permissions_are_not_updated_on_project_key_update() { ProjectDto project = createAndIndexPublicProject(); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_TAGS_UPDATE); + indexPermissions(project, EntityEvent.PROJECT_TAGS_UPDATE); assertThatAuthIndexHasSize(0); verifyAnyoneNotAuthorized(project); @@ -282,7 +272,7 @@ public class PermissionIndexerTest { UserDto user = db.users().insertUser(); db.users().insertProjectPermissionOnUser(user, USER, project); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_CREATION); + indexPermissions(project, EntityEvent.CREATION); assertThatAuthIndexHasSize(1); verifyAuthorized(project, user); @@ -294,7 +284,7 @@ public class PermissionIndexerTest { UserDto user1 = db.users().insertUser(); UserDto user2 = db.users().insertUser(); db.users().insertProjectPermissionOnUser(user1, USER, project); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_CREATION); + indexPermissions(project, EntityEvent.CREATION); verifyAuthorized(project, user1); verifyNotAuthorized(project, user2); @@ -310,11 +300,11 @@ public class PermissionIndexerTest { ProjectDto project = createAndIndexPrivateProject(); UserDto user = db.users().insertUser(); db.users().insertProjectPermissionOnUser(user, USER, project); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_CREATION); + indexPermissions(project, EntityEvent.CREATION); verifyAuthorized(project, user); db.getDbClient().purgeDao().deleteProject(db.getSession(), project.getUuid(), PROJECT, project.getUuid(), project.getKey()); - indexPermissions(project, ProjectIndexer.Cause.PROJECT_DELETION); + indexPermissions(project, EntityEvent.DELETION); verifyNotAuthorized(project, user); assertThatAuthIndexHasSize(0); @@ -392,9 +382,9 @@ public class PermissionIndexerTest { return userSession; } - private IndexingResult indexPermissions(EntityDto entity, ProjectIndexer.Cause cause) { + private IndexingResult indexPermissions(EntityDto entity, EntityEvent cause) { DbSession dbSession = db.getSession(); - Collection items = underTest.prepareForRecovery(dbSession, singletonList(entity.getUuid()), cause); + Collection items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(entity.getUuid()), cause); dbSession.commit(); return underTest.index(dbSession, items); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java index 3d655419222..b532fdf0a52 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java @@ -43,7 +43,7 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -92,7 +92,7 @@ public class ImportAzureProjectActionIT { private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, - mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), + mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(), defaultBranchNameResolver, true); private final Encryption encryption = mock(Encryption.class); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java index a25e53acd6d..ba9dc340a71 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java @@ -43,7 +43,7 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -92,7 +92,7 @@ public class ImportBitbucketCloudRepoActionIT { DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, - mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), + mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(), defaultBranchNameResolver, true); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java index 3ac432bb989..61e41602355 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java @@ -19,7 +19,6 @@ */ package org.sonar.server.almintegration.ws.bitbucketserver; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -48,7 +47,7 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -100,7 +99,7 @@ public class ImportBitbucketServerProjectActionIT { private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, - mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), + mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(), defaultBranchNameResolver, true); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java index 52ac7f05a48..ec75c90e2a5 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java @@ -41,7 +41,7 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; @@ -87,7 +87,7 @@ public class ImportGithubProjectActionIT { private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, - mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), + mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(), defaultBranchNameResolver, true); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java index a2748b8af42..7c81d1c26f2 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java @@ -41,7 +41,7 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.permission.PermissionTemplateService; @@ -83,7 +83,7 @@ public class ImportGitLabProjectActionIT { DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, - mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), + mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(), defaultBranchNameResolver, true); private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class); @@ -137,7 +137,7 @@ public class ImportGitLabProjectActionIT { assertThat(projectDto).isPresent(); assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent(); - assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid())) + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid())) .isPresent() .get() .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid) @@ -252,7 +252,6 @@ public class ImportGitLabProjectActionIT { .containsExactlyInAnyOrder(tuple(DEFAULT_MAIN_BRANCH_NAME, true)); } - @Test public void import_project_without_NCD() { UserDto user = db.users().insertUser(); @@ -284,7 +283,6 @@ public class ImportGitLabProjectActionIT { assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent(); } - private Project getGitlabProject() { return new Project(randomAlphanumeric(5), randomAlphanumeric(5)); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java index 24a66e06610..040aa8cfef4 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java @@ -51,9 +51,9 @@ public class DeleteActionIT { @Rule public DbTester db = DbTester.create(System2.INSTANCE, true); - private ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class); - private ComponentFinder componentFinder = TestComponentFinder.from(db); - private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); + private final ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class); + private final ComponentFinder componentFinder = TestComponentFinder.from(db); + private final ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java index 24358548f74..f2a7f498dd7 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java @@ -182,7 +182,7 @@ public class BranchReportSubmitterIT { ComponentCreationData componentCreationData = mock(ComponentCreationData.class); when(componentCreationData.mainBranchComponent()) .thenAnswer((Answer) invocation -> db.components().insertPrivateProject(nonExistingProject).getMainBranchComponent()); - when(componentUpdater.createWithoutCommit(any(), any(), eq(user.getUuid()), eq(user.getLogin()), any())) + when(componentUpdater.createWithoutCommit(any(), any(), eq(user.getUuid()), eq(user.getLogin()))) .thenReturn(componentCreationData); when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(nonExistingProject), any())).thenReturn(createdBranch); when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(nonExistingProject.getKey()))).thenReturn(true); @@ -197,7 +197,7 @@ public class BranchReportSubmitterIT { verify(branchSupportDelegate).createBranchComponent(any(DbSession.class), same(componentKey), eq(nonExistingProject), eq(exitingProjectMainBranch)); verifyNoMoreInteractions(branchSupportDelegate); verifyQueueSubmit(nonExistingProject, createdBranch, user, randomCharacteristics, taskUuid); - verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(nonExistingProject)); + verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(componentCreationData)); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java index 4cccc2498eb..16b61c3698f 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java @@ -41,7 +41,7 @@ import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.favorite.FavoriteUpdater; @@ -87,7 +87,7 @@ public class ReportSubmitterIT { private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); private final CeQueue queue = mock(CeQueueImpl.class); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); + private final TestIndexers projectIndexers = new TestIndexers(); private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService, diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java index 4590889a678..97e2095c1f3 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java @@ -19,10 +19,9 @@ */ package org.sonar.server.component; +import java.util.List; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -36,15 +35,18 @@ import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.webhook.WebhookDto; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.Indexers.BranchEvent; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.sonar.server.es.Indexers.EntityEvent.DELETION; public class ComponentCleanerServiceIT { @@ -55,19 +57,20 @@ public class ComponentCleanerServiceIT { private final DbClient dbClient = db.getDbClient(); private final DbSession dbSession = db.getSession(); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private final ResourceTypes mockResourceTypes = mock(ResourceTypes.class); - private final ComponentCleanerService underTest = new ComponentCleanerService(dbClient, mockResourceTypes, projectIndexers); + private final Indexers indexers = mock(Indexers.class); + private final ComponentCleanerService underTest = new ComponentCleanerService(dbClient, indexers); @Test public void delete_project_from_db_and_index() { DbData data1 = insertProjectData(); DbData data2 = insertProjectData(); - underTest.delete(dbSession, data1.project); + underTest.deleteEntity(dbSession, data1.project); assertNotExists(data1); assertExists(data2); + verify(indexers).commitAndIndexEntities(any(), eq(List.of(data1.project)), eq(DELETION)); + verifyNoMoreInteractions(indexers); } @Test @@ -82,6 +85,10 @@ public class ComponentCleanerServiceIT { assertNotExists(data1); assertNotExists(data2); assertExists(data3); + verify(indexers).commitAndIndexEntities(any(), eq(List.of(data1.project)), eq(DELETION)); + verify(indexers).commitAndIndexEntities(any(), eq(List.of(data2.project)), eq(DELETION)); + + verifyNoMoreInteractions(indexers); } @Test @@ -91,9 +98,7 @@ public class ComponentCleanerServiceIT { ProjectData projectData2 = db.components().insertPublicProject(); ComponentDto componentDto2 = projectData2.getMainBranchComponent(); - mockResourceTypeAsValidProject(); - - underTest.delete(dbSession, projectData1.getProjectDto()); + underTest.deleteEntity(dbSession, projectData1.getProjectDto()); dbSession.commit(); assertNotExists(componentDto1); @@ -101,12 +106,9 @@ public class ComponentCleanerServiceIT { } @Test - public void fail_with_IAE_if_project_non_deletable() { - ProjectData projectData = db.components().insertPublicProject(); - mockResourceTypeAsNonDeletable(); - dbSession.commit(); - ProjectDto project = projectData.getProjectDto(); - assertThatThrownBy(() -> underTest.delete(dbSession, project)) + public void fail_with_IAE_if_deleting_subview() { + PortfolioDto portfolio = new PortfolioDto().setParentUuid("parent").setRootUuid("root").setUuid("uuid"); + assertThatThrownBy(() -> underTest.deleteEntity(dbSession, portfolio)) .withFailMessage("Only projects can be deleted") .isInstanceOf(IllegalArgumentException.class); } @@ -119,7 +121,7 @@ public class ComponentCleanerServiceIT { ProjectData app1 = insertApplication(data2.project); ProjectData app2 = insertApplication(data3.project); - underTest.delete(dbSession, app1.getProjectDto()); + underTest.deleteEntity(dbSession, app1.getProjectDto()); dbSession.commit(); assertProjectOrAppExists(app1.getProjectDto(), app1.getMainBranchDto(), false); @@ -127,20 +129,21 @@ public class ComponentCleanerServiceIT { assertExists(data1); assertExists(data2); assertExists(data3); + verify(indexers).commitAndIndexEntities(any(), eq(List.of(app1.getProjectDto())), eq(DELETION)); + verifyNoMoreInteractions(indexers); } @Test public void delete_WhenDeletingPortfolio_ShouldDeleteComponents() { PortfolioDto portfolioDto1 = db.components().insertPrivatePortfolioDto(); PortfolioDto portfolioDto2 = db.components().insertPrivatePortfolioDto(); - mockResourceTypeAsValidProject(); - underTest.delete(dbSession, portfolioDto1); + underTest.deleteEntity(dbSession, portfolioDto1); assertThat(dbClient.componentDao().selectByUuid(dbSession, portfolioDto1.getUuid())).isEmpty(); assertThat(dbClient.componentDao().selectByUuid(dbSession, portfolioDto2.getUuid())).isPresent(); - assertThat(projectIndexers.hasBeenCalled(portfolioDto1.getUuid(), PROJECT_DELETION)).isTrue(); - + verify(indexers).commitAndIndexEntities(any(), eq(List.of(portfolioDto1)), eq(DELETION)); + verifyNoMoreInteractions(indexers); } private ProjectData insertApplication(ProjectDto project) { @@ -165,6 +168,8 @@ public class ComponentCleanerServiceIT { assertThat(dbClient.componentDao().selectByUuid(dbSession, otherBranch.getUuid())).isEmpty(); assertThat(dbClient.branchDao().selectByUuid(dbSession, otherBranch.getUuid())).isEmpty(); + verify(indexers).commitAndIndexBranches(any(), eq(List.of(otherBranch)), eq(BranchEvent.DELETION)); + verifyNoMoreInteractions(indexers); } @Test @@ -179,6 +184,7 @@ public class ComponentCleanerServiceIT { assertExists(data1); assertExists(data2); assertExists(data3); + verifyNoMoreInteractions(indexers); } @Test @@ -196,8 +202,6 @@ public class ComponentCleanerServiceIT { ProjectDto projectDto1 = dbClient.projectDao().selectByUuid(dbSession, project1.getUuid()).get(); ProjectDto projectDto2 = dbClient.projectDao().selectByUuid(dbSession, project2.getUuid()).get(); - mockResourceTypeAsValidProject(); - underTest.delete(dbSession, asList(projectDto1, projectDto2)); assertThat(db.countRowsOfTable(db.getSession(), "webhooks")).isOne(); @@ -211,30 +215,15 @@ public class ComponentCleanerServiceIT { RuleDto rule = db.rules().insert(); IssueDto issue = db.issues().insert(rule, mainBranch, mainBranch); SnapshotDto analysis = db.components().insertSnapshot(mainBranch); - mockResourceTypeAsValidProject(); return new DbData(projectData.getProjectDto(), projectData.getMainBranchDto(), analysis, issue); } - private void mockResourceTypeAsValidProject() { - ResourceType resourceType = mock(ResourceType.class); - when(resourceType.getBooleanProperty(anyString())).thenReturn(true); - when(mockResourceTypes.get(anyString())).thenReturn(resourceType); - } - - private void mockResourceTypeAsNonDeletable() { - ResourceType resourceType = mock(ResourceType.class); - when(resourceType.getBooleanProperty("deletable")).thenReturn(false); - when(mockResourceTypes.get(anyString())).thenReturn(resourceType); - } - private void assertNotExists(DbData data) { assertDataInDb(data, false); - assertThat(projectIndexers.hasBeenCalled(data.project.getUuid(), PROJECT_DELETION)).isTrue(); } private void assertExists(DbData data) { assertDataInDb(data, true); - assertThat(projectIndexers.hasBeenCalled(data.project.getUuid(), PROJECT_DELETION)).isFalse(); } private void assertDataInDb(DbData data, boolean exists) { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentServiceUpdateKeyIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentServiceUpdateKeyIT.java index e9d88885b27..cebfeaff1f7 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentServiceUpdateKeyIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentServiceUpdateKeyIT.java @@ -30,13 +30,12 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.project.ProjectDto; import org.sonar.db.pushevent.PushEventDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.tester.UserSessionRule; @@ -56,7 +55,7 @@ public class ComponentServiceUpdateKeyIT { private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); + private TestIndexers projectIndexers = new TestIndexers(); private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexers, projectLifeCycleListeners); @@ -84,7 +83,7 @@ public class ComponentServiceUpdateKeyIT { assertThat(dbClient.componentDao().selectByKey(dbSession, inactiveFile.getKey())).isEmpty(); - assertThat(projectIndexers.hasBeenCalled(project.getUuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); + assertThat(projectIndexers.hasBeenCalledForEntity(project.getUuid(), Indexers.EntityEvent.PROJECT_KEY_UPDATE)).isTrue(); Deque pushEvents = db.getDbClient().pushEventDao().selectChunkByProjectUuids(dbSession, Set.of(project.getUuid()), 0L, "id", 20); @@ -109,7 +108,7 @@ public class ComponentServiceUpdateKeyIT { dbSession.commit(); assertComponentKeyHasBeenUpdated(provisionedProject.getKey(), "provisionedProject2"); - assertThat(projectIndexers.hasBeenCalled(provisionedProject.getUuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); + assertThat(projectIndexers.hasBeenCalledForEntity(provisionedProject.getUuid(), Indexers.EntityEvent.PROJECT_KEY_UPDATE)).isTrue(); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java index 854e097b114..807b8b01a6e 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java @@ -36,14 +36,13 @@ import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.l18n.I18nRule; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.DefaultBranchNameResolver; -import org.sonar.server.project.Project; import static java.util.stream.IntStream.rangeClosed; import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; @@ -71,7 +70,7 @@ public class ComponentUpdaterIT { @Rule public final I18nRule i18n = new I18nRule().put("qualifier.TRK", "Project"); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); + private final TestIndexers projectIndexers = new TestIndexers(); private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); @@ -108,7 +107,7 @@ public class ComponentUpdaterIT { assertThat(loaded.getCreatedAt()).isNotNull(); assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY)).isPresent(); - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); + assertThat(projectIndexers.hasBeenCalledForEntity(returned.projectDto().getUuid(), Indexers.EntityEvent.CREATION)).isTrue(); Optional branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.mainBranchComponent().uuid()); assertThat(branch).isPresent(); @@ -134,21 +133,6 @@ public class ComponentUpdaterIT { assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo("main-branch-global"); } - @Test - public void create_project_with_main_branch_param() { - String customBranchName = "main-branch-custom"; - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setPrivate(true) - .build(); - - ComponentDto returned = underTest.create(db.getSession(), project, null, null, customBranchName).mainBranchComponent(); - - Optional branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.branchUuid()); - assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo(customBranchName); - } - @Test public void persist_private_flag_true_when_creating_project() { NewComponent project = NewComponent.newComponentBuilder() @@ -187,7 +171,7 @@ public class ComponentUpdaterIT { assertThat(loaded.getKey()).isEqualTo("view-key"); assertThat(loaded.name()).isEqualTo("view-name"); assertThat(loaded.qualifier()).isEqualTo("VW"); - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); + assertThat(projectIndexers.hasBeenCalledForEntity(loaded.uuid(), Indexers.EntityEvent.CREATION)).isTrue(); Optional branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); assertThat(branch).isNotPresent(); } @@ -202,11 +186,11 @@ public class ComponentUpdaterIT { ComponentCreationData returned = underTest.create(db.getSession(), application, null, null); - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.mainBranchComponent().uuid()); + ProjectDto loaded = db.getDbClient().projectDao().selectByUuid(db.getSession(), returned.projectDto().getUuid()).get(); assertThat(loaded.getKey()).isEqualTo("app-key"); - assertThat(loaded.name()).isEqualTo("app-name"); - assertThat(loaded.qualifier()).isEqualTo("APP"); - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); + assertThat(loaded.getName()).isEqualTo("app-name"); + assertThat(loaded.getQualifier()).isEqualTo("APP"); + assertThat(projectIndexers.hasBeenCalledForEntity(loaded.getUuid(), Indexers.EntityEvent.CREATION)).isTrue(); Optional branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.mainBranchComponent().uuid()); assertThat(branch).isPresent(); assertThat(branch.get().getKey()).isEqualTo(DEFAULT_MAIN_BRANCH_NAME); @@ -398,7 +382,7 @@ public class ComponentUpdaterIT { public void create_createsComponentWithMasterBranchName() { String componentNameAndKey = "createApplicationOrPortfolio"; ComponentDto app = underTest.create(db.getSession(), NewComponent.newComponentBuilder().setName(componentNameAndKey) - .setKey(componentNameAndKey).setQualifier("APP").build(), null, null, null).mainBranchComponent(); + .setKey(componentNameAndKey).setQualifier("APP").build(), null, null).mainBranchComponent(); Optional branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), app.branchUuid()); assertThat(branch).isPresent(); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchActionIT.java index de0af82b8de..c89ff22122e 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchActionIT.java @@ -22,7 +22,6 @@ package org.sonar.server.component.ws; import com.google.common.base.Joiner; import java.util.ArrayList; import java.util.List; -import org.eclipse.jface.text.projection.ProjectionDocument; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -36,7 +35,7 @@ import org.sonar.db.component.ResourceTypesRule; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.index.ComponentIndex; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.component.ws.SearchAction.SearchRequest; import org.sonar.server.es.EsTester; import org.sonar.server.l18n.I18nRule; @@ -77,7 +76,7 @@ public class SearchActionIT { private final I18nRule i18n = new I18nRule(); private final ResourceTypesRule resourceTypes = new ResourceTypesRule(); - private final ComponentIndexer indexer = new ComponentIndexer(db.getDbClient(), es.client()); + private final EntityDefinitionIndexer indexer = new EntityDefinitionIndexer(db.getDbClient(), es.client()); private final PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, indexer); private final ComponentIndex index = new ComponentIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java index 75db28e67ba..c50e4ed2ed6 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java @@ -1397,7 +1397,7 @@ public class SearchProjectsActionIT { authorizationIndexerTester.allowOnlyAnyone(r.getResultObject()); } }; - db.getDbClient().entityDao().scrollForIndexing(dbSession, null, rh); + db.getDbClient().entityDao().scrollForIndexing(dbSession, rh); } private ComponentDto insertPortfolio() { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java index 2408c613180..a88b8c3316c 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java @@ -38,7 +38,7 @@ import org.sonar.db.component.ProjectData; import org.sonar.db.component.ResourceTypesRule; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.index.ComponentIndex; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.es.EsTester; import org.sonar.server.favorite.FavoriteFinder; import org.sonar.server.permission.index.PermissionIndexerTester; @@ -89,11 +89,11 @@ public class SuggestionsActionIT { public final UserSessionRule userSessionRule = UserSessionRule.standalone(); public final ResourceTypesRule resourceTypes = new ResourceTypesRule(); - private final ComponentIndexer componentIndexer = new ComponentIndexer(db.getDbClient(), es.client()); + private final EntityDefinitionIndexer entityDefinitionIndexer = new EntityDefinitionIndexer(db.getDbClient(), es.client()); private final FavoriteFinder favoriteFinder = mock(FavoriteFinder.class); private final ComponentIndex index = new ComponentIndex(es.client(), new WebAuthorizationTypeSupport(userSessionRule), System2.INSTANCE); private final SuggestionsAction underTest = new SuggestionsAction(db.getDbClient(), index, favoriteFinder, userSessionRule, resourceTypes); - private final PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, componentIndexer); + private final PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, entityDefinitionIndexer); private final WsActionTester ws = new WsActionTester(underTest); @Before @@ -134,7 +134,7 @@ public class SuggestionsActionIT { public void test_example_json_response() { ProjectDto project1 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarqube").setName("SonarSource :: SonarQube")).getProjectDto(); ProjectDto project2 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarlint").setName("SonarSource :: SonarLint")).getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project1); authorizationIndexerTester.allowOnlyAnyone(project2); @@ -152,7 +152,7 @@ public class SuggestionsActionIT { public void suggestions_without_query_should_contain_recently_browsed() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); SuggestionsWsResponse response = ws.newRequest() @@ -177,7 +177,7 @@ public class SuggestionsActionIT { public void suggestions_without_query_should_contain_recently_browsed_public_project() { ProjectDto project = db.components().insertPublicProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") @@ -201,7 +201,7 @@ public class SuggestionsActionIT { public void suggestions_without_query_should_not_contain_recently_browsed_without_permission() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") @@ -218,7 +218,7 @@ public class SuggestionsActionIT { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); SuggestionsWsResponse response = ws.newRequest() @@ -243,7 +243,7 @@ public class SuggestionsActionIT { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") @@ -259,7 +259,7 @@ public class SuggestionsActionIT { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); SuggestionsWsResponse response = ws.newRequest() @@ -284,7 +284,7 @@ public class SuggestionsActionIT { public void suggestions_without_query_should_not_contain_matches_that_are_neither_favorites_nor_recently_browsed() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); SuggestionsWsResponse response = ws.newRequest() @@ -306,7 +306,7 @@ public class SuggestionsActionIT { ProjectDto project4 = db.components().insertPrivateProject(p -> p.setName("Delta")).getProjectDto(); doReturn(asList(project4, project2)).when(favoriteFinder).list(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project1); userSessionRule.addProjectPermission(USER, project2); userSessionRule.addProjectPermission(USER, project3); @@ -331,7 +331,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_return_empty_qualifiers() { ProjectData project = db.components().insertPrivateProject(); - componentIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); + entityDefinitionIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); userSessionRule.addProjectPermission(USER, project.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -349,7 +349,7 @@ public class SuggestionsActionIT { public void suggestions_should_filter_allowed_qualifiers() { resourceTypes.setAllQualifiers(PROJECT, FILE, UNIT_TEST_FILE); ProjectData project = db.components().insertPrivateProject(); - componentIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); + entityDefinitionIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); userSessionRule.addProjectPermission(USER, project.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -366,7 +366,7 @@ public class SuggestionsActionIT { public void exact_match_in_one_qualifier() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); SuggestionsWsResponse response = ws.newRequest() @@ -391,7 +391,7 @@ public class SuggestionsActionIT { public void should_not_return_suggestion_on_non_existing_project() { ProjectDto project = db.components().insertPrivateProject().getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); db.getDbClient().purgeDao().deleteProject(db.getSession(), project.getUuid(), PROJECT, project.getName(), project.getKey()); @@ -412,7 +412,7 @@ public class SuggestionsActionIT { public void must_not_search_if_no_valid_tokens_are_provided() { ProjectDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); SuggestionsWsResponse response = ws.newRequest() @@ -438,7 +438,7 @@ public class SuggestionsActionIT { public void should_warn_about_short_inputs_but_return_results_based_on_other_terms() { ProjectDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getProjectDto(); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); SuggestionsWsResponse response = ws.newRequest() @@ -456,7 +456,7 @@ public class SuggestionsActionIT { @Test public void should_contain_component_names() { ProjectData project1 = db.components().insertPrivateProject(p -> p.setName("Project1")); - componentIndexer.indexOnAnalysis(project1.getMainBranchDto().getUuid()); + entityDefinitionIndexer.indexOnAnalysis(project1.getMainBranchDto().getUuid()); authorizationIndexerTester.allowOnlyAnyone(project1.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -476,7 +476,7 @@ public class SuggestionsActionIT { ComponentDto project = projectData.getMainBranchComponent(); ComponentDto file1 = newFileDto(project).setName("File1"); ComponentDto file2 = newFileDto(project).setName("File2"); - componentIndexer.indexOnAnalysis(project.branchUuid()); + entityDefinitionIndexer.indexOnAnalysis(project.branchUuid()); authorizationIndexerTester.allowOnlyAnyone(projectData.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -497,8 +497,8 @@ public class SuggestionsActionIT { ProjectData nonFavouriteProject = db.components().insertPublicProject(p -> p.setName("Project2")); doReturn(singletonList(favouriteProject.getProjectDto())).when(favoriteFinder).list(); - componentIndexer.indexOnAnalysis(favouriteProject.getMainBranchDto().getUuid()); - componentIndexer.indexOnAnalysis(nonFavouriteProject.getMainBranchDto().getUuid()); + entityDefinitionIndexer.indexOnAnalysis(favouriteProject.getMainBranchDto().getUuid()); + entityDefinitionIndexer.indexOnAnalysis(nonFavouriteProject.getMainBranchDto().getUuid()); authorizationIndexerTester.allowOnlyAnyone(favouriteProject.getProjectDto(), nonFavouriteProject.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -515,7 +515,7 @@ public class SuggestionsActionIT { @Test public void should_return_empty_qualifiers() { ProjectData project = db.components().insertPrivateProject(); - componentIndexer.indexOnAnalysis(project.getMainBranchComponent().uuid()); + entityDefinitionIndexer.indexOnAnalysis(project.getMainBranchComponent().uuid()); authorizationIndexerTester.allowOnlyAnyone(project.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() @@ -541,7 +541,7 @@ public class SuggestionsActionIT { ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "path").setName(query)); ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project, dir).setName(query)); ComponentDto test = db.components().insertComponent(ComponentTesting.newFileDto(project, dir).setName(query).setQualifier(UNIT_TEST_FILE)); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(projectData.getProjectDto()); authorizationIndexerTester.allowOnlyAnyone(view); authorizationIndexerTester.allowOnlyAnyone(appData.getProjectDto()); @@ -565,7 +565,7 @@ public class SuggestionsActionIT { ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); authorizationIndexerTester.allowOnlyAnyone(project); ComponentDto branch = db.components().insertProjectBranch(project); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); SuggestionsWsResponse response = ws.newRequest() @@ -684,7 +684,7 @@ public class SuggestionsActionIT { .mapToObj(i -> db.components().insertPublicProject(p -> p.setName(namePrefix + i)).getProjectDto()) .collect(Collectors.toList()); - componentIndexer.indexAll(); + entityDefinitionIndexer.indexAll(); projects.forEach(authorizationIndexerTester::allowOnlyAnyone); TestRequest request = ws.newRequest() diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/live/LiveMeasureComputerImplIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/live/LiveMeasureComputerImplIT.java index ca207f02f38..7573ec46429 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/live/LiveMeasureComputerImplIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/live/LiveMeasureComputerImplIT.java @@ -40,7 +40,7 @@ import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.metric.MetricDto; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.qualitygate.EvaluatedQualityGate; import org.sonar.server.qualitygate.QualityGate; import org.sonar.server.qualitygate.changeevent.QGChangeEvent; @@ -61,7 +61,7 @@ public class LiveMeasureComputerImplIT { @Rule public DbTester db = DbTester.create(true); - private final TestProjectIndexers projectIndexer = new TestProjectIndexers(); + private final TestIndexers projectIndexer = new TestIndexers(); private MetricDto metric1; private MetricDto metric2; private ComponentDto project; diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/PermissionTemplateServiceIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/PermissionTemplateServiceIT.java index 10b339c08f3..c8bd27bb5a9 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/PermissionTemplateServiceIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/PermissionTemplateServiceIT.java @@ -37,8 +37,8 @@ import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.TemplateMatchingKeyException; import org.sonar.server.tester.UserSessionRule; @@ -60,8 +60,8 @@ public class PermissionTemplateServiceIT { private final UserSessionRule userSession = UserSessionRule.standalone(); private final PermissionTemplateDbTester templateDb = dbTester.permissionTemplates(); private final DbSession session = dbTester.getSession(); - private final ProjectIndexers projectIndexers = new TestProjectIndexers(); - private final PermissionTemplateService underTest = new PermissionTemplateService(dbTester.getDbClient(), projectIndexers, userSession, defaultTemplatesResolver, + private final Indexers indexers = new TestIndexers(); + private final PermissionTemplateService underTest = new PermissionTemplateService(dbTester.getDbClient(), indexers, userSession, defaultTemplatesResolver, new SequenceUuidFactory()); @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/BasePermissionWsIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/BasePermissionWsIT.java index 7e2e5c54315..a2e049c1dc7 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/BasePermissionWsIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/BasePermissionWsIT.java @@ -31,7 +31,7 @@ import org.sonar.db.component.ResourceTypesRule; import org.sonar.db.permission.template.PermissionTemplateDto; import org.sonar.server.component.ComponentFinder; import org.sonar.server.es.EsTester; -import org.sonar.server.es.ProjectIndexersImpl; +import org.sonar.server.es.IndexersImpl; import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.permission.UserPermissionChanger; @@ -82,7 +82,7 @@ public abstract class BasePermissionWsIT { protected PermissionUpdater newPermissionUpdater() { return new PermissionUpdater( - new ProjectIndexersImpl(new PermissionIndexer(db.getDbClient(), es.client())), + new IndexersImpl(new PermissionIndexer(db.getDbClient(), es.client())), new UserPermissionChanger(db.getDbClient(), new SequenceUuidFactory()), new GroupPermissionChanger(db.getDbClient(), new SequenceUuidFactory())); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java index 28015aec9c7..6a065c29e14 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java @@ -34,7 +34,7 @@ import org.sonar.db.permission.template.PermissionTemplateDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -70,7 +70,7 @@ public class ApplyTemplateActionIT extends BasePermissionWsIT> projectsCaptor = ArgumentCaptor.forClass(Set.class); verify(projectLifeCycleListeners).onProjectsDeleted(projectsCaptor.capture()); assertThat(projectsCaptor.getValue()).hasSize(1_000); @@ -255,7 +255,7 @@ public class BulkDeleteActionIT { doNothing() .doThrow(expectedException) .when(componentCleanerService) - .delete(any(), any(ProjectDto.class)); + .deleteEntity(any(), any(ProjectDto.class)); try { ws.newRequest() @@ -314,7 +314,7 @@ public class BulkDeleteActionIT { private void verifyEntityDeleted(EntityDto... entities) { ArgumentCaptor argument = ArgumentCaptor.forClass(EntityDto.class); - verify(componentCleanerService, times(entities.length)).delete(any(DbSession.class), argument.capture()); + verify(componentCleanerService, times(entities.length)).deleteEntity(any(DbSession.class), argument.capture()); for (EntityDto entity : entities) { assertThat(argument.getAllValues()).extracting(EntityDto::getUuid).contains(entity.getUuid()); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java index 01562458c77..e0a4536f168 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java @@ -38,7 +38,8 @@ import org.sonar.db.newcodeperiod.NewCodePeriodDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.favorite.FavoriteUpdater; @@ -96,12 +97,12 @@ public class CreateActionIT { private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); + private final TestIndexers projectIndexers = new TestIndexers(); private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class); + private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class); - private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider); + private final NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider); private final WsActionTester ws = new WsActionTester( new CreateAction( db.getDbClient(), userSession, @@ -133,9 +134,11 @@ public class CreateActionIT { .extracting(ComponentDto::getKey, ComponentDto::name, ComponentDto::qualifier, ComponentDto::scope, ComponentDto::isPrivate) .containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "PRJ", false); - assertThat(db.getDbClient().branchDao().selectByUuid(db.getSession(), component.branchUuid()).get()) + BranchDto branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), component.branchUuid()).get(); + assertThat(branch) .extracting(BranchDto::getKey) .isEqualTo(MAIN_BRANCH); + projectIndexers.hasBeenCalledForEntity(branch.getProjectUuid(), Indexers.EntityEvent.CREATION); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java index ee78e7c66c7..035b3ef9ffc 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java @@ -20,18 +20,14 @@ package org.sonar.server.project.ws; import java.util.List; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectData; import org.sonar.db.permission.GlobalPermission; @@ -40,7 +36,7 @@ import org.sonar.db.user.UserDto; import org.sonar.db.webhook.WebhookDbTester; import org.sonar.db.webhook.WebhookDto; import org.sonar.server.component.ComponentCleanerService; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.project.Project; @@ -54,10 +50,8 @@ import static java.util.Collections.singleton; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.sonar.db.user.UserTesting.newUserDto; import static org.sonar.server.component.TestComponentFinder.from; import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; @@ -75,7 +69,6 @@ public class DeleteActionIT { private final WebhookDbTester webhookDbTester = db.webhooks(); private final ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class); private final ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); - private final ResourceTypes mockResourceTypes = mock(ResourceTypes.class); private final DeleteAction underTest = new DeleteAction( componentCleanerService, @@ -84,17 +77,6 @@ public class DeleteActionIT { userSessionRule, projectLifeCycleListeners); private final WsActionTester tester = new WsActionTester(underTest); - @Before - public void before() { - mockResourceTypeAsValidProject(); - } - - private void mockResourceTypeAsValidProject() { - ResourceType resourceType = mock(ResourceType.class); - when(resourceType.getBooleanProperty(anyString())).thenReturn(true); - when(mockResourceTypes.get(anyString())).thenReturn(resourceType); - } - @Test public void global_administrator_deletes_project_by_key() { ProjectData projectData = db.components().insertPrivateProject(); @@ -128,7 +110,7 @@ public class DeleteActionIT { dbSession.commit(); userSessionRule.logIn().addProjectPermission(UserRole.ADMIN, projectData.getProjectDto()); DeleteAction underTest = new DeleteAction( - new ComponentCleanerService(dbClient, mockResourceTypes, new TestProjectIndexers()), + new ComponentCleanerService(dbClient, new TestIndexers()), from(db), dbClient, userSessionRule, projectLifeCycleListeners); new WsActionTester(underTest) @@ -151,7 +133,7 @@ public class DeleteActionIT { userSessionRule.logIn().addProjectPermission(UserRole.ADMIN, project); DeleteAction underTest = new DeleteAction( - new ComponentCleanerService(dbClient, mockResourceTypes, new TestProjectIndexers()), + new ComponentCleanerService(dbClient, new TestIndexers()), from(db), dbClient, userSessionRule, projectLifeCycleListeners); new WsActionTester(underTest) @@ -190,7 +172,7 @@ public class DeleteActionIT { private String verifyDeletedKey() { ArgumentCaptor argument = ArgumentCaptor.forClass(ProjectDto.class); - verify(componentCleanerService).delete(any(DbSession.class), argument.capture()); + verify(componentCleanerService).deleteEntity(any(DbSession.class), argument.capture()); return argument.getValue().getKey(); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateKeyActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateKeyActionIT.java index fd9624f43d7..1c14be1725d 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateKeyActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateKeyActionIT.java @@ -34,8 +34,8 @@ import org.sonar.db.component.ProjectData; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.es.ProjectIndexersImpl; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.IndexersImpl; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.project.ProjectLifeCycleListenersImpl; @@ -56,8 +56,8 @@ public class UpdateKeyActionIT { @Rule public final UserSessionRule userSessionRule = UserSessionRule.standalone(); private final DbClient dbClient = db.getDbClient(); - private final ProjectIndexers projectIndexers = new ProjectIndexersImpl(); - private final ComponentService componentService = new ComponentService(dbClient, userSessionRule, projectIndexers, new ProjectLifeCycleListenersImpl()); + private final Indexers indexers = new IndexersImpl(); + private final ComponentService componentService = new ComponentService(dbClient, userSessionRule, indexers, new ProjectLifeCycleListenersImpl()); private final ComponentFinder componentFinder = new ComponentFinder(dbClient, null); private final WsActionTester ws = new WsActionTester(new UpdateKeyAction(dbClient, componentService, componentFinder)); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateVisibilityActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateVisibilityActionIT.java index 7d04fff851b..333163ea383 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateVisibilityActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateVisibilityActionIT.java @@ -54,8 +54,8 @@ import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; import org.sonar.server.es.EsTester; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; @@ -101,7 +101,7 @@ public class UpdateVisibilityActionIT { private final DbClient dbClient = dbTester.getDbClient(); private final DbSession dbSession = dbTester.getSession(); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); + private final TestIndexers projectIndexers = new TestIndexers(); private final Configuration configuration = mock(Configuration.class); private final UpdateVisibilityAction underTest = new UpdateVisibilityAction(dbClient, userSessionRule, projectIndexers, new SequenceUuidFactory(), configuration); @@ -423,7 +423,7 @@ public class UpdateVisibilityActionIT { .setParam(PARAM_VISIBILITY, initiallyPrivate ? PUBLIC : PRIVATE) .execute(); - assertThat(projectIndexers.hasBeenCalled(project.projectUuid(), ProjectIndexer.Cause.PERMISSION_CHANGE)).isTrue(); + assertThat(projectIndexers.hasBeenCalledForEntity(project.projectUuid(), Indexers.EntityEvent.PERMISSION_CHANGE)).isTrue(); } @Test @@ -436,7 +436,7 @@ public class UpdateVisibilityActionIT { .setParam(PARAM_VISIBILITY, initiallyPrivate ? PRIVATE : PUBLIC) .execute(); - assertThat(projectIndexers.hasBeenCalled(project.projectUuid())).isFalse(); + assertThat(projectIndexers.hasBeenCalledForEntity(project.projectUuid())).isFalse(); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projecttag/ws/SetActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projecttag/ws/SetActionIT.java index 2903770460b..dab7a100568 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projecttag/ws/SetActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projecttag/ws/SetActionIT.java @@ -32,7 +32,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectData; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.TestComponentFinder; -import org.sonar.server.es.TestProjectIndexers; +import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -48,7 +48,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.USER; +import static org.sonar.db.component.ComponentDbTester.defaults; import static org.sonar.db.component.ComponentTesting.newFileDto; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_TAGS_UPDATE; public class SetActionIT { @Rule @@ -58,8 +60,8 @@ public class SetActionIT { private final DbClient dbClient = db.getDbClient(); private final DbSession dbSession = db.getSession(); - private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private final TagsWsSupport tagsWsSupport = new TagsWsSupport(dbClient, TestComponentFinder.from(db), userSession, projectIndexers, System2.INSTANCE); + private final TestIndexers indexers = new TestIndexers(); + private final TagsWsSupport tagsWsSupport = new TagsWsSupport(dbClient, TestComponentFinder.from(db), userSession, indexers, System2.INSTANCE); private final WsActionTester ws = new WsActionTester(new SetAction(dbClient, tagsWsSupport)); private ProjectDto project; private ComponentDto projectComponent; @@ -77,15 +79,13 @@ public class SetActionIT { TestResponse response = call(project.getKey(), "finance , offshore, platform, ,"); assertTags(project.getKey(), "finance", "offshore", "platform"); - // FIXME verify(indexer).indexProject(project.uuid(), PROJECT_TAGS_UPDATE); - + indexers.hasBeenCalledForEntity(project.getUuid(), PROJECT_TAGS_UPDATE); assertThat(response.getStatus()).isEqualTo(HTTP_NO_CONTENT); } @Test public void reset_tags() { - project = db.components().insertPrivateProject(c -> { - }, p -> p.setTagsString("platform,scanner")).getProjectDto(); + project = db.components().insertPrivateProject(defaults(), p -> p.setTagsString("platform,scanner")).getProjectDto(); userSession.addProjectPermission(ADMIN, project); call(project.getKey(), ""); @@ -95,8 +95,7 @@ public class SetActionIT { @Test public void override_existing_tags() { - project = db.components().insertPrivateProject(c -> { - }, p -> p.setTagsString("marketing,languages")).getProjectDto(); + project = db.components().insertPrivateProject(defaults(), p -> p.setTagsString("marketing,languages")).getProjectDto(); userSession.addProjectPermission(ADMIN, project); call(project.getKey(), "finance,offshore,platform"); @@ -111,6 +110,7 @@ public class SetActionIT { call(project.getKey(), "platform, lambda"); assertTags(project.getKey(), "platform", "lambda"); + indexers.hasBeenCalledForEntity(project.getUuid(), PROJECT_TAGS_UPDATE); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java index b61c5584cd6..de64a6458c6 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java @@ -156,7 +156,7 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { newCodeDefinitionType, newCodeDefinitionValue); } - componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + componentUpdater.commitAndIndex(dbSession, componentCreationData); return toCreateResponse(projectDto); } @@ -180,9 +180,7 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { .build(), userSession.isLoggedIn() ? userSession.getUuid() : null, userSession.isLoggedIn() ? userSession.getLogin() : null, - repo.getDefaultBranchName(), - s -> { - }); + repo.getDefaultBranchName()); } private void populatePRSetting(DbSession dbSession, GsonAzureRepo repo, ProjectDto projectDto, AlmSettingDto almSettingDto) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java index 69afb640854..793fc5b4299 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java @@ -153,7 +153,7 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { newCodeDefinitionType, newCodeDefinitionValue); } - componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + componentUpdater.commitAndIndex(dbSession, componentCreationData); return toCreateResponse(projectDto); } @@ -180,8 +180,7 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { String userUuid = userSession.isLoggedIn() ? userSession.getUuid() : null; String userLogin = userSession.isLoggedIn() ? userSession.getLogin() : null; - return componentUpdater.createWithoutCommit(dbSession, mainBranch, userUuid, userLogin, defaultBranchName, p -> { - }); + return componentUpdater.createWithoutCommit(dbSession, mainBranch, userUuid, userLogin, defaultBranchName); } private void populatePRSetting(DbSession dbSession, Repository repo, ProjectDto projectDto, AlmSettingDto almSettingDto) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java index 85bc552f2d4..cf6b6350710 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java @@ -165,7 +165,7 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi newCodeDefinitionType, newCodeDefinitionValue); } - componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + componentUpdater.commitAndIndex(dbSession, componentCreationData); return toCreateResponse(projectDto); } @@ -198,8 +198,7 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi String userUuid = userSession.isLoggedIn() ? userSession.getUuid() : null; String userLogin = userSession.isLoggedIn() ? userSession.getLogin() : null; - return componentUpdater.createWithoutCommit(dbSession, newProject, userUuid, userLogin, defaultBranchName, p -> { - }); + return componentUpdater.createWithoutCommit(dbSession, newProject, userUuid, userLogin, defaultBranchName); } private void populatePRSetting(DbSession dbSession, Repository repo, ProjectDto componentDto, AlmSettingDto almSettingDto) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java index 56fbda88008..6a57fe33088 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java @@ -164,7 +164,7 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { newCodeDefinitionType, newCodeDefinitionValue); } - componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + componentUpdater.commitAndIndex(dbSession, componentCreationData); return toCreateResponse(projectDto); } @@ -187,8 +187,7 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { .setPrivate(visibility) .setQualifier(PROJECT) .build(), - userSession.getUuid(), userSession.getLogin(), mainBranchName, s -> { - }); + userSession.getUuid(), userSession.getLogin(), mainBranchName); } private void populatePRSetting(DbSession dbSession, Repository repo, ProjectDto projectDto, AlmSettingDto almSettingDto) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java index e895173cf7d..3d9ab26f8df 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java @@ -144,7 +144,7 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { newCodeDefinitionType, newCodeDefinitionValue); } - componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + componentUpdater.commitAndIndex(dbSession, componentCreationData); return ImportHelper.toCreateResponse(projectDto); } @@ -183,8 +183,7 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { .setPrivate(visibility) .setQualifier(PROJECT) .build(), - userSession.getUuid(), userSession.getLogin(), mainBranchName, s -> { - }); + userSession.getUuid(), userSession.getLogin(), mainBranchName); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java index 9aa203138f4..81427f7d77d 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java @@ -38,6 +38,7 @@ import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.permission.GlobalPermission; +import org.sonar.server.component.ComponentCreationData; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.component.NewComponent; import org.sonar.server.exceptions.BadRequestException; @@ -75,7 +76,7 @@ public class ReportSubmitter { public CeTask submit(String projectKey, @Nullable String projectName, Map characteristics, InputStream reportInput) { try (DbSession dbSession = dbClient.openSession(false)) { - boolean projectCreated = false; + ComponentCreationData componentCreationData = null; // Note: when the main branch is analyzed, the characteristics may or may not have the branch name, so componentKey#isMainBranch is not // reliable! BranchSupport.ComponentKey componentKey = branchSupport.createComponentKey(projectKey, characteristics); @@ -86,8 +87,8 @@ public class ReportSubmitter { mainBranchComponent = mainBranchComponentOpt.get(); validateProject(dbSession, mainBranchComponent, projectKey); } else { - mainBranchComponent = createProject(dbSession, componentKey.getKey(), projectName); - projectCreated = true; + componentCreationData = createProject(dbSession, componentKey.getKey(), projectName); + mainBranchComponent = componentCreationData.mainBranchComponent(); } BranchDto mainBranch = dbClient.branchDao().selectByUuid(dbSession, mainBranchComponent.branchUuid()) @@ -103,8 +104,8 @@ public class ReportSubmitter { .orElseGet(() -> branchSupport.createBranchComponent(dbSession, componentKey, mainBranchComponent, mainBranch)); } - if (projectCreated) { - componentUpdater.commitAndIndex(dbSession, mainBranchComponent); + if (componentCreationData != null) { + componentUpdater.commitAndIndex(dbSession, componentCreationData); } else { dbSession.commit(); } @@ -151,7 +152,7 @@ public class ReportSubmitter { } } - private ComponentDto createProject(DbSession dbSession, String projectKey, @Nullable String projectName) { + private ComponentCreationData createProject(DbSession dbSession, String projectKey, @Nullable String projectName) { userSession.checkPermission(GlobalPermission.PROVISION_PROJECTS); String userUuid = userSession.getUuid(); String userName = userSession.getLogin(); @@ -167,8 +168,7 @@ public class ReportSubmitter { .setQualifier(Qualifiers.PROJECT) .setPrivate(getDefaultVisibility(dbSession).isPrivate()) .build(); - return componentUpdater.createWithoutCommit(dbSession, newProject, userUuid, userName, c -> { - }).mainBranchComponent(); + return componentUpdater.createWithoutCommit(dbSession, newProject, userUuid, userName); } private Visibility getDefaultVisibility(DbSession dbSession) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java index 9325afef071..413fe60ca3b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -21,36 +21,33 @@ package org.sonar.server.component; import java.util.List; import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; import org.sonar.api.server.ServerSide; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.BranchDto; import org.sonar.db.entity.EntityDto; import org.sonar.db.project.ProjectDto; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.Indexers; +import org.sonar.server.es.Indexers.BranchEvent; +import org.sonar.server.es.Indexers.EntityEvent; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Collections.singletonList; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; @ServerSide public class ComponentCleanerService { private final DbClient dbClient; - private final ResourceTypes resourceTypes; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; - public ComponentCleanerService(DbClient dbClient, ResourceTypes resourceTypes, ProjectIndexers projectIndexers) { + public ComponentCleanerService(DbClient dbClient, Indexers indexers) { this.dbClient = dbClient; - this.resourceTypes = resourceTypes; - this.projectIndexers = projectIndexers; + this.indexers = indexers; } public void delete(DbSession dbSession, List projects) { for (ProjectDto project : projects) { - delete(dbSession, project); + deleteEntity(dbSession, project); } } @@ -59,23 +56,17 @@ public class ComponentCleanerService { throw new IllegalArgumentException("Only non-main branches can be deleted"); } dbClient.purgeDao().deleteBranch(dbSession, branch.getUuid()); - projectIndexers.commitAndIndexBranches(dbSession, singletonList(branch), PROJECT_DELETION); + indexers.commitAndIndexBranches(dbSession, singletonList(branch), BranchEvent.DELETION); } - public void delete(DbSession dbSession, EntityDto entity) { - checkArgument(isDeletable(entity), "Only projects can be deleted"); - + public void deleteEntity(DbSession dbSession, EntityDto entity) { + checkArgument(!entity.getQualifier().equals(Qualifiers.SUBVIEW), "Qualifier can't be subview"); dbClient.purgeDao().deleteProject(dbSession, entity.getUuid(), entity.getQualifier(), entity.getName(), entity.getKey()); dbClient.userDao().cleanHomepage(dbSession, entity); if (Qualifiers.PROJECT.equals(entity.getQualifier())) { dbClient.userTokenDao().deleteByProjectUuid(dbSession, entity.getKey(), entity.getUuid()); } - projectIndexers.commitAndIndexEntities(dbSession, singletonList(entity), PROJECT_DELETION); - } - - private boolean isDeletable(EntityDto entityDto) { - ResourceType resourceType = resourceTypes.get(entityDto.getQualifier()); - // this essentially means PROJECTS, VIEWS and APPS (not SUBVIEWS) - return resourceType != null && resourceType.getBooleanProperty("deletable"); + // Note that we do not send an event for each individual branch being deleted with the project + indexers.commitAndIndexEntities(dbSession, singletonList(entity), EntityEvent.DELETION); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCreationData.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCreationData.java index f3b2aabf582..9751629c114 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCreationData.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCreationData.java @@ -22,8 +22,9 @@ package org.sonar.server.component; import javax.annotation.Nullable; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; +import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; -public record ComponentCreationData(ComponentDto mainBranchComponent, @Nullable BranchDto mainBranchDto, +public record ComponentCreationData(ComponentDto mainBranchComponent, @Nullable PortfolioDto portfolioDto, @Nullable BranchDto mainBranchDto, @Nullable ProjectDto projectDto) { } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentService.java index fdd54e406e8..d8e6792b1e9 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentService.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentService.java @@ -27,8 +27,8 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.project.ProjectDto; import org.sonar.db.pushevent.PushEventDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.EventIndexer; +import org.sonar.server.es.Indexers; import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.project.RekeyedProject; @@ -45,13 +45,13 @@ public class ComponentService { private final DbClient dbClient; private final UserSession userSession; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final ProjectLifeCycleListeners projectLifeCycleListeners; - public ComponentService(DbClient dbClient, UserSession userSession, ProjectIndexers projectIndexers, ProjectLifeCycleListeners projectLifeCycleListeners) { + public ComponentService(DbClient dbClient, UserSession userSession, Indexers indexers, ProjectLifeCycleListeners projectLifeCycleListeners) { this.dbClient = dbClient; this.userSession = userSession; - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.projectLifeCycleListeners = projectLifeCycleListeners; } @@ -59,7 +59,7 @@ public class ComponentService { userSession.checkEntityPermission(UserRole.ADMIN, project); checkProjectKey(newKey); dbClient.componentKeyUpdaterDao().updateKey(dbSession, project.getUuid(), project.getKey(), newKey); - projectIndexers.commitAndIndexProjects(dbSession, singletonList(project), ProjectIndexer.Cause.PROJECT_KEY_UPDATE); + indexers.commitAndIndexEntities(dbSession, singletonList(project), Indexers.EntityEvent.PROJECT_KEY_UPDATE); Project newProject = new Project(project.getUuid(), newKey, project.getName(), project.getDescription(), project.getTags()); projectLifeCycleListeners.onProjectsRekeyed(singleton(new RekeyedProject(newProject, project.getKey()))); persistEvent(project, newKey); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java index 4a0f002cd6b..95aece5b40e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; -import java.util.function.Consumer; import java.util.stream.Collectors; import javax.annotation.Nullable; import org.sonar.api.resources.Qualifiers; @@ -41,8 +40,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.portfolio.PortfolioDto.SelectionMode; import org.sonar.db.project.ProjectDto; -import org.sonar.server.es.ProjectIndexer.Cause; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.Indexers; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.DefaultBranchNameResolver; @@ -56,7 +54,7 @@ import static org.sonar.server.exceptions.BadRequestException.throwBadRequestExc public class ComponentUpdater { - private static final Set MAIN_BRANCH_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.APP); + private static final Set PROJ_APP_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.APP); private static final String KEY_ALREADY_EXISTS_ERROR = "Could not create %s with key: \"%s\". A similar key already exists: \"%s\""; private static final String MALFORMED_KEY_ERROR = "Malformed key for %s: '%s'. %s."; private final DbClient dbClient; @@ -64,7 +62,7 @@ public class ComponentUpdater { private final System2 system2; private final PermissionTemplateService permissionTemplateService; private final FavoriteUpdater favoriteUpdater; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final UuidFactory uuidFactory; private final DefaultBranchNameResolver defaultBranchNameResolver; private final boolean useDifferentUuids; @@ -72,21 +70,21 @@ public class ComponentUpdater { @Autowired public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2, PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater, - ProjectIndexers projectIndexers, UuidFactory uuidFactory, DefaultBranchNameResolver defaultBranchNameResolver) { - this(dbClient, i18n, system2, permissionTemplateService, favoriteUpdater, projectIndexers, uuidFactory, defaultBranchNameResolver, false); + Indexers indexers, UuidFactory uuidFactory, DefaultBranchNameResolver defaultBranchNameResolver) { + this(dbClient, i18n, system2, permissionTemplateService, favoriteUpdater, indexers, uuidFactory, defaultBranchNameResolver, false); } @VisibleForTesting public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2, PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater, - ProjectIndexers projectIndexers, UuidFactory uuidFactory, DefaultBranchNameResolver defaultBranchNameResolver, + Indexers indexers, UuidFactory uuidFactory, DefaultBranchNameResolver defaultBranchNameResolver, boolean useDifferentUuids) { this.dbClient = dbClient; this.i18n = i18n; this.system2 = system2; this.permissionTemplateService = permissionTemplateService; this.favoriteUpdater = favoriteUpdater; - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.uuidFactory = uuidFactory; this.defaultBranchNameResolver = defaultBranchNameResolver; this.useDifferentUuids = useDifferentUuids; @@ -99,19 +97,17 @@ public class ComponentUpdater { * - Index component in es indexes */ public ComponentCreationData create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin) { - return create(dbSession, newComponent, userUuid, userLogin, null); - } - - public ComponentCreationData create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin, - @Nullable String mainBranchName) { - ComponentCreationData componentCreationData = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, mainBranchName, c -> { - }); - commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); + ComponentCreationData componentCreationData = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, null); + commitAndIndex(dbSession, componentCreationData); return componentCreationData; } - public void commitAndIndex(DbSession dbSession, ComponentDto componentDto) { - projectIndexers.commitAndIndexComponents(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION); + public void commitAndIndex(DbSession dbSession, ComponentCreationData componentCreationData) { + if (componentCreationData.portfolioDto() != null) { + indexers.commitAndIndexEntities(dbSession, singletonList(componentCreationData.portfolioDto()), Indexers.EntityEvent.CREATION); + } else if (componentCreationData.projectDto() != null) { + indexers.commitAndIndexEntities(dbSession, singletonList(componentCreationData.projectDto()), Indexers.EntityEvent.CREATION); + } } /** @@ -119,8 +115,8 @@ public class ComponentUpdater { * Don't forget to call commitAndIndex(...) when ready to commit. */ public ComponentCreationData createWithoutCommit(DbSession dbSession, NewComponent newComponent, - @Nullable String userUuid, @Nullable String userLogin, Consumer componentModifier) { - return createWithoutCommit(dbSession, newComponent, userUuid, userLogin, null, componentModifier); + @Nullable String userUuid, @Nullable String userLogin) { + return createWithoutCommit(dbSession, newComponent, userUuid, userLogin, null); } /** @@ -128,33 +124,33 @@ public class ComponentUpdater { * Don't forget to call commitAndIndex(...) when ready to commit. */ public ComponentCreationData createWithoutCommit(DbSession dbSession, NewComponent newComponent, - @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName, - Consumer componentModifier) { + @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName) { checkKeyFormat(newComponent.qualifier(), newComponent.key()); checkKeyAlreadyExists(dbSession, newComponent); long now = system2.now(); - ComponentDto componentDto = createRootComponent(dbSession, newComponent, componentModifier, now); + ComponentDto componentDto = createRootComponent(dbSession, newComponent, now); BranchDto mainBranch = null; ProjectDto projectDto = null; + PortfolioDto portfolioDto = null; - if (isRootProject(componentDto)) { + if (isProjectOrApp(componentDto)) { projectDto = toProjectDto(componentDto, now); dbClient.projectDao().insert(dbSession, projectDto); addToFavourites(dbSession, projectDto, userUuid, userLogin); mainBranch = createMainBranch(dbSession, componentDto.uuid(), projectDto.getUuid(), mainBranchName); permissionTemplateService.applyDefaultToNewComponent(dbSession, projectDto, userUuid); - } else if (isRootView(componentDto)) { - PortfolioDto portfolioDto = toPortfolioDto(componentDto, now); + } else if (isPortfolio(componentDto)) { + portfolioDto = toPortfolioDto(componentDto, now); dbClient.portfolioDao().insert(dbSession, portfolioDto); permissionTemplateService.applyDefaultToNewComponent(dbSession, portfolioDto, userUuid); } else { throw new IllegalArgumentException("Component " + componentDto + " is not a top level entity"); } - return new ComponentCreationData(componentDto, mainBranch, projectDto); + return new ComponentCreationData(componentDto, portfolioDto, mainBranch, projectDto); } private void addToFavourites(DbSession dbSession, ProjectDto projectDto, @Nullable String userUuid, @Nullable String userLogin) { @@ -179,7 +175,7 @@ public class ComponentUpdater { } } - private ComponentDto createRootComponent(DbSession session, NewComponent newComponent, Consumer componentModifier, long now) { + private ComponentDto createRootComponent(DbSession session, NewComponent newComponent, long now) { String uuid = uuidFactory.create(); ComponentDto component = new ComponentDto() @@ -195,7 +191,6 @@ public class ComponentUpdater { .setPrivate(newComponent.isPrivate()) .setCreatedAt(new Date(now)); - componentModifier.accept(component); dbClient.componentDao().insert(session, component, true); return component; } @@ -225,14 +220,12 @@ public class ComponentUpdater { .setCreatedAt(now); } - private static boolean isRootProject(ComponentDto componentDto) { - return Scopes.PROJECT.equals(componentDto.scope()) - && MAIN_BRANCH_QUALIFIERS.contains(componentDto.qualifier()); + private static boolean isProjectOrApp(ComponentDto componentDto) { + return PROJ_APP_QUALIFIERS.contains(componentDto.qualifier()); } - private static boolean isRootView(ComponentDto componentDto) { - return Scopes.PROJECT.equals(componentDto.scope()) - && Qualifiers.VIEW.contains(componentDto.qualifier()); + private static boolean isPortfolio(ComponentDto componentDto) { + return Qualifiers.VIEW.contains(componentDto.qualifier()); } private BranchDto createMainBranch(DbSession session, String componentUuid, String projectUuid, @Nullable String mainBranch) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java index f3e12e9e0b1..c75a637fd32 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java @@ -119,16 +119,17 @@ public class AuthorsAction implements IssuesWsAction { private List getAuthors(DbSession session, @Nullable EntityDto entity, Request request) { IssueQuery.Builder issueQueryBuilder = IssueQuery.builder(); - ofNullable(entity).ifPresent(p -> { - switch (p.getQualifier()) { - case Qualifiers.PROJECT -> issueQueryBuilder.projectUuids(Set.of(p.getUuid())); - case Qualifiers.VIEW -> issueQueryBuilder.viewUuids(Set.of(p.getUuid())); + ofNullable(entity).ifPresent(e -> { + switch (e.getQualifier()) { + case Qualifiers.PROJECT -> issueQueryBuilder.projectUuids(Set.of(e.getUuid())); + case Qualifiers.VIEW -> issueQueryBuilder.viewUuids(Set.of(e.getUuid())); case Qualifiers.APP -> { - BranchDto appMainBranch = dbClient.branchDao().selectMainBranchByProjectUuid(session, entity.getUuid()) - .orElseThrow(() -> new IllegalStateException("Couldn't find main branch for APP " + entity.getUuid())); - issueQueryBuilder.viewUuids(Set.of(appMainBranch.getUuid())); + BranchDto appMainBranch = dbClient.branchDao().selectMainBranchByProjectUuid(session, e.getUuid()) + .orElseThrow(() -> new IllegalStateException("Couldn't find main branch for APP " + e.getUuid())); + issueQueryBuilder.viewUuids(Set.of(entity.getUuid())); + issueQueryBuilder.branchUuid(appMainBranch.getUuid()); } - default -> throw new IllegalArgumentException(String.format("Component of type '%s' is not supported", p.getQualifier())); + default -> throw new IllegalArgumentException(String.format("Component of type '%s' is not supported", e.getQualifier())); } }); return issueIndex.searchAuthors( diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java index 643f5335f54..9c346e2cfec 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java @@ -39,8 +39,8 @@ import org.sonar.db.measure.LiveMeasureComparator; import org.sonar.db.measure.LiveMeasureDto; import org.sonar.db.metric.MetricDto; import org.sonar.db.project.ProjectDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.EventIndexer; +import org.sonar.server.es.Indexers; import org.sonar.server.qualitygate.EvaluatedQualityGate; import org.sonar.server.qualitygate.QualityGate; import org.sonar.server.qualitygate.changeevent.QGChangeEvent; @@ -59,11 +59,11 @@ public class LiveMeasureComputerImpl implements LiveMeasureComputer { private final ComponentIndexFactory componentIndexFactory; private final LiveQualityGateComputer qGateComputer; private final ProjectConfigurationLoader projectConfigurationLoader; - private final ProjectIndexers projectIndexer; + private final Indexers projectIndexer; private final LiveMeasureTreeUpdater treeUpdater; public LiveMeasureComputerImpl(DbClient dbClient, MeasureUpdateFormulaFactory formulaFactory, ComponentIndexFactory componentIndexFactory, - LiveQualityGateComputer qGateComputer, ProjectConfigurationLoader projectConfigurationLoader, ProjectIndexers projectIndexer, LiveMeasureTreeUpdater treeUpdater) { + LiveQualityGateComputer qGateComputer, ProjectConfigurationLoader projectConfigurationLoader, Indexers projectIndexer, LiveMeasureTreeUpdater treeUpdater) { this.dbClient = dbClient; this.formulaFactory = formulaFactory; this.componentIndexFactory = componentIndexFactory; @@ -106,7 +106,7 @@ public class LiveMeasureComputerImpl implements LiveMeasureComputer { Metric.Level previousStatus = loadPreviousStatus(dbSession, branchComponent); EvaluatedQualityGate evaluatedQualityGate = qGateComputer.refreshGateStatus(branchComponent, qualityGate, matrix, config); - persistAndIndex(dbSession, matrix, branchComponent); + persistAndIndex(dbSession, matrix, branch); return Optional.of(new QGChangeEvent(project, branch, lastAnalysis.get(), config, previousStatus, () -> Optional.of(evaluatedQualityGate))); } @@ -118,10 +118,10 @@ public class LiveMeasureComputerImpl implements LiveMeasureComputer { return new MeasureMatrix(componentUuids, metricsPerUuid.values(), measures); } - private void persistAndIndex(DbSession dbSession, MeasureMatrix matrix, ComponentDto branchComponent) { + private void persistAndIndex(DbSession dbSession, MeasureMatrix matrix, BranchDto branch) { // persist the measures that have been created or updated matrix.getChanged().sorted(LiveMeasureComparator.INSTANCE).forEach(m -> dbClient.liveMeasureDao().insertOrUpdate(dbSession, m)); - projectIndexer.commitAndIndexComponents(dbSession, singleton(branchComponent), ProjectIndexer.Cause.MEASURE_CHANGE); + projectIndexer.commitAndIndexBranches(dbSession, singleton(branch), Indexers.BranchEvent.MEASURE_CHANGE); } @CheckForNull diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionTemplateService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionTemplateService.java index 7390880e6cd..43072bf34f9 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionTemplateService.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionTemplateService.java @@ -45,8 +45,7 @@ import org.sonar.db.permission.template.PermissionTemplateUserDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.db.user.UserId; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.Indexers; import org.sonar.server.exceptions.TemplateMatchingKeyException; import org.sonar.server.permission.DefaultTemplatesResolver.ResolvedDefaultTemplates; import org.sonar.server.user.UserSession; @@ -62,15 +61,15 @@ import static org.sonar.db.permission.GlobalPermission.SCAN; public class PermissionTemplateService { private final DbClient dbClient; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final UserSession userSession; private final DefaultTemplatesResolver defaultTemplatesResolver; private final UuidFactory uuidFactory; - public PermissionTemplateService(DbClient dbClient, ProjectIndexers projectIndexers, UserSession userSession, + public PermissionTemplateService(DbClient dbClient, Indexers indexers, UserSession userSession, DefaultTemplatesResolver defaultTemplatesResolver, UuidFactory uuidFactory) { this.dbClient = dbClient; - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.userSession = userSession; this.defaultTemplatesResolver = defaultTemplatesResolver; this.uuidFactory = uuidFactory; @@ -106,11 +105,12 @@ public class PermissionTemplateService { dbClient.userPermissionDao().deleteEntityPermissions(dbSession, entity); copyPermissions(dbSession, template, entity, null); } - projectIndexers.commitAndIndexEntities(dbSession, entities, ProjectIndexer.Cause.PERMISSION_CHANGE); + indexers.commitAndIndexEntities(dbSession, entities, Indexers.EntityEvent.PERMISSION_CHANGE); } /** * Apply the default permission template to a new project (has no permissions yet). + * * @param projectCreatorUserId id of the user creating the project. */ public void applyDefaultToNewComponent(DbSession dbSession, EntityDto entityDto, @Nullable String projectCreatorUserId) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionUpdater.java index f3bdf455d6b..3564da99516 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionUpdater.java @@ -23,21 +23,20 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.sonar.db.DbSession; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.Indexers; /** * Add or remove global/project permissions to a group. This class does not verify that caller has administration right on the related project. */ public class PermissionUpdater { - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final UserPermissionChanger userPermissionChanger; private final GroupPermissionChanger groupPermissionChanger; - public PermissionUpdater(ProjectIndexers projectIndexers, + public PermissionUpdater(Indexers indexers, UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger) { - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.userPermissionChanger = userPermissionChanger; this.groupPermissionChanger = groupPermissionChanger; } @@ -51,7 +50,7 @@ public class PermissionUpdater { projectOrViewUuids.add(projectUuid); } } - projectIndexers.commitAndIndexByProjectUuids(dbSession, projectOrViewUuids, ProjectIndexer.Cause.PERMISSION_CHANGE); + indexers.commitAndIndexOnEntityEvent(dbSession, projectOrViewUuids, Indexers.EntityEvent.PERMISSION_CHANGE); } private boolean doApply(DbSession dbSession, PermissionChange change) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java index 3f8ed5b98fa..57d33bc5ff8 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java @@ -25,6 +25,7 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; @@ -151,9 +152,9 @@ public class BulkDeleteAction implements ProjectsWsAction { List entities = dbClient.entityDao().selectByKeys(dbSession, componentDtos.stream().map(ComponentDto::getKey).collect(toSet())); try { - entities.forEach(e -> componentCleanerService.delete(dbSession, e)); + entities.forEach(p -> componentCleanerService.deleteEntity(dbSession, p)); } finally { - projectLifeCycleListeners.onProjectsDeleted(entities.stream().map(Project::from).collect(MoreCollectors.toSet(componentDtos.size()))); + projectLifeCycleListeners.onProjectsDeleted(entities.stream().map(Project::from).collect(Collectors.toSet())); } } response.noContent(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java index 49a10dc1336..9c67047cf25 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java @@ -28,7 +28,9 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; +import org.sonar.db.project.ProjectDto; +import org.sonar.server.component.ComponentCreationData; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.project.DefaultBranchNameResolver; @@ -132,18 +134,18 @@ public class CreateAction implements ProjectsWsAction { try (DbSession dbSession = dbClient.openSession(false)) { userSession.checkPermission(PROVISION_PROJECTS); checkNewCodeDefinitionParam(request.getNewCodeDefinitionType(), request.getNewCodeDefinitionValue()); - ComponentDto componentDto = createProject(request, dbSession); + ComponentCreationData componentData = createProject(request, dbSession); if (request.getNewCodeDefinitionType() != null) { String defaultBranchName = Optional.ofNullable(request.getMainBranchKey()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName()); - newCodeDefinitionResolver.createNewCodeDefinition(dbSession, componentDto.uuid(), defaultBranchName, request.getNewCodeDefinitionType(), + newCodeDefinitionResolver.createNewCodeDefinition(dbSession, componentData.mainBranchDto().getUuid(), defaultBranchName, request.getNewCodeDefinitionType(), request.getNewCodeDefinitionValue()); } - componentUpdater.commitAndIndex(dbSession, componentDto); - return toCreateResponse(componentDto); + componentUpdater.commitAndIndex(dbSession, componentData); + return toCreateResponse(componentData.projectDto()); } } - private ComponentDto createProject(CreateRequest request, DbSession dbSession) { + private ComponentCreationData createProject(CreateRequest request, DbSession dbSession) { String visibility = request.getVisibility(); boolean changeToPrivate = visibility == null ? projectDefaultVisibility.get(dbSession).isPrivate() : "private".equals(visibility); @@ -155,8 +157,7 @@ public class CreateAction implements ProjectsWsAction { .build(), userSession.isLoggedIn() ? userSession.getUuid() : null, userSession.isLoggedIn() ? userSession.getLogin() : null, - request.getMainBranchKey(), s -> { - }).mainBranchComponent(); + request.getMainBranchKey()); } @@ -171,13 +172,13 @@ public class CreateAction implements ProjectsWsAction { .build(); } - private static CreateWsResponse toCreateResponse(ComponentDto componentDto) { + private static CreateWsResponse toCreateResponse(EntityDto project) { return CreateWsResponse.newBuilder() .setProject(CreateWsResponse.Project.newBuilder() - .setKey(componentDto.getKey()) - .setName(componentDto.name()) - .setQualifier(componentDto.qualifier()) - .setVisibility(Visibility.getLabel(componentDto.isPrivate()))) + .setKey(project.getKey()) + .setName(project.getName()) + .setQualifier(project.getQualifier()) + .setVisibility(Visibility.getLabel(project.isPrivate()))) .build(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java index f6ff00362e5..3fc9097d398 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java @@ -81,7 +81,7 @@ public class DeleteAction implements ProjectsWsAction { try (DbSession dbSession = dbClient.openSession(false)) { ProjectDto project = componentFinder.getProjectByKey(dbSession, key); checkPermission(project); - componentCleanerService.delete(dbSession, project); + componentCleanerService.deleteEntity(dbSession, project); projectLifeCycleListeners.onProjectsDeleted(singleton(Project.fromProjectDtoWithTags(project))); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java index 6d0ca25d61f..0510d1fd956 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java @@ -34,8 +34,8 @@ import org.sonar.db.permission.GroupPermissionDto; import org.sonar.db.permission.UserPermissionDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserId; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.EventIndexer; +import org.sonar.server.es.Indexers; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.project.Visibility; import org.sonar.server.user.UserSession; @@ -57,14 +57,14 @@ public class UpdateVisibilityAction implements ProjectsWsAction { private final DbClient dbClient; private final UserSession userSession; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final UuidFactory uuidFactory; private final Configuration configuration; - public UpdateVisibilityAction(DbClient dbClient, UserSession userSession, ProjectIndexers projectIndexers, UuidFactory uuidFactory, Configuration configuration) { + public UpdateVisibilityAction(DbClient dbClient, UserSession userSession, Indexers indexers, UuidFactory uuidFactory, Configuration configuration) { this.dbClient = dbClient; this.userSession = userSession; - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.uuidFactory = uuidFactory; this.configuration = configuration; } @@ -119,7 +119,7 @@ public class UpdateVisibilityAction implements ProjectsWsAction { } else { updatePermissionsToPublic(dbSession, entityDto); } - projectIndexers.commitAndIndexEntities(dbSession, singletonList(entityDto), ProjectIndexer.Cause.PERMISSION_CHANGE); + indexers.commitAndIndexEntities(dbSession, singletonList(entityDto), Indexers.EntityEvent.PERMISSION_CHANGE); } response.noContent(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/projecttag/TagsWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/projecttag/TagsWsSupport.java index 5f5f88c3a3d..da16ab046d3 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/projecttag/TagsWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/projecttag/TagsWsSupport.java @@ -30,11 +30,11 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentFinder; -import org.sonar.server.es.ProjectIndexers; +import org.sonar.server.es.Indexers; import org.sonar.server.user.UserSession; import static java.util.Collections.singletonList; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_TAGS_UPDATE; +import static org.sonar.server.es.Indexers.EntityEvent.PROJECT_TAGS_UPDATE; import static org.sonar.server.exceptions.BadRequestException.checkRequest; public class TagsWsSupport { @@ -47,14 +47,14 @@ public class TagsWsSupport { private final DbClient dbClient; private final ComponentFinder componentFinder; private final UserSession userSession; - private final ProjectIndexers projectIndexers; + private final Indexers indexers; private final System2 system2; - public TagsWsSupport(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ProjectIndexers projectIndexers, System2 system2) { + public TagsWsSupport(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, Indexers indexers, System2 system2) { this.dbClient = dbClient; this.componentFinder = componentFinder; this.userSession = userSession; - this.projectIndexers = projectIndexers; + this.indexers = indexers; this.system2 = system2; } @@ -76,7 +76,7 @@ public class TagsWsSupport { projectOrApplication.setUpdatedAt(system2.now()); dbClient.projectDao().updateTags(dbSession, projectOrApplication); - projectIndexers.commitAndIndexProjects(dbSession, singletonList(projectOrApplication), PROJECT_TAGS_UPDATE); + indexers.commitAndIndexEntities(dbSession, singletonList(projectOrApplication), PROJECT_TAGS_UPDATE); } public static List checkAndUnifyTags(List tags) { diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index e46e8aa5909..dfc05cadc6a 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -82,7 +82,7 @@ import org.sonar.server.component.ComponentService; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.component.index.ComponentIndex; import org.sonar.server.component.index.ComponentIndexDefinition; -import org.sonar.server.component.index.ComponentIndexer; +import org.sonar.server.component.index.EntityDefinitionIndexer; import org.sonar.server.component.ws.ComponentViewerJsonWriter; import org.sonar.server.component.ws.ComponentsWsModule; import org.sonar.server.developers.ws.DevelopersWsModule; @@ -92,7 +92,7 @@ import org.sonar.server.duplication.ws.ShowResponseBuilder; import org.sonar.server.email.ws.EmailsWsModule; import org.sonar.server.es.IndexCreator; import org.sonar.server.es.IndexDefinitions; -import org.sonar.server.es.ProjectIndexersImpl; +import org.sonar.server.es.IndexersImpl; import org.sonar.server.es.RecoveryIndexer; import org.sonar.server.es.metadata.EsDbCompatibilityImpl; import org.sonar.server.es.metadata.MetadataIndexDefinition; @@ -434,7 +434,7 @@ public class PlatformLevel4 extends PlatformLevel { ComponentCleanerService.class, ComponentIndexDefinition.class, ComponentIndex.class, - ComponentIndexer.class, + EntityDefinitionIndexer.class, new LiveMeasureModule(), ComponentViewerJsonWriter.class, @@ -615,7 +615,7 @@ public class PlatformLevel4 extends PlatformLevel { new HttpRequestIdModule(), RecoveryIndexer.class, - ProjectIndexersImpl.class, + IndexersImpl.class, // telemetry TelemetryDataLoaderImpl.class, -- 2.39.5