From: Jacek Date: Fri, 5 Jun 2020 07:12:30 +0000 (+0200) Subject: SONAR-13398 extract common component for checking issue sync status X-Git-Tag: 8.4.0.35506~60 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9cad39aca828793ec1da0525e92d37e583cce5f2;p=sonarqube.git SONAR-13398 extract common component for checking issue sync status --- diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/es/EsIndexSyncInProgressException.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/es/EsIndexSyncInProgressException.java new file mode 100644 index 00000000000..bc75d400841 --- /dev/null +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/es/EsIndexSyncInProgressException.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 org.sonar.server.es.IndexType.IndexMainType; + +public class EsIndexSyncInProgressException extends RuntimeException { + + private IndexMainType indexType; + + public EsIndexSyncInProgressException(IndexMainType indexType) { + super(String.format("Synchronization of %s index is in progress", indexType.toString())); + this.indexType = indexType; + } + + public IndexMainType getIndexType() { + return indexType; + } +} diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 67fafd572d5..fc652c7b454 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -86,7 +86,6 @@ import org.sonar.server.es.searchrequest.TopAggregationDefinition; import org.sonar.server.es.searchrequest.TopAggregationDefinition.SimpleFieldFilterScope; import org.sonar.server.es.searchrequest.TopAggregationHelper; import org.sonar.server.issue.index.IssueQuery.PeriodStart; -import org.sonar.server.measure.Rating; import org.sonar.server.permission.index.AuthorizationDoc; import org.sonar.server.permission.index.WebAuthorizationTypeSupport; import org.sonar.server.security.SecurityStandards; diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndexSyncProgressChecker.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndexSyncProgressChecker.java new file mode 100644 index 00000000000..d728139e487 --- /dev/null +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndexSyncProgressChecker.java @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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.issue.index; + +import com.google.common.collect.Sets; +import java.util.List; +import java.util.Set; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.project.ProjectDto; +import org.sonar.server.es.EsIndexSyncInProgressException; + +public class IssueIndexSyncProgressChecker { + private final DbClient dbClient; + + public IssueIndexSyncProgressChecker(DbClient dbClient) { + this.dbClient = dbClient; + } + + public IssueSyncProgress getIssueSyncProgress(DbSession dbSession) { + int completed = dbClient.branchDao().countByNeedIssueSync(dbSession, false); + int total = dbClient.branchDao().countAll(dbSession); + return new IssueSyncProgress(completed, total); + } + + /** + * Checks if issue index sync is in progress, if it is, method throws exception org.sonar.server.es.EsIndexSyncInProgressException + */ + public void checkIfIssueSyncInProgress(DbSession dbSession) throws EsIndexSyncInProgressException { + if (isIssueSyncInProgress(dbSession)) { + throw new EsIndexSyncInProgressException(IssueIndexDefinition.TYPE_ISSUE.getMainType()); + } + } + + /** + * Checks if project issue index sync is in progress, if it is, method throws exception org.sonar.server.es.EsIndexSyncInProgressException + */ + public void checkIfProjectIssueSyncInProgress(DbSession dbSession, ProjectDto projectDto) throws EsIndexSyncInProgressException { + if (doProjectNeedIssueSync(dbSession, projectDto.getUuid())) { + throw new EsIndexSyncInProgressException(IssueIndexDefinition.TYPE_ISSUE.getMainType()); + } + } + + public boolean isIssueSyncInProgress(DbSession dbSession) throws EsIndexSyncInProgressException { + return dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(dbSession, true); + } + + public boolean doProjectNeedIssueSync(DbSession dbSession, String projectUuid) { + return !findProjectUuidsWithIssuesSyncNeed(dbSession, Sets.newHashSet(projectUuid)).isEmpty(); + } + + public List findProjectUuidsWithIssuesSyncNeed(DbSession dbSession, Set projectUuids) { + return dbClient.branchDao().selectProjectUuidsWithIssuesNeedSync(dbSession, projectUuids); + } +} diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueSyncProgress.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueSyncProgress.java new file mode 100644 index 00000000000..193db999a9c --- /dev/null +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueSyncProgress.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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.issue.index; + +public class IssueSyncProgress { + private static final int PERCENT_100 = 100; + + private final int completed; + private final int total; + + public IssueSyncProgress(int completed, int total) { + this.completed = completed; + this.total = total; + } + + public int getCompleted() { + return completed; + } + + public int getTotal() { + return total; + } + + public int toPercentCompleted() { + if (total != 0) { + return (int) Math.floor(PERCENT_100 * (double) completed / total); + } + return PERCENT_100; + } + + public boolean isCompleted() { + return completed == total; + } +} diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSyncProgressCheckerTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSyncProgressCheckerTest.java new file mode 100644 index 00000000000..3315c8cb37e --- /dev/null +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSyncProgressCheckerTest.java @@ -0,0 +1,116 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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.issue.index; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.stream.IntStream; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.db.project.ProjectDto; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(DataProviderRunner.class) +public class IssueIndexSyncProgressCheckerTest { + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient()); + + @Test + public void return_100_if_there_is_no_tasks_left() { + IssueSyncProgress issueSyncProgress = underTest.getIssueSyncProgress(db.getSession()); + assertThat(issueSyncProgress.getCompleted()).isZero(); + assertThat(issueSyncProgress.getTotal()).isZero(); + assertThat(issueSyncProgress.toPercentCompleted()).isEqualTo(100); + assertThat(issueSyncProgress.isCompleted()).isTrue(); + } + + @Test + public void return_100_if_all_branches_have_need_issue_sync_set_FALSE() { + IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(false, 2)); + IntStream.range(0, 14).forEach(value -> insertProjectWithBranches(false, 4)); + IntStream.range(0, 4).forEach(value -> insertProjectWithBranches(false, 10)); + + IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); + assertThat(result.getCompleted()).isEqualTo(153); + assertThat(result.getTotal()).isEqualTo(153); + assertThat(result.toPercentCompleted()).isEqualTo(100); + assertThat(result.isCompleted()).isTrue(); + } + + @Test + @UseDataProvider("various_task_numbers") + public void return_correct_percent_value_for_branches_to_sync(int toSync, int synced, int expectedPercent, boolean isCompleted) { + IntStream.range(0, toSync).forEach(value -> insertProjectWithBranches(true, 0)); + IntStream.range(0, synced).forEach(value -> insertProjectWithBranches(false, 0)); + + IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); + assertThat(result.getCompleted()).isEqualTo(synced); + assertThat(result.getTotal()).isEqualTo(toSync + synced); + assertThat(result.toPercentCompleted()).isEqualTo(expectedPercent); + assertThat(result.isCompleted()).isEqualTo(isCompleted); + } + + @DataProvider + public static Object[][] various_task_numbers() { + return new Object[][] { + // toSync, synced, expected result, expectedCompleted + {0, 0, 100, true}, + {0, 9, 100, true}, + {10, 0, 0, false}, + {99, 1, 1, false}, + {2, 1, 33, false}, + {6, 4, 40, false}, + {7, 7, 50, false}, + {1, 2, 66, false}, + {4, 10, 71, false}, + {1, 99, 99, false}, + }; + } + + @Test + public void return_0_if_all_branches_have_need_issue_sync_set_TRUE() { + // only project + IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0)); + + // project + additional branch + IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1)); + + IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); + assertThat(result.getCompleted()).isZero(); + assertThat(result.getTotal()).isEqualTo(30); + assertThat(result.toPercentCompleted()).isZero(); + assertThat(result.isCompleted()).isFalse(); + } + + private void insertProjectWithBranches(boolean needIssueSync, int numberOfBranches) { + ProjectDto projectDto = db.components() + .insertPrivateProjectDto(db.getDefaultOrganization(), branchDto -> branchDto.setNeedIssueSync(needIssueSync)); + IntStream.range(0, numberOfBranches).forEach( + i -> db.components().insertProjectBranch(projectDto, branchDto -> branchDto.setNeedIssueSync(needIssueSync))); + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/IndexationStatusAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/IndexationStatusAction.java index bc165c46966..723833d1bc5 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/IndexationStatusAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/IndexationStatusAction.java @@ -24,16 +24,19 @@ 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.server.issue.index.IssueIndexSyncProgressChecker; +import org.sonar.server.issue.index.IssueSyncProgress; import org.sonarqube.ws.Ce.IndexationStatusWsResponse; import static org.sonar.server.ws.WsUtils.writeProtobuf; public class IndexationStatusAction implements CeWsAction { - private static final int PERCENT_100 = 100; + private final IssueIndexSyncProgressChecker issueIndexSyncChecker; private final DbClient dbClient; - public IndexationStatusAction(DbClient dbClient) { + public IndexationStatusAction(DbClient dbClient, IssueIndexSyncProgressChecker issueIndexSyncChecker) { this.dbClient = dbClient; + this.issueIndexSyncChecker = issueIndexSyncChecker; } @Override @@ -53,19 +56,15 @@ public class IndexationStatusAction implements CeWsAction { } private IndexationStatusWsResponse doHandle() { + IssueSyncProgress issueSyncProgress; try (DbSession dbSession = dbClient.openSession(false)) { - int branchesToProcess = dbClient.branchDao().countByNeedIssueSync(dbSession, false); - int total = dbClient.branchDao().countAll(dbSession); - - int percentCompleted = PERCENT_100; - if (total != 0) { - percentCompleted = (int) Math.floor(PERCENT_100 * (double) branchesToProcess / total); - } - return IndexationStatusWsResponse.newBuilder() - .setIsCompleted(percentCompleted == PERCENT_100) - .setPercentCompleted(percentCompleted) - .build(); + issueSyncProgress = issueIndexSyncChecker.getIssueSyncProgress(dbSession); } + + return IndexationStatusWsResponse.newBuilder() + .setIsCompleted(issueSyncProgress.isCompleted()) + .setPercentCompleted(issueSyncProgress.toPercentCompleted()) + .build(); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java index 860430e873d..52339a0e6d1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java @@ -63,6 +63,7 @@ import org.sonar.server.component.ws.SearchProjectsAction.SearchResults.SearchRe import org.sonar.server.es.Facets; import org.sonar.server.es.SearchIdResult; import org.sonar.server.es.SearchOptions; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.measure.index.ProjectMeasuresIndex; import org.sonar.server.measure.index.ProjectMeasuresQuery; import org.sonar.server.project.Visibility; @@ -119,14 +120,18 @@ public class SearchProjectsAction implements ComponentsWsAction { private final UserSession userSession; private final ProjectsInWarning projectsInWarning; private final PlatformEditionProvider editionProvider; + private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker; - public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, UserSession userSession, ProjectsInWarning projectsInWarning, - PlatformEditionProvider editionProvider) { + public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, UserSession userSession, + ProjectsInWarning projectsInWarning, + PlatformEditionProvider editionProvider, + IssueIndexSyncProgressChecker issueIndexSyncProgressChecker) { this.dbClient = dbClient; this.index = index; this.userSession = userSession; this.projectsInWarning = projectsInWarning; this.editionProvider = editionProvider; + this.issueIndexSyncProgressChecker = issueIndexSyncProgressChecker; } @Override @@ -300,7 +305,7 @@ public class SearchProjectsAction implements ComponentsWsAction { } private List getProjectUuidsWithBranchesNeedIssueSync(DbSession dbSession, Set projectUuids) { - return dbClient.branchDao().selectProjectUuidsWithIssuesNeedSync(dbSession, projectUuids); + return issueIndexSyncProgressChecker.findProjectUuidsWithIssuesSyncNeed(dbSession, projectUuids); } private Set getQualifiersBasedOnEdition(ProjectMeasuresQuery query) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java index 2dd0bf2a036..55b69539fb1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java @@ -20,7 +20,6 @@ package org.sonar.server.component.ws; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import java.util.List; import java.util.Optional; import java.util.Set; @@ -39,6 +38,7 @@ import org.sonar.db.component.SnapshotDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Components; import org.sonarqube.ws.Components.ShowWsResponse; @@ -61,11 +61,14 @@ public class ShowAction implements ComponentsWsAction { private final UserSession userSession; private final DbClient dbClient; private final ComponentFinder componentFinder; + private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker; - public ShowAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder) { + public ShowAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder, + IssueIndexSyncProgressChecker issueIndexSyncProgressChecker) { this.userSession = userSession; this.dbClient = dbClient; this.componentFinder = componentFinder; + this.issueIndexSyncProgressChecker = issueIndexSyncProgressChecker; } @Override @@ -164,10 +167,10 @@ public class ShowAction implements ComponentsWsAction { private boolean needIssueSync(DbSession dbSession, ComponentDto component, @Nullable ProjectDto projectDto) { if (projectDto == null || VIEW_OR_SUBVIEW_QUALIFIERS.contains(component.qualifier())) { - return dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(dbSession, true); + return issueIndexSyncProgressChecker.isIssueSyncInProgress(dbSession); } - return !dbClient.branchDao().selectProjectUuidsWithIssuesNeedSync(dbSession, Sets.newHashSet(projectDto.getUuid())).isEmpty(); + return issueIndexSyncProgressChecker.doProjectNeedIssueSync(dbSession, projectDto.getUuid()); } private static Request toShowWsRequest(org.sonar.api.server.ws.Request request) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java index d1063417f92..31ddc1d5c14 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java @@ -40,6 +40,7 @@ import org.sonar.db.DbSession; import org.sonar.db.dialect.H2; import org.sonar.server.almsettings.MultipleAlmFeatureProvider; import org.sonar.server.branch.BranchFeatureProxy; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.OrganizationFlags; import org.sonar.server.platform.WebServer; @@ -83,11 +84,12 @@ public class GlobalAction implements NavigationWsAction, Startable { private final PlatformEditionProvider editionProvider; private final MultipleAlmFeatureProvider multipleAlmFeatureProvider; private final WebAnalyticsLoader webAnalyticsLoader; + private final IssueIndexSyncProgressChecker issueIndexSyncChecker; public GlobalAction(PageRepository pageRepository, Configuration config, ResourceTypes resourceTypes, Server server, WebServer webServer, DbClient dbClient, OrganizationFlags organizationFlags, DefaultOrganizationProvider defaultOrganizationProvider, BranchFeatureProxy branchFeature, UserSession userSession, PlatformEditionProvider editionProvider, - MultipleAlmFeatureProvider multipleAlmFeatureProvider, WebAnalyticsLoader webAnalyticsLoader) { + MultipleAlmFeatureProvider multipleAlmFeatureProvider, WebAnalyticsLoader webAnalyticsLoader, IssueIndexSyncProgressChecker issueIndexSyncChecker) { this.pageRepository = pageRepository; this.config = config; this.resourceTypes = resourceTypes; @@ -102,6 +104,7 @@ public class GlobalAction implements NavigationWsAction, Startable { this.multipleAlmFeatureProvider = multipleAlmFeatureProvider; this.webAnalyticsLoader = webAnalyticsLoader; this.systemSettingValuesByKey = new HashMap<>(); + this.issueIndexSyncChecker = issueIndexSyncChecker; } @Override @@ -213,7 +216,7 @@ public class GlobalAction implements NavigationWsAction, Startable { private void writeNeedIssueSync(JsonWriter json) { try (DbSession dbSession = dbClient.openSession(false)) { - json.prop("needIssueSync", dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(dbSession, true)); + json.prop("needIssueSync", issueIndexSyncChecker.isIssueSyncInProgress(dbSession)); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/IndexationStatusActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/IndexationStatusActionTest.java index 13a98e593d6..f5a66a0995a 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/IndexationStatusActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/IndexationStatusActionTest.java @@ -19,22 +19,23 @@ */ package org.sonar.server.ce.ws; -import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.stream.IntStream; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; -import org.sonar.db.project.ProjectDto; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; +import org.sonar.server.issue.index.IssueSyncProgress; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Ce.IndexationStatusWsResponse; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @RunWith(DataProviderRunner.class) public class IndexationStatusActionTest { @@ -42,10 +43,12 @@ public class IndexationStatusActionTest { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); + public IssueIndexSyncProgressChecker issueIndexSyncProgressCheckerMock = mock(IssueIndexSyncProgressChecker.class); + @Rule public DbTester db = DbTester.create(System2.INSTANCE); - private WsActionTester ws = new WsActionTester(new IndexationStatusAction(db.getDbClient())); + private WsActionTester ws = new WsActionTester(new IndexationStatusAction(db.getDbClient(), issueIndexSyncProgressCheckerMock)); @Test public void definition() { @@ -58,73 +61,26 @@ public class IndexationStatusActionTest { @Test public void verify_example_of_response() { - insertProjectWithBranches(false, 0); + when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(0, 0)); ws.newRequest().execute().assertJson(ws.getDef().responseExampleAsString()); } @Test public void return_100_if_there_is_no_tasks_left() { + when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(10, 10)); IndexationStatusWsResponse response = ws.newRequest() .executeProtobuf(IndexationStatusWsResponse.class); assertThat(response.getPercentCompleted()).isEqualTo(100); assertThat(response.getIsCompleted()).isTrue(); } - @Test - public void return_100_if_all_branches_have_need_issue_sync_set_FALSE() { - IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(false, 2)); - IntStream.range(0, 14).forEach(value -> insertProjectWithBranches(false, 4)); - IntStream.range(0, 4).forEach(value -> insertProjectWithBranches(false, 10)); - - IndexationStatusWsResponse response = ws.newRequest() - .executeProtobuf(IndexationStatusWsResponse.class); - assertThat(response.getPercentCompleted()).isEqualTo(100); - assertThat(response.getIsCompleted()).isTrue(); - } - - @Test - @UseDataProvider("various_task_numbers") - public void return_correct_percent_value_for_branches_to_sync(int toSync, int synced, int expectedPercent, boolean isCompleted) { - IntStream.range(0, toSync).forEach(value -> insertProjectWithBranches(true, 0)); - IntStream.range(0, synced).forEach(value -> insertProjectWithBranches(false, 0)); - - IndexationStatusWsResponse response = ws.newRequest() - .executeProtobuf(IndexationStatusWsResponse.class); - assertThat(response.getPercentCompleted()).isEqualTo(expectedPercent); - assertThat(response.getIsCompleted()).isEqualTo(isCompleted); - } - - @DataProvider - public static Object[][] various_task_numbers() { - return new Object[][] { - // toSync, synced, expected result, expectedCompleted - {0, 0, 100, true}, - {0, 9, 100, true}, - {10, 0, 0, false}, - {99, 1, 1, false}, - {2, 1, 33, false}, - {6, 4, 40, false}, - {7, 7, 50, false}, - {1, 2, 66, false}, - {4, 10, 71, false}, - {1, 99, 99, false}, - }; - } - @Test public void return_0_if_all_branches_have_need_issue_sync_set_TRUE() { - IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(true, value)); + when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(0, 10)); IndexationStatusWsResponse response = ws.newRequest() .executeProtobuf(IndexationStatusWsResponse.class); assertThat(response.getPercentCompleted()).isZero(); assertThat(response.getIsCompleted()).isFalse(); } - - private void insertProjectWithBranches(boolean needIssueSync, int numberOfBranches) { - ProjectDto projectDto = db.components() - .insertPrivateProjectDto(db.getDefaultOrganization(), branchDto -> branchDto.setNeedIssueSync(needIssueSync)); - IntStream.range(0, numberOfBranches).forEach( - i -> db.components().insertProjectBranch(projectDto, branchDto -> branchDto.setNeedIssueSync(needIssueSync))); - } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java index 68cf90221ba..97d53d1e022 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java @@ -54,6 +54,7 @@ import org.sonar.db.property.PropertyDto; import org.sonar.server.component.ws.SearchProjectsAction.RequestBuilder; import org.sonar.server.component.ws.SearchProjectsAction.SearchProjectsRequest; import org.sonar.server.es.EsTester; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.measure.index.ProjectMeasuresIndex; import org.sonar.server.measure.index.ProjectMeasuresIndexer; import org.sonar.server.permission.index.PermissionIndexerTester; @@ -171,7 +172,8 @@ public class SearchProjectsActionTest { private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client()); private ProjectsInWarning projectsInWarning = new ProjectsInWarning(); - private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, index, userSession, projectsInWarning, editionProviderMock)); + private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, index, userSession, projectsInWarning, editionProviderMock, + new IssueIndexSyncProgressChecker(db.getDbClient()))); private RequestBuilder request = SearchProjectsRequest.builder(); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/ShowActionTest.java index 6d0252f1a5f..354b4f0ed04 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/ShowActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/ShowActionTest.java @@ -31,12 +31,12 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.db.DbTester; -import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; @@ -68,7 +68,8 @@ public class ShowActionTest { @Rule public DbTester db = DbTester.create(System2.INSTANCE); - private WsActionTester ws = new WsActionTester(new ShowAction(userSession, db.getDbClient(), TestComponentFinder.from(db))); + private WsActionTester ws = new WsActionTester(new ShowAction(userSession, db.getDbClient(), TestComponentFinder.from(db), + new IssueIndexSyncProgressChecker(db.getDbClient()))); @Test public void verify_definition() { @@ -340,12 +341,12 @@ public class ShowActionTest { userSession.addProjectPermission(UserRole.USER, project1, project2, project3); userSession.registerComponents(portfolio1, portfolio2, subview, project1, project2, project3); - //for portfolios, sub-views need issue sync flag is set to true if any project need sync + // for portfolios, sub-views need issue sync flag is set to true if any project need sync assertNeedIssueSyncEqual(null, null, portfolio1, true); assertNeedIssueSyncEqual(null, null, subview, true); assertNeedIssueSyncEqual(null, null, portfolio2, true); - //if branch need sync it is propagated to other components + // if branch need sync it is propagated to other components assertNeedIssueSyncEqual(null, null, project1, true); assertNeedIssueSyncEqual(branch1.getPullRequest(), null, branch1, true); assertNeedIssueSyncEqual(branch1.getPullRequest(), null, module, true); @@ -356,7 +357,7 @@ public class ShowActionTest { assertNeedIssueSyncEqual(null, branch2.getBranch(), branch2, true); assertNeedIssueSyncEqual(null, branch3.getBranch(), branch3, true); - //if all branches are synced, need issue sync on project is is set to false + // if all branches are synced, need issue sync on project is is set to false assertNeedIssueSyncEqual(null, null, project3, false); assertNeedIssueSyncEqual(branch4.getPullRequest(), null, branch4, false); assertNeedIssueSyncEqual(branch4.getPullRequest(), null, moduleOfBranch4, false); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java index 3bb39526c30..56cf8231513 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java @@ -38,6 +38,7 @@ import org.sonar.db.DbClient; import org.sonar.db.dialect.H2; import org.sonar.db.dialect.PostgreSql; import org.sonar.server.almsettings.MultipleAlmFeatureProvider; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.organization.TestOrganizationFlags; @@ -66,6 +67,7 @@ public class GlobalActionTest { private Server server = mock(Server.class); private WebServer webServer = mock(WebServer.class); private DbClient dbClient = mock(DbClient.class, RETURNS_DEEP_STUBS); + private IssueIndexSyncProgressChecker indexSyncProgressChecker = mock(IssueIndexSyncProgressChecker.class); private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone(); private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.fromUuid("foo"); private BranchFeatureRule branchFeature = new BranchFeatureRule(); @@ -221,7 +223,6 @@ public class GlobalActionTest { "}"); } - @Test public void organization_support() { init(); @@ -257,10 +258,10 @@ public class GlobalActionTest { @Test public void return_need_issue_sync() { init(); - when(dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(any(), eq(true))).thenReturn(true); + when(indexSyncProgressChecker.isIssueSyncInProgress(any())).thenReturn(true); assertJson(call()).isSimilarTo("{\"needIssueSync\": true}"); - when(dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(any(), eq(true))).thenReturn(false); + when(indexSyncProgressChecker.isIssueSyncInProgress(any())).thenReturn(false); assertJson(call()).isSimilarTo("{\"needIssueSync\": false}"); } @@ -375,7 +376,8 @@ public class GlobalActionTest { }}); pageRepository.start(); GlobalAction wsAction = new GlobalAction(pageRepository, settings.asConfig(), new ResourceTypes(resourceTypeTrees), server, - webServer, dbClient, organizationFlags, defaultOrganizationProvider, branchFeature, userSession, editionProvider, multipleAlmFeatureProvider, webAnalyticsLoader); + webServer, dbClient, organizationFlags, defaultOrganizationProvider, branchFeature, userSession, editionProvider, multipleAlmFeatureProvider, webAnalyticsLoader, + indexSyncProgressChecker); ws = new WsActionTester(wsAction); wsAction.start(); } diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java index 4c35aea40ae..31373524b96 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java @@ -29,6 +29,7 @@ import org.sonar.api.internal.MetadataLoader; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; +import org.sonar.server.issue.index.IssueIndexSyncProgressChecker; import org.sonar.server.platform.DockerSupportImpl; import org.sonar.server.util.GlobalLockManagerImpl; import org.sonar.server.util.Paths2Impl; @@ -132,6 +133,7 @@ public class PlatformLevel1 extends PlatformLevel { // issues IssueIndex.class, + IssueIndexSyncProgressChecker.class, GlobalLockManagerImpl.class,