diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-10-18 17:44:48 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-10-20 13:12:07 +0200 |
commit | ac8031ea04ac687ebde118919d7a079ed9ebc609 (patch) | |
tree | b7ae9b983bc05994d326ceb61b3d19f877421a70 /server/sonar-server | |
parent | 980460baadab04da9a1092fe15c22a716af3d1bc (diff) | |
download | sonarqube-ac8031ea04ac687ebde118919d7a079ed9ebc609.tar.gz sonarqube-ac8031ea04ac687ebde118919d7a079ed9ebc609.zip |
SONAR-8227 Index project measures authorization
Diffstat (limited to 'server/sonar-server')
11 files changed, 233 insertions, 104 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java b/server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java index aba3ca3c003..f73bfeaac9d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java +++ b/server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java @@ -22,9 +22,9 @@ package org.sonar.server.es; import org.sonar.api.config.Settings; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.server.component.es.ProjectMeasuresIndexer; import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.permission.index.AuthorizationIndexer; -import org.sonar.server.component.es.ProjectMeasuresIndexer; import org.sonar.server.test.index.TestIndexer; import org.sonar.server.user.index.UserIndexer; import org.sonar.server.view.index.ViewIndexer; @@ -47,8 +47,8 @@ public class IndexerStartupTask { * {@link org.sonar.server.issue.index.IssueIndexer} */ public IndexerStartupTask(TestIndexer testIndexer, AuthorizationIndexer authorizationIndexer, IssueIndexer issueIndexer, - UserIndexer userIndexer, ViewIndexer viewIndexer, ProjectMeasuresIndexer projectMeasuresIndexer, - Settings settings) { + UserIndexer userIndexer, ViewIndexer viewIndexer, ProjectMeasuresIndexer projectMeasuresIndexer, + Settings settings) { this.testIndexer = testIndexer; this.authorizationIndexer = authorizationIndexer; this.issueIndexer = issueIndexer; @@ -62,7 +62,7 @@ public class IndexerStartupTask { if (!settings.getBoolean("sonar.internal.es.disableIndexes")) { LOG.info("Index authorization"); - authorizationIndexer.index(); + authorizationIndexer.indexAllIfEmpty(); LOG.info("Index issues"); issueIndexer.index(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationDao.java b/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationDao.java index b585a05e35f..a3b848471db 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationDao.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationDao.java @@ -148,14 +148,15 @@ public class AuthorizationDao { " AND group_roles.group_id IS NULL " + " ) project_authorization"; - List<Dto> selectAfterDate(DbClient dbClient, DbSession session, List<String> projectUuids) { - if (projectUuids.isEmpty()) { - return doSelectAfterDate(dbClient, session, Collections.emptyList()); - } - return executeLargeInputs(projectUuids, subProjectUuids -> doSelectAfterDate(dbClient, session, subProjectUuids)); + List<Dto> selectAll(DbClient dbClient, DbSession session) { + return doSelectByProjects(dbClient, session, Collections.emptyList()); + } + + List<Dto> selectByProjects(DbClient dbClient, DbSession session, List<String> projectUuids) { + return executeLargeInputs(projectUuids, subProjectUuids -> doSelectByProjects(dbClient, session, subProjectUuids)); } - private List<Dto> doSelectAfterDate(DbClient dbClient, DbSession session, List<String> projectUuids) { + private static List<Dto> doSelectByProjects(DbClient dbClient, DbSession session, List<String> projectUuids) { try { Map<String, Dto> dtosByProjectUuid = new HashMap<>(); PreparedStatement stmt = null; diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationIndexer.java index 614a689bbf5..7ed91cbc758 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationIndexer.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationIndexer.java @@ -20,28 +20,33 @@ package org.sonar.server.permission.index; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.Uninterruptibles; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.picocontainer.Startable; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.server.es.BaseIndexer; +import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.EsClient; +import org.sonar.server.es.EsUtils; +import org.sonar.server.issue.index.IssueIndexDefinition; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Arrays.asList; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_UPDATED_AT; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_USERS; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_TECHNICAL_UPDATED_AT; -import static org.sonar.server.issue.index.IssueIndexDefinition.INDEX; -import static org.sonar.server.issue.index.IssueIndexDefinition.TYPE_AUTHORIZATION; +import static java.util.Collections.singletonList; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; /** * Manages the synchronization of index issues/authorization with authorization settings defined in database : @@ -50,76 +55,148 @@ import static org.sonar.server.issue.index.IssueIndexDefinition.TYPE_AUTHORIZATI * <li>delete project orphans from index</li> * </ul> */ -public class AuthorizationIndexer extends BaseIndexer { +public class AuthorizationIndexer implements Startable { + private static final int MAX_BATCH_SIZE = 1000; + + private static final String BULK_ERROR_MESSAGE = "Fail to index authorization"; + + private final ThreadPoolExecutor executor; private final DbClient dbClient; + private final EsClient esClient; public AuthorizationIndexer(DbClient dbClient, EsClient esClient) { - super(esClient, 0L, INDEX, TYPE_AUTHORIZATION, FIELD_ISSUE_TECHNICAL_UPDATED_AT); + this.executor = new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); this.dbClient = dbClient; + this.esClient = esClient; } - @Override - protected long doIndex(long lastUpdatedAt) { - return doIndex(createBulkIndexer(), Collections.<String>emptyList()); + /** + * Index issues authorization and project measures authorization indexes only when they are empty + */ + public void indexAllIfEmpty() { + Future submit = executor.submit(() -> { + if (isIndexEmpty(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION) || + isIndexEmpty(ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)) { + truncate(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION); + truncate(ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION); + try (DbSession dbSession = dbClient.openSession(false)) { + index(new AuthorizationDao().selectAll(dbClient, dbSession)); + } + } + }); + try { + Uninterruptibles.getUninterruptibly(submit); + } catch (ExecutionException e) { + Throwables.propagate(e); + } } - public void index(String projectUuid) { - index(asList(projectUuid)); + private boolean isIndexEmpty(String index, String type) { + SearchResponse issuesAuthorizationResponse = esClient.prepareSearch(index).setTypes(type).setSize(0).get(); + return issuesAuthorizationResponse.getHits().getTotalHits() == 0; + } + + private void truncate(String index, String type) { + BulkIndexer.delete(esClient, index, esClient.prepareSearch(index).setTypes(type).setQuery(matchAllQuery())); } public void index(List<String> projectUuids) { checkArgument(!projectUuids.isEmpty(), "ProjectUuids cannot be empty"); - super.index(lastUpdatedAt -> doIndex(createBulkIndexer(), projectUuids)); + try (DbSession dbSession = dbClient.openSession(false)) { + AuthorizationDao dao = new AuthorizationDao(); + index(dao.selectByProjects(dbClient, dbSession, projectUuids)); + } } - private long doIndex(BulkIndexer bulk, List<String> projectUuids) { + private void index(Collection<AuthorizationDao.Dto> authorizations) { + if (authorizations.isEmpty()) { + return; + } + int count = 0; + BulkRequestBuilder bulkRequest = esClient.prepareBulk().setRefresh(false); + for (AuthorizationDao.Dto dto : authorizations) { + bulkRequest.add(newIssuesAuthorizationIndexRequest(dto)); + bulkRequest.add(newProjectMeasuresAuthorizationIndexRequest(dto)); + count++; + if (count >= MAX_BATCH_SIZE) { + EsUtils.executeBulkRequest(bulkRequest, BULK_ERROR_MESSAGE); + bulkRequest = esClient.prepareBulk().setRefresh(false); + count = 0; + } + } + EsUtils.executeBulkRequest(bulkRequest, BULK_ERROR_MESSAGE); + esClient.prepareRefresh(IssueIndexDefinition.INDEX).get(); + esClient.prepareRefresh(ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES).get(); + } + + public void index(String projectUuid) { try (DbSession dbSession = dbClient.openSession(false)) { AuthorizationDao dao = new AuthorizationDao(); - Collection<AuthorizationDao.Dto> authorizations = dao.selectAfterDate(dbClient, dbSession, projectUuids); - return doIndex(bulk, authorizations); + List<AuthorizationDao.Dto> dtos = dao.selectByProjects(dbClient, dbSession, singletonList(projectUuid)); + if (dtos.size() == 1) { + index(dtos.get(0)); + } } } @VisibleForTesting - public void index(Collection<AuthorizationDao.Dto> authorizations) { - final BulkIndexer bulk = new BulkIndexer(esClient, INDEX); - doIndex(bulk, authorizations); + void index(AuthorizationDao.Dto dto) { + index(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, newIssuesAuthorizationIndexRequest(dto)); + index(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, newProjectMeasuresAuthorizationIndexRequest(dto)); } - private static long doIndex(BulkIndexer bulk, Collection<AuthorizationDao.Dto> authorizations) { - long maxDate = 0L; - bulk.start(); - for (AuthorizationDao.Dto authorization : authorizations) { - bulk.add(newIndexRequest(authorization)); - maxDate = Math.max(maxDate, authorization.getUpdatedAt()); - } - bulk.stop(); - return maxDate; + private void index(String index, String type, IndexRequest indexRequest) { + esClient.prepareIndex(index, type) + .setId(indexRequest.id()) + .setRouting(indexRequest.routing()) + .setSource(indexRequest.source()) + .setRefresh(true) + .get(); } public void deleteProject(String uuid, boolean refresh) { esClient - .prepareDelete(INDEX, TYPE_AUTHORIZATION, uuid) + .prepareDelete(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, uuid) + .setRefresh(refresh) + .setRouting(uuid) + .get(); + esClient + .prepareDelete(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, uuid) .setRefresh(refresh) .setRouting(uuid) .get(); } - private BulkIndexer createBulkIndexer() { - // warning - do not enable large mode, else disabling of replicas - // will impact the type "issue" which is much bigger than issueAuthorization - return new BulkIndexer(esClient, INDEX); + private static IndexRequest newIssuesAuthorizationIndexRequest(AuthorizationDao.Dto dto) { + Map<String, Object> doc = ImmutableMap.of( + IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, dto.getProjectUuid(), + IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS, dto.getGroups(), + IssueIndexDefinition.FIELD_AUTHORIZATION_USERS, dto.getUsers(), + IssueIndexDefinition.FIELD_AUTHORIZATION_UPDATED_AT, new Date(dto.getUpdatedAt())); + return new IndexRequest(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, dto.getProjectUuid()) + .routing(dto.getProjectUuid()) + .source(doc); } - private static IndexRequest newIndexRequest(AuthorizationDao.Dto dto) { + private static IndexRequest newProjectMeasuresAuthorizationIndexRequest(AuthorizationDao.Dto dto) { Map<String, Object> doc = ImmutableMap.of( - FIELD_AUTHORIZATION_PROJECT_UUID, dto.getProjectUuid(), - FIELD_AUTHORIZATION_GROUPS, dto.getGroups(), - FIELD_AUTHORIZATION_USERS, dto.getUsers(), - FIELD_AUTHORIZATION_UPDATED_AT, new Date(dto.getUpdatedAt())); - return new IndexRequest(INDEX, TYPE_AUTHORIZATION, dto.getProjectUuid()) + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, dto.getProjectUuid(), + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_GROUPS, dto.getGroups(), + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_USERS, dto.getUsers(), + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_UPDATED_AT, new Date(dto.getUpdatedAt())); + return new IndexRequest(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, dto.getProjectUuid()) .routing(dto.getProjectUuid()) .source(doc); } + + @Override + public void start() { + // nothing to do at startup + } + + @Override + public void stop() { + executor.shutdown(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java index 62190745f3a..3260a53eee9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java @@ -43,13 +43,12 @@ import org.sonar.server.issue.index.IssueDoc; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.permission.index.AuthorizationDao; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.AuthorizationIndexerTester; import org.sonar.server.platform.ServerFileSystem; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; -import static com.google.common.collect.Lists.newArrayList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -78,7 +77,7 @@ public class IssuesActionTest { private IssueIndex issueIndex; private IssueIndexer issueIndexer; - private AuthorizationIndexer issueAuthorizationIndexer; + private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); private ServerFileSystem fs = mock(ServerFileSystem.class); WsTester tester; @@ -89,7 +88,6 @@ public class IssuesActionTest { public void before() { issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSessionRule); issueIndexer = new IssueIndexer(null, es.client()); - issueAuthorizationIndexer = new AuthorizationIndexer(null, es.client()); issuesAction = new IssuesAction(db.getDbClient(), issueIndex, userSessionRule, new ComponentFinder(db.getDbClient())); tester = new WsTester(new BatchWs(new BatchIndex(fs), issuesAction)); @@ -329,7 +327,7 @@ public class IssuesActionTest { } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable String user) { - issueAuthorizationIndexer.index(newArrayList(new AuthorizationDao.Dto(projectUuid, 1).addGroup(group).addUser(user))); + authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); } private void addBrowsePermissionOnComponent(String componentKey) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStepTest.java index d04968bacc1..e78f57338dd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStepTest.java @@ -35,6 +35,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.permission.PermissionRepository; import org.sonar.db.permission.template.PermissionTemplateDto; +import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; @@ -61,7 +62,7 @@ public class ApplyPermissionsStepTest extends BaseStepTest { private static final long SOME_DATE = 1000L; @Rule - public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings())); + public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java index 65117b830de..023db7a3177 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java @@ -19,7 +19,6 @@ */ package org.sonar.server.issue.index; -import java.util.Arrays; import java.util.Map; import java.util.TimeZone; import javax.annotation.Nullable; @@ -41,13 +40,14 @@ import org.sonar.server.es.SearchResult; import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueQuery.Builder; import org.sonar.server.issue.IssueTesting; -import org.sonar.server.permission.index.AuthorizationDao; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.AuthorizationIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.server.view.index.ViewIndexer; import static com.google.common.collect.Lists.newArrayList; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static org.mockito.Mockito.mock; @@ -66,13 +66,12 @@ public class IssueIndexDebtTest { IssueIndex index; IssueIndexer issueIndexer; - AuthorizationIndexer issueAuthorizationIndexer; + AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(tester); ViewIndexer viewIndexer; @Before public void setUp() { issueIndexer = new IssueIndexer(null, tester.client()); - issueAuthorizationIndexer = new AuthorizationIndexer(null, tester.client()); viewIndexer = new ViewIndexer(null, tester.client()); System2 system = mock(System2.class); when(system.getDefaultTimeZone()).thenReturn(TimeZone.getTimeZone("+01:00")); @@ -280,14 +279,14 @@ public class IssueIndexDebtTest { } private void indexIssues(IssueDoc... issues) { - issueIndexer.index(Arrays.asList(issues).iterator()); + issueIndexer.index(asList(issues).iterator()); for (IssueDoc issue : issues) { addIssueAuthorization(issue.projectUuid(), DefaultGroups.ANYONE, null); } } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable String user) { - issueAuthorizationIndexer.index(newArrayList(new AuthorizationDao.Dto(projectUuid, 1).addGroup(group).addUser(user))); + authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); } private Builder newQueryBuilder() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java index e60c23c85d8..34aa4a444db 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java @@ -50,14 +50,14 @@ import org.sonar.server.es.SearchResult; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueTesting; -import org.sonar.server.permission.index.AuthorizationDao; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.AuthorizationIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.view.index.ViewDoc; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.server.view.index.ViewIndexer; import static com.google.common.collect.Lists.newArrayList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; @@ -79,13 +79,12 @@ public class IssueIndexTest { IssueIndex underTest; IssueIndexer issueIndexer; - AuthorizationIndexer issueAuthorizationIndexer; + AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(tester); ViewIndexer viewIndexer; @Before public void setUp() { issueIndexer = new IssueIndexer(null, tester.client()); - issueAuthorizationIndexer = new AuthorizationIndexer(null, tester.client()); viewIndexer = new ViewIndexer(null, tester.client()); System2 system = mock(System2.class); when(system.getDefaultTimeZone()).thenReturn(TimeZone.getTimeZone("GMT-1:00")); @@ -1290,7 +1289,7 @@ public class IssueIndexTest { } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable String user) { - issueAuthorizationIndexer.index(newArrayList(new AuthorizationDao.Dto(projectUuid, 1).addGroup(group).addUser(user))); + authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); } private void indexView(String viewUuid, List<String> projects) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationDaoTest.java index 9428f6070ed..942dd696dcf 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationDaoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationDaoTest.java @@ -21,7 +21,6 @@ package org.sonar.server.permission.index; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -80,7 +79,7 @@ public class AuthorizationDaoTest { public void select_all() { insertTestDataForProject1And2(); - Collection<AuthorizationDao.Dto> dtos = underTest.selectAfterDate(dbClient, dbSession, Collections.emptyList()); + Collection<AuthorizationDao.Dto> dtos = underTest.selectAll(dbClient, dbSession); assertThat(dtos).hasSize(2); AuthorizationDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); @@ -98,7 +97,7 @@ public class AuthorizationDaoTest { public void select_by_project() throws Exception { insertTestDataForProject1And2(); - Collection<AuthorizationDao.Dto> dtos = underTest.selectAfterDate(dbClient, dbSession, singletonList(project1.uuid())); + Collection<AuthorizationDao.Dto> dtos = underTest.selectByProjects(dbClient, dbSession, singletonList(project1.uuid())); assertThat(dtos).hasSize(1); AuthorizationDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); @@ -110,7 +109,7 @@ public class AuthorizationDaoTest { public void select_by_projects() throws Exception { insertTestDataForProject1And2(); - Map<String, AuthorizationDao.Dto> dtos = underTest.selectAfterDate(dbClient, dbSession, asList(project1.uuid(), project2.uuid())) + Map<String, AuthorizationDao.Dto> dtos = underTest.selectByProjects(dbClient, dbSession, asList(project1.uuid(), project2.uuid())) .stream() .collect(Collectors.uniqueIndex(AuthorizationDao.Dto::getProjectUuid, Function.identity())); assertThat(dtos).hasSize(2); @@ -142,7 +141,7 @@ public class AuthorizationDaoTest { } dbSession.commit(); - Map<String, AuthorizationDao.Dto> dtos = underTest.selectAfterDate(dbClient, dbSession, projects) + Map<String, AuthorizationDao.Dto> dtos = underTest.selectByProjects(dbClient, dbSession, projects) .stream() .collect(Collectors.uniqueIndex(AuthorizationDao.Dto::getProjectUuid, Function.identity())); assertThat(dtos).hasSize(350); @@ -153,7 +152,7 @@ public class AuthorizationDaoTest { userDbTester.insertProjectPermissionOnUser(user1, USER, project2); userDbTester.insertProjectPermissionOnGroup(group, USER, project2); - Collection<AuthorizationDao.Dto> dtos = underTest.selectAfterDate(dbClient, dbSession, Collections.emptyList()); + Collection<AuthorizationDao.Dto> dtos = underTest.selectAll(dbClient, dbSession); assertThat(dtos).hasSize(2); AuthorizationDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTest.java index dc67e68442f..8fa2c0400d1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.permission.index; +import com.google.common.collect.ImmutableMap; import java.util.Collections; import org.junit.Rule; import org.junit.Test; @@ -28,9 +29,12 @@ import org.sonar.api.utils.System2; 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.permission.GroupPermissionDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDbTester; import org.sonar.db.user.UserDto; +import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.EsTester; import org.sonar.server.issue.index.IssueIndexDefinition; @@ -51,7 +55,7 @@ public class AuthorizationIndexerTest { public DbTester dbTester = DbTester.create(System2.INSTANCE); @Rule - public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings())); + public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); UserDbTester userDbTester = new UserDbTester(dbTester); @@ -60,14 +64,14 @@ public class AuthorizationIndexerTest { AuthorizationIndexer underTest = new AuthorizationIndexer(dbTester.getDbClient(), esTester.client()); @Test - public void index_nothing() { - underTest.index(); + public void index_all_does_nothing_when_no_data() { + underTest.indexAllIfEmpty(); assertThat(esTester.countDocuments("issues", "authorization")).isZero(); } @Test - public void index() { + public void index_all() { ComponentDto project = componentDbTester.insertProject(); UserDto user = userDbTester.insertUser(); userDbTester.insertProjectPermissionOnUser(user, USER, project); @@ -76,12 +80,52 @@ public class AuthorizationIndexerTest { userDbTester.insertProjectPermissionOnGroup(group, USER, project); userDbTester.insertProjectPermissionOnAnyone(USER, project); - underTest.index(); + underTest.indexAllIfEmpty(); authorizationIndexerTester.verifyProjectExistsWithAuthorization(project.uuid(), asList(group.getName(), ANYONE), singletonList(user.getLogin())); } @Test + public void index_all_with_huge_number_of_projects() throws Exception { + GroupDto group = userDbTester.insertGroup(); + for (int i = 0; i < 1100; i++) { + ComponentDto project = ComponentTesting.newProjectDto(); + dbTester.getDbClient().componentDao().insert(dbTester.getSession(), project); + GroupPermissionDto dto = new GroupPermissionDto() + .setOrganizationUuid(group.getOrganizationUuid()) + .setGroupId(group.getId()) + .setRole(USER) + .setResourceId(project.getId()); + dbTester.getDbClient().groupPermissionDao().insert(dbTester.getSession(), dto); + } + dbTester.getSession().commit(); + + underTest.indexAllIfEmpty(); + + assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION)).isEqualTo(1100); + assertThat(esTester.countDocuments(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)).isEqualTo(1100); + } + + @Test + public void index_all_is_first_truncating_indexes() throws Exception { + // Insert only one document in issues authorization => only one index is empty + esTester.client().prepareIndex(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION) + .setId("ABC") + .setRouting("ABC") + .setSource(ImmutableMap.of(IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, "ABC")) + .setRefresh(true) + .get(); + GroupDto group = userDbTester.insertGroup(); + ComponentDto project = componentDbTester.insertProject(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project); + + underTest.indexAllIfEmpty(); + + authorizationIndexerTester.verifyProjectExistsWithAuthorization(project.uuid(), asList(group.getName(), ANYONE), emptyList()); + authorizationIndexerTester.verifyProjectDoesNotExist("ABC"); + } + + @Test public void index_one_project() throws Exception { GroupDto group = userDbTester.insertGroup(); ComponentDto project1 = componentDbTester.insertProject(); @@ -123,7 +167,7 @@ public class AuthorizationIndexerTest { } @Test - public void do_not_fail_when_deleting_unindexed_project() { + public void do_not_fail_when_deleting_unknown_project() { underTest.deleteProject("UNKNOWN", true); authorizationIndexerTester.verifyEmptyProjectAuthorization(); @@ -134,7 +178,7 @@ public class AuthorizationIndexerTest { authorizationIndexerTester.insertProjectAuthorization("ABC", singletonList("guy"), singletonList("dev")); // remove permissions -> dto has no users nor groups - underTest.index(singletonList(new AuthorizationDao.Dto("ABC", System.currentTimeMillis()))); + underTest.index(new AuthorizationDao.Dto("ABC", System.currentTimeMillis())); authorizationIndexerTester.verifyProjectExistsWithoutAuthorization("ABC"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTester.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTester.java index 9096bd17b4e..90c756a2d70 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTester.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTester.java @@ -23,19 +23,17 @@ package org.sonar.server.permission.index; import java.util.List; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.index.query.BoolQueryBuilder; +import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.EsTester; +import org.sonar.server.issue.index.IssueIndexDefinition; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.existsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.index.query.QueryBuilders.termsQuery; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID; -import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_AUTHORIZATION_USERS; public class AuthorizationIndexerTester { @@ -50,17 +48,19 @@ public class AuthorizationIndexerTester { public void insertProjectAuthorization(String projectUuid, List<String> groupNames, List<String> userLogins) { AuthorizationDao.Dto authorization = new AuthorizationDao.Dto(projectUuid, System.currentTimeMillis()); - groupNames.forEach(authorization::addUser); - userLogins.forEach(authorization::addGroup); - authorizationIndexer.index(singletonList(authorization)); + groupNames.forEach(authorization::addGroup); + userLogins.forEach(authorization::addUser); + authorizationIndexer.index(authorization); } public void verifyEmptyProjectAuthorization() { - assertThat(esTester.countDocuments("issues", "authorization")).isZero(); + assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION)).isZero(); + assertThat(esTester.countDocuments(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)).isZero(); } public void verifyProjectDoesNotExist(String projectUuid) { - assertThat(esTester.getIds("issues", "authorization")).doesNotContain(projectUuid); + assertThat(esTester.getIds(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); + assertThat(esTester.getIds(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); } public void verifyProjectExistsWithoutAuthorization(String projectUuid) { @@ -68,21 +68,31 @@ public class AuthorizationIndexerTester { } public void verifyProjectExistsWithAuthorization(String projectUuid, List<String> groupNames, List<String> userLogins) { - assertThat(esTester.getIds("issues", "authorization")).contains(projectUuid); - BoolQueryBuilder queryBuilder = boolQuery().must(termQuery(FIELD_AUTHORIZATION_PROJECT_UUID, projectUuid)); + verifyProjectExistsWithAuthorizationInIndex(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, + IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS, IssueIndexDefinition.FIELD_AUTHORIZATION_USERS, + projectUuid, groupNames, userLogins); + verifyProjectExistsWithAuthorizationInIndex(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_GROUPS, + ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_USERS, projectUuid, groupNames, userLogins); + } + + private void verifyProjectExistsWithAuthorizationInIndex(String index, String type, String projectField, String groupField, String userField, String projectUuid, + List<String> groupNames, List<String> userLogins) { + assertThat(esTester.getIds(index, type)).contains(projectUuid); + BoolQueryBuilder queryBuilder = boolQuery().must(termQuery(projectField, projectUuid)); if (groupNames.isEmpty()) { - queryBuilder.mustNot(existsQuery(FIELD_AUTHORIZATION_GROUPS)); + queryBuilder.mustNot(existsQuery(groupField)); } else { - queryBuilder.must(termsQuery(FIELD_AUTHORIZATION_GROUPS, groupNames)); + queryBuilder.must(termsQuery(groupField, groupNames)); } if (userLogins.isEmpty()) { - queryBuilder.mustNot(existsQuery(FIELD_AUTHORIZATION_USERS)); + queryBuilder.mustNot(existsQuery(userField)); } else { - queryBuilder.must(termsQuery(FIELD_AUTHORIZATION_USERS, userLogins)); + queryBuilder.must(termsQuery(userField, userLogins)); } SearchRequestBuilder request = esTester.client() - .prepareSearch("issues") - .setTypes("authorization") + .prepareSearch(index) + .setTypes(type) .setQuery(boolQuery().must(matchAllQuery()).filter(queryBuilder)); assertThat(request.get().getHits()).hasSize(1); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/ApplyTemplateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/ApplyTemplateActionTest.java index e90a36aebc5..5c3957ea7de 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/ApplyTemplateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/ApplyTemplateActionTest.java @@ -36,6 +36,7 @@ import org.sonar.db.permission.template.PermissionTemplateDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; @@ -60,7 +61,7 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_T public class ApplyTemplateActionTest extends BasePermissionWsTest<ApplyTemplateAction> { @Rule - public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings())); + public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); private static final String ACTION = "apply_template"; |