소스 검색

SONAR-19558 Refactor Project Indexers

tags/10.2.0.77647
Duarte Meneses 11 달 전
부모
커밋
0b24d4b1fa
85개의 변경된 파일1059개의 추가작업 그리고 1039개의 파일을 삭제
  1. 7
    12
      server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStepIT.java
  2. 5
    5
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java
  3. 7
    7
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/IndexAnalysisStep.java
  4. 4
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java
  5. 4
    4
      server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
  6. 1
    28
      server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java
  7. 2
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java
  8. 1
    1
      server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java
  9. 0
    4
      server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
  10. 3
    9
      server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml
  11. 30
    28
      server/sonar-server-common/src/it/java/org/sonar/server/component/index/EntityDefinitionIndexerIT.java
  12. 103
    82
      server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java
  13. 16
    17
      server/sonar-server-common/src/it/java/org/sonar/server/measure/index/ProjectMeasuresIndexerIT.java
  14. 33
    28
      server/sonar-server-common/src/main/java/org/sonar/server/component/index/EntityDefinitionIndexer.java
  15. 43
    0
      server/sonar-server-common/src/main/java/org/sonar/server/es/AnalysisIndexer.java
  16. 6
    19
      server/sonar-server-common/src/main/java/org/sonar/server/es/BranchIndexer.java
  17. 13
    18
      server/sonar-server-common/src/main/java/org/sonar/server/es/EventIndexer.java
  18. 81
    0
      server/sonar-server-common/src/main/java/org/sonar/server/es/Indexers.java
  19. 76
    0
      server/sonar-server-common/src/main/java/org/sonar/server/es/IndexersImpl.java
  20. 0
    64
      server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java
  21. 0
    48
      server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java
  22. 2
    2
      server/sonar-server-common/src/main/java/org/sonar/server/es/ResilientIndexer.java
  23. 2
    2
      server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java
  24. 95
    34
      server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexer.java
  25. 44
    22
      server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java
  26. 3
    3
      server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationDoc.java
  27. 6
    6
      server/sonar-server-common/src/main/java/org/sonar/server/permission/index/AuthorizationScope.java
  28. 3
    1
      server/sonar-server-common/src/main/java/org/sonar/server/permission/index/NeedAuthorizationIndexer.java
  29. 103
    0
      server/sonar-server-common/src/test/java/org/sonar/server/es/IndexersImplTest.java
  30. 0
    55
      server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java
  31. 0
    120
      server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java
  32. 3
    5
      server/sonar-server-common/src/test/java/org/sonar/server/es/StartupIndexerTest.java
  33. 2
    2
      server/sonar-server-common/src/test/java/org/sonar/server/permission/index/AuthorizationDocTest.java
  34. 65
    0
      server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestIndexers.java
  35. 0
    1
      server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java
  36. 14
    22
      server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java
  37. 1
    1
      server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexSearchTest.java
  38. 1
    1
      server/sonar-webserver-es/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java
  39. 2
    28
      server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/FooIndexer.java
  40. 11
    21
      server/sonar-webserver-es/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java
  41. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java
  42. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java
  43. 2
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java
  44. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java
  45. 3
    5
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
  46. 3
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java
  47. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java
  48. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java
  49. 30
    41
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java
  50. 5
    6
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentServiceUpdateKeyIT.java
  51. 10
    26
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java
  52. 2
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchActionIT.java
  53. 1
    1
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
  54. 26
    26
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java
  55. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/measure/live/LiveMeasureComputerImplIT.java
  56. 4
    4
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/PermissionTemplateServiceIT.java
  57. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/BasePermissionWsIT.java
  58. 2
    2
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java
  59. 4
    4
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionIT.java
  60. 3
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java
  61. 8
    5
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java
  62. 4
    22
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java
  63. 4
    4
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateKeyActionIT.java
  64. 5
    5
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/UpdateVisibilityActionIT.java
  65. 9
    9
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/projecttag/ws/SetActionIT.java
  66. 2
    4
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java
  67. 2
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java
  68. 2
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java
  69. 2
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java
  70. 2
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java
  71. 8
    8
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java
  72. 12
    21
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java
  73. 2
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCreationData.java
  74. 6
    6
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentService.java
  75. 29
    36
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java
  76. 9
    8
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java
  77. 7
    7
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java
  78. 6
    6
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionTemplateService.java
  79. 5
    6
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionUpdater.java
  80. 3
    2
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
  81. 14
    13
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java
  82. 1
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java
  83. 6
    6
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java
  84. 6
    6
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/projecttag/TagsWsSupport.java
  85. 4
    4
      server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java

+ 7
- 12
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

+ 5
- 5
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<String> disabledComponentUuids) {
componentIndexer.delete(projectUuid, disabledComponentUuids);
entityDefinitionIndexer.delete(projectUuid, disabledComponentUuids);
}

@Override

+ 7
- 7
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<ProjectIndexer> projectIndexerConsumer = getProjectIndexerConsumer(branchUuid);
for (ProjectIndexer indexer : indexers) {
Consumer<AnalysisIndexer> analysisIndexerConsumer = getAnalysisIndexerConsumer(branchUuid);
for (AnalysisIndexer indexer : indexers) {
LOGGER.debug("Call {}", indexer);
projectIndexerConsumer.accept(indexer);
analysisIndexerConsumer.accept(indexer);
}
}

private Consumer<ProjectIndexer> getProjectIndexerConsumer(String branchUuid) {
private Consumer<AnalysisIndexer> getAnalysisIndexerConsumer(String branchUuid) {
Set<String> fileUuidsMarkedAsUnchanged = fileStatuses.getFileUuidsMarkedAsUnchanged();
return isBranchNeedIssueSync(branchUuid)
? (indexer -> indexer.indexOnAnalysis(branchUuid))

+ 4
- 4
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<String> uuids = singletonList(uuid);
underTest.onComponentsDisabling(projectUuid, uuids);

verify(componentIndexer).delete(projectUuid, uuids);
verify(entityDefinitionIndexer).delete(projectUuid, uuids);
}

@Test

+ 4
- 4
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,

+ 1
- 28
server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java 파일 보기

@@ -162,36 +162,9 @@ public class EntityDaoIT {

List<EntityDto> result = new LinkedList<>();
ResultHandler<EntityDto> 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<EntityDto> result = new LinkedList<>();
ResultHandler<EntityDto> 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<EntityDto> result = new LinkedList<>();
ResultHandler<EntityDto> handler = resultContext -> result.add(resultContext.getResultObject());
entityDao.scrollForIndexing(db.getSession(), "unknown", handler);

assertThat(result).isEmpty();
}
}

+ 2
- 2
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<EntityDto> handler) {
mapper(session).scrollForIndexing(entityUuid, handler);
public void scrollForIndexing(DbSession session, ResultHandler<EntityDto> handler) {
mapper(session).scrollForIndexing(handler);
}

private static EntityMapper mapper(DbSession session) {

+ 1
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java 파일 보기

@@ -40,5 +40,5 @@ public interface EntityMapper {

List<EntityDto> selectByKeys(@Param("keys") Collection<String> keys);

void scrollForIndexing(@Param("entityUuid") @Nullable String entityUuid, ResultHandler<EntityDto> handler);
void scrollForIndexing(ResultHandler<EntityDto> handler);
}

+ 0
- 4
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());
}

+ 3
- 9
server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml 파일 보기

@@ -85,17 +85,11 @@
</foreach>)
</select>

<select id="scrollForIndexing" parameterType="map" resultType="Entity" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
<select id="scrollForIndexing" resultType="Entity" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
(select <include refid="entityProjectColumns"/>
from projects p
<if test="entityUuid != null">
where p.uuid = #{entityUuid,jdbcType=VARCHAR}
</if>)
from projects p)
UNION
(select <include refid="entityPortfolioColumns"/>
from portfolios p
<if test="entityUuid != null">
where p.uuid = #{entityUuid,jdbcType=VARCHAR}
</if>)
from portfolios p)
</select>
</mapper>

server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java → 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<EsQueueDto> items = underTest.prepareForRecovery(dbSession, singletonList(entity.getUuid()), cause);
Collection<EsQueueDto> items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(project.getUuid()), cause);
dbSession.commit();
return underTest.index(dbSession, items);
}

+ 103
- 82
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<IndexPermissions> projectPredicate = scope.getProjectPredicate();
Predicate<IndexPermissions> 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<IndexType> 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<EsQueueDto> items = underTest.prepareForRecovery(db.getSession(), singletonList(projectUuid), cause);
private IndexingResult indexBranch(String branchUuid, Indexers.BranchEvent cause) {
Collection<EsQueueDto> items = underTest.prepareForRecoveryOnBranchEvent(db.getSession(), singletonList(branchUuid), cause);
db.commit();
return underTest.index(db.getSession(), items);
}

private IndexingResult indexProject(String projectUuid, EntityEvent cause) {
Collection<EsQueueDto> 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<String> 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) {

+ 16
- 17
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<IndexPermissions> projectPredicate = scope.getProjectPredicate();
Predicate<IndexPermissions> 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<EsQueueDto> items = underTest.prepareForRecovery(dbSession, singletonList(project.getUuid()), cause);
Collection<EsQueueDto> items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(project.getUuid()), cause);
dbSession.commit();
return underTest.index(dbSession, items);
}

server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java → 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<IndexType> 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<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> 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<EsQueueDto> 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<EsQueueDto> prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection<String> 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<EsQueueDto> 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<EsQueueDto> prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection<String> branchUuids, Indexers.BranchEvent cause) {
return emptyList();
}

@Override
@@ -130,13 +138,10 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe
Set<String> entityUuids = items.stream().map(EsQueueDto::getDocId).collect(MoreCollectors.toHashSet(items.size()));
Set<String> 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();

+ 43
- 0
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<String> unchangedComponentUuids);
}

server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexer.java → 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<String> unchangedComponentUuids);
void indexBranchOnAnalysis(String branchUuid, Set<String> unchangedComponentUuids);

Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> projectUuids, ProjectIndexer.Cause cause);
Collection<EsQueueDto> prepareBranchIndexForRecovery(DbSession dbSession, Collection<String> branchUuids, BranchIndexer.Cause cause);
}

server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java → 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<String, ProjectIndexer.Cause> calls = ArrayListMultimap.create();

@Override
public void commitAndIndexByProjectUuids(DbSession dbSession, Collection<String> 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<EsQueueDto> prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection<String> entityUuids, Indexers.EntityEvent cause);

public boolean hasBeenCalled(String projectUuid, ProjectIndexer.Cause expectedCause) {
return calls.get(projectUuid).contains(expectedCause);
}
Collection<EsQueueDto> prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection<String> branchUuids, Indexers.BranchEvent cause);

public boolean hasBeenCalled(String projectUuid) {
return calls.containsKey(projectUuid);
}
}

+ 81
- 0
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<String> 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<String> 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<? extends EntityDto> entities, EntityEvent cause) {
Collection<String> 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<BranchDto> branches, BranchEvent cause) {
Collection<String> branchUuids = branches.stream()
.map(BranchDto::getUuid)
.collect(Collectors.toSet());
commitAndIndexOnBranchEvent(dbSession, branchUuids, cause);
}
}

+ 76
- 0
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<EventIndexer> 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<String> 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<String> branchUuids, BranchEvent cause) {
indexOnEvent(dbSession, indexer -> indexer.prepareForRecoveryOnBranchEvent(dbSession, branchUuids, cause));
}


private void indexOnEvent(DbSession dbSession, Function<EventIndexer, Collection<EsQueueDto>> esQueueSupplier) {
Map<EventIndexer, Collection<EsQueueDto>> 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));
}
}

+ 0
- 64
server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexers.java 파일 보기

@@ -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<String> projectUuids, ProjectIndexer.Cause cause);

default void commitAndIndexEntities(DbSession dbSession, Collection<? extends EntityDto> entities, ProjectIndexer.Cause cause) {
Collection<String> entityUuids = entities.stream()
.map(EntityDto::getUuid)
.collect(MoreCollectors.toSet(entities.size()));
commitAndIndexByProjectUuids(dbSession, entityUuids, cause);
}

default void commitAndIndexProjects(DbSession dbSession, Collection<ProjectDto> projects, ProjectIndexer.Cause cause) {
commitAndIndexEntities(dbSession, projects, cause);
}

default void commitAndIndexComponents(DbSession dbSession, Collection<ComponentDto> projects, ProjectIndexer.Cause cause) {
Collection<String> projectUuids = projects.stream()
.map(ComponentDto::branchUuid)
.collect(MoreCollectors.toSet(projects.size()));
commitAndIndexByProjectUuids(dbSession, projectUuids, cause);
}

default void commitAndIndexBranches(DbSession dbSession, Collection<BranchDto> branches, ProjectIndexer.Cause cause) {
Collection<String> branchUuids = branches.stream()
.map(BranchDto::getUuid)
.toList();
commitAndIndexByProjectUuids(dbSession, branchUuids, cause);
}
}

+ 0
- 48
server/sonar-server-common/src/main/java/org/sonar/server/es/ProjectIndexersImpl.java 파일 보기

@@ -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<ProjectIndexer> indexers;

public ProjectIndexersImpl(ProjectIndexer... indexers) {
this.indexers = asList(indexers);
}

@Override
public void commitAndIndexByProjectUuids(DbSession dbSession, Collection<String> projectUuids, ProjectIndexer.Cause cause) {
Map<ProjectIndexer, Collection<EsQueueDto>> 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));
}
}

+ 2
- 2
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

+ 2
- 2
server/sonar-server-common/src/main/java/org/sonar/server/es/StartupIndexer.java 파일 보기

@@ -34,7 +34,7 @@ public interface StartupIndexer {
}

default void triggerAsyncIndexOnStartup(Set<IndexType> 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<IndexType> uninitializedIndexTypes) {
throw new IllegalStateException("SYNCHRONE StartupIndexer must implement indexOnStartup");
throw new IllegalStateException("SYNCHRONOUS StartupIndexer must implement indexOnStartup");
}

Set<IndexType> getIndexTypes();

+ 95
- 34
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<IndexType> INDEX_TYPES = Set.of(TYPE_ISSUE);

private final EsClient esClient;
@@ -127,23 +141,44 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer {
}

@Override
public Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> projectUuids, ProjectIndexer.Cause cause) {
switch (cause) {
case PROJECT_CREATION, MEASURE_CHANGE, PROJECT_KEY_UPDATE, PROJECT_TAGS_UPDATE, PERMISSION_CHANGE:
public Collection<EsQueueDto> prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection<String> 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<EsQueueDto> 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<EsQueueDto> items = createProjectDeleteRecoveryItems(entityUuids);
yield dbClient.esQueueDao().insert(dbSession, items);
}
};
}

default:
// defensive case
throw new IllegalStateException("Unsupported cause: " + cause);
}
@Override
public Collection<EsQueueDto> prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection<String> 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<EsQueueDto> items = createBranchRecoveryItems(branchUuids);
yield dbClient.esQueueDao().insert(dbSession, items);
}
};
}

private List<EsQueueDto> createProjectDeleteRecoveryItems(Collection<String> entityUuids) {
return entityUuids.stream()
.map(entityUuid -> createQueueDto(entityUuid, ID_TYPE_DELETE_PROJECT_UUID, entityUuid))
.collect(Collectors.toList());
}

private List<EsQueueDto> createBranchRecoveryItems(Collection<String> 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<EsQueueDto> items) {
ListMultimap<String, EsQueueDto> itemsByIssueKey = ArrayListMultimap.create();
ListMultimap<String, EsQueueDto> itemsByProjectUuid = ArrayListMultimap.create();
ListMultimap<String, EsQueueDto> itemsByBranchUuid = ArrayListMultimap.create();
ListMultimap<String, EsQueueDto> 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<String, EsQueueDto> itemsByProjectUuid) {
if (itemsByProjectUuid.isEmpty()) {
private IndexingResult doDeleteProjectIndexItems(DbSession dbSession, ListMultimap<String, EsQueueDto> 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<String, EsQueueDto> 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<BranchDto> 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));
}

+ 44
- 22
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<IndexType> 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<String> unchangedComponentUuids) {
doIndex(Size.REGULAR, projectUuid);
public void indexOnAnalysis(String branchUuid, Set<String> unchangedComponentUuids) {
doIndex(Size.REGULAR, branchUuid);
}

@Override
public Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> 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<EsQueueDto> prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection<String> 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<EsQueueDto> 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<EsQueueDto> prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection<String> branchUuids, Indexers.BranchEvent cause) {
return switch (cause) {
case DELETION -> Collections.emptyList();
case MEASURE_CHANGE -> {
Set<String> entityUuids = dbClient.branchDao().selectByUuids(dbSession, branchUuids)
.stream().map(BranchDto::getProjectUuid)
.collect(Collectors.toSet());
yield prepareForRecovery(dbSession, entityUuids);
}
};
}

private Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> entityUuids) {
List<EsQueueDto> 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<String> projectUuids) {

+ 3
- 3
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) {

+ 6
- 6
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<IndexPermissions> projectPredicate;
private final Predicate<IndexPermissions> entityPredicate;

public AuthorizationScope(IndexRelationType functionalType, Predicate<IndexPermissions> projectPredicate) {
public AuthorizationScope(IndexRelationType functionalType, Predicate<IndexPermissions> 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<IndexPermissions> getProjectPredicate() {
return projectPredicate;
public Predicate<IndexPermissions> getEntityPredicate() {
return entityPredicate;
}
}

+ 3
- 1
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.
*/

+ 103
- 0
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<EsQueueDto> items1 = List.of(EsQueueDto.create("fake/fake1", "P1"), EsQueueDto.create("fake/fake1", "P1"));
List<EsQueueDto> 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<EsQueueDto> items1 = List.of(EsQueueDto.create("fake/fake1", "P1"), EsQueueDto.create("fake/fake1", "P1"));
List<EsQueueDto> 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);
}
}

+ 0
- 55
server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersImplTest.java 파일 보기

@@ -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<String> calls = new ArrayList<>();

@Override
public void commitAndIndexByProjectUuids(DbSession dbSession, Collection<String> projectUuids, Cause cause) {
calls.addAll(projectUuids);
}
}
}

+ 0
- 120
server/sonar-server-common/src/test/java/org/sonar/server/es/ProjectIndexersTest.java 파일 보기

@@ -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<String> calledProjectUuids;
ProjectIndexer.Cause cause;

@Override
public void commitAndIndexByProjectUuids(DbSession dbSession, Collection<String> projectUuids, ProjectIndexer.Cause cause) {
this.calledProjectUuids = projectUuids;
this.cause = cause;
}
}

private static class FakeIndexer implements ProjectIndexer {

private final List<EsQueueDto> items;
private Collection<EsQueueDto> calledItems;

private FakeIndexer(List<EsQueueDto> items) {
this.items = items;
}

@Override
public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
throw new UnsupportedOperationException();
}

@Override
public Set<IndexType> getIndexTypes() {
throw new UnsupportedOperationException();
}

@Override
public Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> projectUuids, Cause cause) {
return items;
}

@Override
public IndexingResult index(DbSession dbSession, Collection<EsQueueDto> items) {
this.calledItems = items;
return new IndexingResult();
}

@Override
public void indexOnAnalysis(String branchUuid) {
throw new UnsupportedOperationException();
}

@Override
public void indexOnAnalysis(String branchUuid, Set<String> unchangedComponentUuids) {
throw new UnsupportedOperationException();
}
}
}

+ 3
- 5
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");
}

}

+ 2
- 2
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

+ 65
- 0
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<String, EntityEvent> entityCalls = ArrayListMultimap.create();
private final ListMultimap<String, BranchEvent> branchCalls = ArrayListMultimap.create();

@Override
public void commitAndIndexOnEntityEvent(DbSession dbSession, Collection<String> entityUuids, EntityEvent cause) {
dbSession.commit();
entityUuids.forEach(entityUuid -> entityCalls.put(entityUuid, cause));
}

@Override
public void commitAndIndexOnBranchEvent(DbSession dbSession, Collection<String> 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);
}
}

+ 0
- 1
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);

+ 14
- 22
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<AuthorizationScope> 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<String> unchangedComponentUuids) {
// nothing to do, permissions don't change during an analysis
}

@Override
public Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> projectUuids, ProjectIndexer.Cause cause) {
public Collection<EsQueueDto> prepareForRecoveryOnEntityEvent(DbSession dbSession, Collection<String> 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<EsQueueDto> prepareForRecoveryOnBranchEvent(DbSession dbSession, Collection<String> branchUuids, Indexers.BranchEvent cause) {
return emptyList();
}

private Collection<EsQueueDto> insertIntoEsQueue(DbSession dbSession, Collection<String> projectUuids) {
List<EsQueueDto> 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);

+ 1
- 1
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);


+ 1
- 1
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);


+ 2
- 28
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<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> 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<IndexType> uninitializedIndexTypes) {
throw new UnsupportedOperationException();
}

@Override
public Set<IndexType> getIndexTypes() {
return ImmutableSet.of(TYPE_FOO);
}

@Override
public IndexingResult index(DbSession dbSession, Collection<EsQueueDto> items) {
throw new UnsupportedOperationException();
}
}

+ 11
- 21
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<EsQueueDto> 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<EsQueueDto> items = underTest.prepareForRecovery(dbSession, singletonList(entity.getUuid()), cause);
Collection<EsQueueDto> items = underTest.prepareForRecoveryOnEntityEvent(dbSession, singletonList(entity.getUuid()), cause);
dbSession.commit();
return underTest.index(dbSession, items);
}

+ 2
- 2
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);

+ 2
- 2
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);

+ 2
- 3
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);

+ 2
- 2
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);

+ 3
- 5
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));
}

+ 3
- 3
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();

+ 2
- 2
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<ComponentDto>) 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

+ 2
- 2
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,

+ 30
- 41
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) {

+ 5
- 6
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<PushEventDto> 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

+ 10
- 26
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<BranchDto> 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<BranchDto> 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<BranchDto> 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<BranchDto> 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<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), app.branchUuid());
assertThat(branch).isPresent();

+ 2
- 3
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);


+ 1
- 1
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() {

+ 26
- 26
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()

+ 2
- 2
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;

+ 4
- 4
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

+ 2
- 2
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<A extends PermissionsWsAction> {

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()));
}

+ 2
- 2
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<ApplyTemplateActio
private final ResourceTypesRule resourceTypesRule = new ResourceTypesRule().setRootQualifiers(PROJECT, VIEW, APP);
private final DefaultTemplatesResolver defaultTemplatesResolver = new DefaultTemplatesResolverImpl(dbTester.getDbClient(), resourceTypesRule);
private final PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
new TestProjectIndexers(), userSession, defaultTemplatesResolver, new SequenceUuidFactory());
new TestIndexers(), userSession, defaultTemplatesResolver, new SequenceUuidFactory());

@Override
protected ApplyTemplateAction buildWsAction() {

+ 4
- 4
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionIT.java 파일 보기

@@ -39,8 +39,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.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.l18n.I18nRule;
@@ -71,14 +71,14 @@ public class BulkApplyTemplateActionIT extends BasePermissionWsIT<BulkApplyTempl
private GroupDto group1;
private GroupDto group2;
private PermissionTemplateDto template1;
private final ProjectIndexers projectIndexers = new TestProjectIndexers();
private final Indexers indexers = new TestIndexers();
private final ResourceTypesRule resourceTypesRule = new ResourceTypesRule().setRootQualifiers(PROJECT, VIEW, APP);
private final DefaultTemplatesResolver defaultTemplatesResolver = new DefaultTemplatesResolverImpl(db.getDbClient(), resourceTypesRule);

@Override
protected BulkApplyTemplateAction buildWsAction() {
PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
projectIndexers, userSession, defaultTemplatesResolver, new SequenceUuidFactory());
indexers, userSession, defaultTemplatesResolver, new SequenceUuidFactory());
return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
}


+ 3
- 3
server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java 파일 보기

@@ -238,7 +238,7 @@ public class BulkDeleteActionIT {
.setParam("projects", StringUtils.join(keys, ","))
.execute();

verify(componentCleanerService, times(1_000)).delete(any(DbSession.class), any(EntityDto.class));
verify(componentCleanerService, times(1_000)).deleteEntity(any(DbSession.class), any(EntityDto.class));
ArgumentCaptor<Set<Project>> 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<EntityDto> 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());

+ 8
- 5
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

+ 4
- 22
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<ProjectDto> 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();
}


+ 4
- 4
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));


+ 5
- 5
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

+ 9
- 9
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

+ 2
- 4
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) {

+ 2
- 3
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) {

+ 2
- 3
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) {

+ 2
- 3
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) {

+ 2
- 3
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);
}

}

+ 8
- 8
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<String, String> 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) {

+ 12
- 21
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<ProjectDto> 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);
}
}

+ 2
- 1
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) {
}

+ 6
- 6
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);

+ 29
- 36
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<String> MAIN_BRANCH_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.APP);
private static final Set<String> 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<ComponentDto> 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<ComponentDto> 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<ComponentDto> 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) {

+ 9
- 8
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<String> 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(

+ 7
- 7
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

+ 6
- 6
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) {

+ 5
- 6
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) {

+ 3
- 2
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<EntityDto> 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();

+ 14
- 13
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();
}


+ 1
- 1
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)));
}


+ 6
- 6
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();

+ 6
- 6
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<String> checkAndUnifyTags(List<String> tags) {

+ 4
- 4
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,

Loading…
취소
저장