From: Julien Lancelot Date: Thu, 20 Oct 2016 10:45:06 +0000 (+0200) Subject: SONAR-8227 Rename AuthorizationIndexer to PermissionIndexer X-Git-Tag: 6.2-RC1~343 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F1311%2Fhead;p=sonarqube.git SONAR-8227 Rename AuthorizationIndexer to PermissionIndexer --- diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 32dc0e95471..547008af676 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -68,6 +68,7 @@ import org.sonar.process.Props; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; +import org.sonar.server.component.es.ProjectMeasuresIndexer; import org.sonar.server.computation.queue.PurgeCeActivities; import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule; import org.sonar.server.computation.taskprocessor.CeTaskProcessorModule; @@ -99,7 +100,7 @@ import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionService; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.permission.UserPermissionChanger; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.platform.DatabaseServerCompatibility; import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.ServerFileSystemImpl; @@ -116,7 +117,6 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper; import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper; -import org.sonar.server.component.es.ProjectMeasuresIndexer; import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.QProfileProjectOperations; @@ -340,7 +340,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { // issues IssueIndexer.class, - AuthorizationIndexer.class, + PermissionIndexer.class, IssueUpdater.class, // used in Web Services and CE's DebtCalculator FunctionExecutor.class, // used by IssueWorkflow IssueWorkflow.class, // used in Web Services and CE's DebtCalculator diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java index 375b6743727..92e3c0a46e8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -31,7 +31,7 @@ import org.sonar.db.MyBatis; import org.sonar.db.component.ComponentDto; 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.permission.index.PermissionIndexer; import org.sonar.server.test.index.TestIndexer; @ServerSide @@ -39,17 +39,17 @@ import org.sonar.server.test.index.TestIndexer; public class ComponentCleanerService { private final DbClient dbClient; - private final AuthorizationIndexer authorizationIndexer; + private final PermissionIndexer permissionIndexer; private final IssueIndexer issueIndexer; private final TestIndexer testIndexer; private final ProjectMeasuresIndexer projectMeasuresIndexer; private final ResourceTypes resourceTypes; private final ComponentFinder componentFinder; - public ComponentCleanerService(DbClient dbClient, AuthorizationIndexer authorizationIndexer, IssueIndexer issueIndexer, + public ComponentCleanerService(DbClient dbClient, PermissionIndexer permissionIndexer, IssueIndexer issueIndexer, TestIndexer testIndexer, ProjectMeasuresIndexer projectMeasuresIndexer, ResourceTypes resourceTypes, ComponentFinder componentFinder) { this.dbClient = dbClient; - this.authorizationIndexer = authorizationIndexer; + this.permissionIndexer = permissionIndexer; this.issueIndexer = issueIndexer; this.testIndexer = testIndexer; this.projectMeasuresIndexer = projectMeasuresIndexer; diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresAuthorizationDoc.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresAuthorizationDoc.java deleted file mode 100644 index 85950f36fa4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresAuthorizationDoc.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.component.es; - -import com.google.common.collect.Maps; -import org.sonar.server.es.BaseDoc; - -import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID; - -public class ProjectMeasuresAuthorizationDoc extends BaseDoc { - - public ProjectMeasuresAuthorizationDoc() { - super(Maps.newHashMap()); - } - - @Override - public String getId() { - return projectUuid(); - } - - @Override - public String getRouting() { - return projectUuid(); - } - - @Override - public String getParent() { - return null; - } - - public String projectUuid() { - return getField(FIELD_AUTHORIZATION_PROJECT_UUID); - } - - public ProjectMeasuresAuthorizationDoc setProjectUuid(String s) { - setField(FIELD_AUTHORIZATION_PROJECT_UUID, s); - return this; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStep.java index b46059d147f..29c79d11686 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ApplyPermissionsStep.java @@ -29,7 +29,7 @@ import org.sonar.server.computation.task.projectanalysis.component.DepthTraversa import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter; import org.sonar.server.computation.task.step.ComputationStep; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.VIEW; @@ -42,12 +42,12 @@ public class ApplyPermissionsStep implements ComputationStep { private final DbClient dbClient; private final DbIdsRepository dbIdsRepository; - private final AuthorizationIndexer indexer; + private final PermissionIndexer indexer; private final PermissionRepository permissionRepository; private final TreeRootHolder treeRootHolder; - public ApplyPermissionsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, AuthorizationIndexer indexer, PermissionRepository permissionRepository, - TreeRootHolder treeRootHolder) { + public ApplyPermissionsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, PermissionIndexer indexer, PermissionRepository permissionRepository, + TreeRootHolder treeRootHolder) { this.dbClient = dbClient; this.dbIdsRepository = dbIdsRepository; this.indexer = indexer; 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 f73bfeaac9d..8887ebe001f 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 @@ -24,7 +24,7 @@ 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.permission.index.PermissionIndexer; import org.sonar.server.test.index.TestIndexer; import org.sonar.server.user.index.UserIndexer; import org.sonar.server.view.index.ViewIndexer; @@ -34,7 +34,7 @@ public class IndexerStartupTask { private static final Logger LOG = Loggers.get(IndexerStartupTask.class); private final TestIndexer testIndexer; - private final AuthorizationIndexer authorizationIndexer; + private final PermissionIndexer permissionIndexer; private final IssueIndexer issueIndexer; private final UserIndexer userIndexer; private final ViewIndexer viewIndexer; @@ -43,14 +43,14 @@ public class IndexerStartupTask { /** * Limitation - {@link org.sonar.server.es.BaseIndexer} are not injected through an array or a collection - * because we need {@link AuthorizationIndexer} to be executed before + * because we need {@link PermissionIndexer} to be executed before * {@link org.sonar.server.issue.index.IssueIndexer} */ - public IndexerStartupTask(TestIndexer testIndexer, AuthorizationIndexer authorizationIndexer, IssueIndexer issueIndexer, - UserIndexer userIndexer, ViewIndexer viewIndexer, ProjectMeasuresIndexer projectMeasuresIndexer, - Settings settings) { + public IndexerStartupTask(TestIndexer testIndexer, PermissionIndexer permissionIndexer, IssueIndexer issueIndexer, + UserIndexer userIndexer, ViewIndexer viewIndexer, ProjectMeasuresIndexer projectMeasuresIndexer, + Settings settings) { this.testIndexer = testIndexer; - this.authorizationIndexer = authorizationIndexer; + this.permissionIndexer = permissionIndexer; this.issueIndexer = issueIndexer; this.userIndexer = userIndexer; this.viewIndexer = viewIndexer; @@ -62,7 +62,7 @@ public class IndexerStartupTask { if (!settings.getBoolean("sonar.internal.es.disableIndexes")) { LOG.info("Index authorization"); - authorizationIndexer.indexAllIfEmpty(); + permissionIndexer.indexAllIfEmpty(); LOG.info("Index issues"); issueIndexer.index(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java index 9f3c15d95ae..4d5705822cd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java @@ -34,7 +34,7 @@ import org.sonar.db.component.ResourceDto; import org.sonar.db.permission.PermissionRepository; import org.sonar.db.permission.template.PermissionTemplateDto; import org.sonar.server.component.ComponentFinder; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.user.UserSession; import static java.util.Arrays.asList; @@ -45,15 +45,15 @@ public class PermissionService { private final DbClient dbClient; private final PermissionRepository permissionRepository; - private final AuthorizationIndexer authorizationIndexer; + private final PermissionIndexer permissionIndexer; private final UserSession userSession; private final ComponentFinder componentFinder; - public PermissionService(DbClient dbClient, PermissionRepository permissionRepository, AuthorizationIndexer authorizationIndexer, UserSession userSession, - ComponentFinder componentFinder) { + public PermissionService(DbClient dbClient, PermissionRepository permissionRepository, PermissionIndexer permissionIndexer, UserSession userSession, + ComponentFinder componentFinder) { this.dbClient = dbClient; this.permissionRepository = permissionRepository; - this.authorizationIndexer = authorizationIndexer; + this.permissionIndexer = permissionIndexer; this.userSession = userSession; this.componentFinder = componentFinder; } @@ -114,6 +114,6 @@ public class PermissionService { } private void indexProjectPermissions(DbSession dbSession, List projectUuids) { - authorizationIndexer.index(dbSession, projectUuids); + permissionIndexer.index(dbSession, projectUuids); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java index 07f5813776b..4d90f6c09db 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java @@ -27,7 +27,7 @@ import java.util.Optional; import java.util.Set; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; /** * Add or remove global/project permissions to a group. This class @@ -37,14 +37,14 @@ import org.sonar.server.permission.index.AuthorizationIndexer; public class PermissionUpdater { private final DbClient dbClient; - private final AuthorizationIndexer authorizationIndexer; + private final PermissionIndexer permissionIndexer; private final UserPermissionChanger userPermissionChanger; private final GroupPermissionChanger groupPermissionChanger; - public PermissionUpdater(DbClient dbClient, AuthorizationIndexer authorizationIndexer, + public PermissionUpdater(DbClient dbClient, PermissionIndexer permissionIndexer, UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger) { this.dbClient = dbClient; - this.authorizationIndexer = authorizationIndexer; + this.permissionIndexer = permissionIndexer; this.userPermissionChanger = userPermissionChanger; this.groupPermissionChanger = groupPermissionChanger; } @@ -66,7 +66,7 @@ public class PermissionUpdater { dbSession.commit(); if (!projectIds.isEmpty()) { - authorizationIndexer.index(dbSession, projectUuids); + permissionIndexer.index(dbSession, projectUuids); } } 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 deleted file mode 100644 index b95f9251b8d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationDao.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.permission.index; - -import com.google.common.collect.Lists; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.apache.commons.dbutils.DbUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; - -import static org.sonar.db.DatabaseUtils.executeLargeInputs; -import static org.sonar.db.DatabaseUtils.repeatCondition; - -/** - * No streaming because of union of joins -> no need to use ResultSetIterator - */ -public class AuthorizationDao { - - public static final class Dto { - private final String projectUuid; - private final long updatedAt; - private final List users = Lists.newArrayList(); - private final List groups = Lists.newArrayList(); - - public Dto(String projectUuid, long updatedAt) { - this.projectUuid = projectUuid; - this.updatedAt = updatedAt; - } - - public String getProjectUuid() { - return projectUuid; - } - - public long getUpdatedAt() { - return updatedAt; - } - - public List getUsers() { - return users; - } - - public Dto addUser(Long s) { - users.add(s); - return this; - } - - public Dto addGroup(String s) { - groups.add(s); - return this; - } - - public List getGroups() { - return groups; - } - } - - private static final String SQL_TEMPLATE = "SELECT " + - " project_authorization.project as project, " + - " project_authorization.user_id as user_id, " + - " project_authorization.permission_group as permission_group, " + - " project_authorization.updated_at as updated_at " + - "FROM ( " + - - // project is returned when no authorization - " SELECT " + - " projects.uuid AS project, " + - " projects.authorization_updated_at AS updated_at, " + - " NULL AS user_id, " + - " NULL AS permission_group " + - " FROM projects " + - " WHERE " + - " projects.qualifier = 'TRK' " + - " AND projects.copy_component_uuid is NULL " + - " {projectsCondition} " + - " UNION " + - - // users - - " SELECT " + - " projects.uuid AS project, " + - " projects.authorization_updated_at AS updated_at, " + - " user_roles.user_id AS user_id, " + - " NULL AS permission_group " + - " FROM projects " + - " INNER JOIN user_roles ON user_roles.resource_id = projects.id AND user_roles.role = 'user' " + - " WHERE " + - " projects.qualifier = 'TRK' " + - " AND projects.copy_component_uuid is NULL " + - " {projectsCondition} " + - " UNION " + - - // groups without Anyone - - " SELECT " + - " projects.uuid AS project, " + - " projects.authorization_updated_at AS updated_at, " + - " NULL AS user_id, " + - " groups.name AS permission_group " + - " FROM projects " + - " INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role = 'user' " + - " INNER JOIN groups ON groups.id = group_roles.group_id " + - " WHERE " + - " projects.qualifier = 'TRK' " + - " AND projects.copy_component_uuid is NULL " + - " {projectsCondition} " + - " AND group_id IS NOT NULL " + - " UNION " + - - // Anyone groups - - " SELECT " + - " projects.uuid AS project, " + - " projects.authorization_updated_at AS updated_at, " + - " NULL AS user_id, " + - " 'Anyone' AS permission_group " + - " FROM projects " + - " INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role='user' " + - " WHERE " + - " projects.qualifier = 'TRK' " + - " AND projects.copy_component_uuid is NULL " + - " {projectsCondition} " + - " AND group_roles.group_id IS NULL " + - " ) project_authorization"; - - List selectAll(DbClient dbClient, DbSession session) { - return doSelectByProjects(dbClient, session, Collections.emptyList()); - } - - List selectByProjects(DbClient dbClient, DbSession session, List projectUuids) { - return executeLargeInputs(projectUuids, subProjectUuids -> doSelectByProjects(dbClient, session, subProjectUuids)); - } - - private static List doSelectByProjects(DbClient dbClient, DbSession session, List projectUuids) { - try { - Map dtosByProjectUuid = new HashMap<>(); - PreparedStatement stmt = null; - ResultSet rs = null; - try { - stmt = createStatement(dbClient, session, projectUuids); - rs = stmt.executeQuery(); - while (rs.next()) { - processRow(rs, dtosByProjectUuid); - } - return new ArrayList<>(dtosByProjectUuid.values()); - } finally { - DbUtils.closeQuietly(rs); - DbUtils.closeQuietly(stmt); - } - } catch (SQLException e) { - throw new IllegalStateException("Fail to select authorizations", e); - } - } - - private static PreparedStatement createStatement(DbClient dbClient, DbSession session, List projectUuids) throws SQLException { - String sql; - if (!projectUuids.isEmpty()) { - sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", " AND (" + repeatCondition("projects.uuid = ?", projectUuids.size(), "OR") + ")"); - } else { - sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", ""); - } - PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql); - if (!projectUuids.isEmpty()) { - int index = 1; - for (int i = 1; i <= 4; i++) { - for (int uuidIndex = 0; uuidIndex < projectUuids.size(); uuidIndex++) { - stmt.setString(index, projectUuids.get(uuidIndex)); - index++; - } - } - } - return stmt; - } - - private static void processRow(ResultSet rs, Map dtosByProjectUuid) throws SQLException { - String projectUuid = rs.getString(1); - String group = rs.getString(3); - - Dto dto = dtosByProjectUuid.get(projectUuid); - if (dto == null) { - long updatedAt = rs.getLong(4); - dto = new Dto(projectUuid, updatedAt); - dtosByProjectUuid.put(projectUuid, dto); - } - Long userId = rs.getLong(2); - if (!rs.wasNull()) { - dto.addUser(userId); - } - if (StringUtils.isNotBlank(group)) { - dto.addGroup(group); - } - } -} 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 deleted file mode 100644 index 502b254acd4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/index/AuthorizationIndexer.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.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.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.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.Collections.singletonList; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; - -/** - * Manages the synchronization of index issues/authorization with authorization settings defined in database : - *
    - *
  • index the projects with recent permission changes
  • - *
  • delete project orphans from index
  • - *
- */ -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) { - this.executor = new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); - this.dbClient = dbClient; - this.esClient = esClient; - } - - /** - * 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); - } - } - - 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(DbSession dbSession, List projectUuids) { - checkArgument(!projectUuids.isEmpty(), "ProjectUuids cannot be empty"); - AuthorizationDao dao = new AuthorizationDao(); - index(dao.selectByProjects(dbClient, dbSession, projectUuids)); - } - - private void index(Collection 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(DbSession dbSession, String projectUuid) { - AuthorizationDao dao = new AuthorizationDao(); - List dtos = dao.selectByProjects(dbClient, dbSession, singletonList(projectUuid)); - if (dtos.size() == 1) { - index(dtos.get(0)); - } - } - - @VisibleForTesting - void index(AuthorizationDao.Dto dto) { - index(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, newIssuesAuthorizationIndexRequest(dto)); - index(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, newProjectMeasuresAuthorizationIndexRequest(dto)); - } - - 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(); - } - - private static IndexRequest newIssuesAuthorizationIndexRequest(AuthorizationDao.Dto dto) { - Map 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 newProjectMeasuresAuthorizationIndexRequest(AuthorizationDao.Dto dto) { - Map doc = ImmutableMap.of( - 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/main/java/org/sonar/server/permission/index/PermissionIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java new file mode 100644 index 00000000000..b42a43f8010 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java @@ -0,0 +1,185 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.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.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.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.Collections.singletonList; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; + +/** + * Manages the synchronization of index issues/authorization with authorization settings defined in database : + *
    + *
  • index the projects with recent permission changes
  • + *
  • delete project orphans from index
  • + *
+ */ +public class PermissionIndexer 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 PermissionIndexer(DbClient dbClient, EsClient esClient) { + this.executor = new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + this.dbClient = dbClient; + this.esClient = esClient; + } + + /** + * 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 PermissionIndexerDao().selectAll(dbClient, dbSession)); + } + } + }); + try { + Uninterruptibles.getUninterruptibly(submit); + } catch (ExecutionException e) { + Throwables.propagate(e); + } + } + + 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(DbSession dbSession, List projectUuids) { + checkArgument(!projectUuids.isEmpty(), "ProjectUuids cannot be empty"); + PermissionIndexerDao dao = new PermissionIndexerDao(); + index(dao.selectByProjects(dbClient, dbSession, projectUuids)); + } + + private void index(Collection authorizations) { + if (authorizations.isEmpty()) { + return; + } + int count = 0; + BulkRequestBuilder bulkRequest = esClient.prepareBulk().setRefresh(false); + for (PermissionIndexerDao.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(DbSession dbSession, String projectUuid) { + PermissionIndexerDao dao = new PermissionIndexerDao(); + List dtos = dao.selectByProjects(dbClient, dbSession, singletonList(projectUuid)); + if (dtos.size() == 1) { + index(dtos.get(0)); + } + } + + @VisibleForTesting + void index(PermissionIndexerDao.Dto dto) { + index(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, newIssuesAuthorizationIndexRequest(dto)); + index(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION, newProjectMeasuresAuthorizationIndexRequest(dto)); + } + + 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(); + } + + private static IndexRequest newIssuesAuthorizationIndexRequest(PermissionIndexerDao.Dto dto) { + Map 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 newProjectMeasuresAuthorizationIndexRequest(PermissionIndexerDao.Dto dto) { + Map doc = ImmutableMap.of( + 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/main/java/org/sonar/server/permission/index/PermissionIndexerDao.java b/server/sonar-server/src/main/java/org/sonar/server/permission/index/PermissionIndexerDao.java new file mode 100644 index 00000000000..292acfd1897 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/index/PermissionIndexerDao.java @@ -0,0 +1,217 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.permission.index; + +import com.google.common.collect.Lists; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.dbutils.DbUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; + +import static org.sonar.db.DatabaseUtils.executeLargeInputs; +import static org.sonar.db.DatabaseUtils.repeatCondition; + +/** + * No streaming because of union of joins -> no need to use ResultSetIterator + */ +public class PermissionIndexerDao { + + public static final class Dto { + private final String projectUuid; + private final long updatedAt; + private final List users = Lists.newArrayList(); + private final List groups = Lists.newArrayList(); + + public Dto(String projectUuid, long updatedAt) { + this.projectUuid = projectUuid; + this.updatedAt = updatedAt; + } + + public String getProjectUuid() { + return projectUuid; + } + + public long getUpdatedAt() { + return updatedAt; + } + + public List getUsers() { + return users; + } + + public Dto addUser(Long s) { + users.add(s); + return this; + } + + public Dto addGroup(String s) { + groups.add(s); + return this; + } + + public List getGroups() { + return groups; + } + } + + private static final String SQL_TEMPLATE = "SELECT " + + " project_authorization.project as project, " + + " project_authorization.user_id as user_id, " + + " project_authorization.permission_group as permission_group, " + + " project_authorization.updated_at as updated_at " + + "FROM ( " + + + // project is returned when no authorization + " SELECT " + + " projects.uuid AS project, " + + " projects.authorization_updated_at AS updated_at, " + + " NULL AS user_id, " + + " NULL AS permission_group " + + " FROM projects " + + " WHERE " + + " projects.qualifier = 'TRK' " + + " AND projects.copy_component_uuid is NULL " + + " {projectsCondition} " + + " UNION " + + + // users + + " SELECT " + + " projects.uuid AS project, " + + " projects.authorization_updated_at AS updated_at, " + + " user_roles.user_id AS user_id, " + + " NULL AS permission_group " + + " FROM projects " + + " INNER JOIN user_roles ON user_roles.resource_id = projects.id AND user_roles.role = 'user' " + + " WHERE " + + " projects.qualifier = 'TRK' " + + " AND projects.copy_component_uuid is NULL " + + " {projectsCondition} " + + " UNION " + + + // groups without Anyone + + " SELECT " + + " projects.uuid AS project, " + + " projects.authorization_updated_at AS updated_at, " + + " NULL AS user_id, " + + " groups.name AS permission_group " + + " FROM projects " + + " INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role = 'user' " + + " INNER JOIN groups ON groups.id = group_roles.group_id " + + " WHERE " + + " projects.qualifier = 'TRK' " + + " AND projects.copy_component_uuid is NULL " + + " {projectsCondition} " + + " AND group_id IS NOT NULL " + + " UNION " + + + // Anyone groups + + " SELECT " + + " projects.uuid AS project, " + + " projects.authorization_updated_at AS updated_at, " + + " NULL AS user_id, " + + " 'Anyone' AS permission_group " + + " FROM projects " + + " INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role='user' " + + " WHERE " + + " projects.qualifier = 'TRK' " + + " AND projects.copy_component_uuid is NULL " + + " {projectsCondition} " + + " AND group_roles.group_id IS NULL " + + " ) project_authorization"; + + List selectAll(DbClient dbClient, DbSession session) { + return doSelectByProjects(dbClient, session, Collections.emptyList()); + } + + List selectByProjects(DbClient dbClient, DbSession session, List projectUuids) { + return executeLargeInputs(projectUuids, subProjectUuids -> doSelectByProjects(dbClient, session, subProjectUuids)); + } + + private static List doSelectByProjects(DbClient dbClient, DbSession session, List projectUuids) { + try { + Map dtosByProjectUuid = new HashMap<>(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = createStatement(dbClient, session, projectUuids); + rs = stmt.executeQuery(); + while (rs.next()) { + processRow(rs, dtosByProjectUuid); + } + return new ArrayList<>(dtosByProjectUuid.values()); + } finally { + DbUtils.closeQuietly(rs); + DbUtils.closeQuietly(stmt); + } + } catch (SQLException e) { + throw new IllegalStateException("Fail to select authorizations", e); + } + } + + private static PreparedStatement createStatement(DbClient dbClient, DbSession session, List projectUuids) throws SQLException { + String sql; + if (!projectUuids.isEmpty()) { + sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", " AND (" + repeatCondition("projects.uuid = ?", projectUuids.size(), "OR") + ")"); + } else { + sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", ""); + } + PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql); + if (!projectUuids.isEmpty()) { + int index = 1; + for (int i = 1; i <= 4; i++) { + for (int uuidIndex = 0; uuidIndex < projectUuids.size(); uuidIndex++) { + stmt.setString(index, projectUuids.get(uuidIndex)); + index++; + } + } + } + return stmt; + } + + private static void processRow(ResultSet rs, Map dtosByProjectUuid) throws SQLException { + String projectUuid = rs.getString(1); + String group = rs.getString(3); + + Dto dto = dtosByProjectUuid.get(projectUuid); + if (dto == null) { + long updatedAt = rs.getLong(4); + dto = new Dto(projectUuid, updatedAt); + dtosByProjectUuid.put(projectUuid, dto); + } + Long userId = rs.getLong(2); + if (!rs.wasNull()) { + dto.addUser(userId); + } + if (StringUtils.isNotBlank(group)) { + dto.addGroup(group); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 1e25081156a..7ce7034056e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -42,6 +42,7 @@ import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; import org.sonar.server.component.DefaultComponentFinder; import org.sonar.server.component.DefaultRubyComponentService; +import org.sonar.server.component.es.ProjectsEsModule; import org.sonar.server.component.ws.ComponentsWsModule; import org.sonar.server.config.ws.PropertiesWs; import org.sonar.server.dashboard.template.GlobalDefaultDashboard; @@ -139,7 +140,7 @@ import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionService; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.permission.UserPermissionChanger; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.permission.ws.PermissionsWsModule; import org.sonar.server.platform.BackendCleanup; import org.sonar.server.platform.PersistentSettings; @@ -177,7 +178,6 @@ import org.sonar.server.plugins.ws.PluginWSCommons; import org.sonar.server.plugins.ws.PluginsWs; import org.sonar.server.plugins.ws.UninstallAction; import org.sonar.server.plugins.ws.UpdatesAction; -import org.sonar.server.component.es.ProjectsEsModule; import org.sonar.server.project.ws.ProjectsWsModule; import org.sonar.server.projectlink.ws.ProjectLinksModule; import org.sonar.server.property.InternalPropertiesImpl; @@ -457,7 +457,7 @@ public class PlatformLevel4 extends PlatformLevel { // issues IssueIndexDefinition.class, IssueIndexer.class, - AuthorizationIndexer.class, + PermissionIndexer.class, ServerIssueStorage.class, IssueUpdater.class, FunctionExecutor.class, 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 ffacf68f848..9e0ef04b242 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,7 +43,7 @@ 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.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.platform.ServerFileSystem; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; @@ -77,7 +77,7 @@ public class IssuesActionTest { private IssueIndex issueIndex; private IssueIndexer issueIndexer; - private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); + private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es); private ServerFileSystem fs = mock(ServerFileSystem.class); WsTester tester; @@ -327,7 +327,7 @@ public class IssuesActionTest { } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable Long user) { - authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); + authorizationIndexerTester.indexProjectPermission(projectUuid, singletonList(group), singletonList(user)); } private void addBrowsePermissionOnComponent(String componentKey) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java index e2e0b138b51..abdf7a01435 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java @@ -45,7 +45,7 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.IssueTesting; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.test.index.TestDoc; import org.sonar.server.test.index.TestIndexDefinition; import org.sonar.server.test.index.TestIndexer; @@ -76,7 +76,7 @@ public class ComponentCleanerServiceTest { DbClient dbClient = db.getDbClient(); DbSession dbSession = db.getSession(); - AuthorizationIndexer authorizationIndexer = new AuthorizationIndexer(dbClient, es.client()); + PermissionIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client()); IssueIndexer issueIndexer = new IssueIndexer(dbClient, es.client()); TestIndexer testIndexer = new TestIndexer(dbClient, es.client()); ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(dbClient, es.client()); @@ -84,7 +84,7 @@ public class ComponentCleanerServiceTest { ResourceTypes mockResourceTypes = mock(ResourceTypes.class); ComponentCleanerService underTest = new ComponentCleanerService(dbClient, - authorizationIndexer, issueIndexer, testIndexer, projectMeasuresIndexer, + permissionIndexer, issueIndexer, testIndexer, projectMeasuresIndexer, mockResourceTypes, new ComponentFinder(dbClient)); @@ -225,7 +225,7 @@ public class ComponentCleanerServiceTest { dbClient.componentDao().insert(dbSession, project); dbSession.commit(); projectMeasuresIndexer.index(); - authorizationIndexer.index(dbSession, project.uuid()); + permissionIndexer.index(dbSession, project.uuid()); String issueKey = "issue-key-" + suffix; es.putDocuments(IssueIndexDefinition.INDEX, TYPE_ISSUE, IssueTesting.newDoc(issueKey, project)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java index 17fb2860a53..6ee2e8ebed3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java @@ -34,7 +34,7 @@ import org.sonar.server.component.es.ProjectMeasuresQuery.Operator; import org.sonar.server.es.EsTester; import org.sonar.server.es.SearchIdResult; import org.sonar.server.es.SearchOptions; -import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; import static com.google.common.collect.Lists.newArrayList; @@ -56,7 +56,7 @@ public class ProjectMeasuresIndexTest { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); - private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); + private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es); private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client(), userSession); @@ -218,7 +218,7 @@ public class ProjectMeasuresIndexTest { try { es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs); for (ProjectMeasuresDoc doc : docs) { - authorizationIndexerTester.insertProjectAuthorization(doc.getId(), + authorizationIndexerTester.indexProjectPermission(doc.getId(), authorizedGroup != null ? singletonList(authorizedGroup) : Collections.emptyList(), authorizeUser != null ? singletonList(authorizeUser) : Collections.emptyList()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java index aaf66fcc26c..0ee1c4935df 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java @@ -31,7 +31,7 @@ import org.sonar.db.component.ComponentDbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; import org.sonar.server.es.EsTester; -import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; @@ -52,7 +52,7 @@ public class ProjectMeasuresIndexerTest { public DbTester dbTester = DbTester.create(System2.INSTANCE); ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); - AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(esTester); + PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(esTester); ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(dbTester.getDbClient(), esTester.client()); @@ -129,9 +129,9 @@ public class ProjectMeasuresIndexerTest { ComponentDto project3 = newProjectDto(); componentDbTester.insertProjectAndSnapshot(project3); underTest.index(); - authorizationIndexerTester.insertProjectAuthorization(project1.uuid(), emptyList(), emptyList()); - authorizationIndexerTester.insertProjectAuthorization(project2.uuid(), emptyList(), emptyList()); - authorizationIndexerTester.insertProjectAuthorization(project3.uuid(), emptyList(), emptyList()); + authorizationIndexerTester.indexProjectPermission(project1.uuid(), emptyList(), emptyList()); + authorizationIndexerTester.indexProjectPermission(project2.uuid(), emptyList(), emptyList()); + authorizationIndexerTester.indexProjectPermission(project3.uuid(), emptyList(), emptyList()); underTest.deleteProject(project1.uuid()); @@ -144,7 +144,7 @@ public class ProjectMeasuresIndexerTest { ComponentDto project = newProjectDto(); componentDbTester.insertProjectAndSnapshot(project); underTest.index(); - authorizationIndexerTester.insertProjectAuthorization(project.uuid(), emptyList(), emptyList()); + authorizationIndexerTester.indexProjectPermission(project.uuid(), emptyList(), emptyList()); underTest.deleteProject("UNKNOWN"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java index d0930e213bc..2bfef03e97f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java @@ -46,7 +46,7 @@ import org.sonar.server.component.es.ProjectMeasuresDoc; import org.sonar.server.component.es.ProjectMeasuresIndex; import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.EsTester; -import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.KeyExamples; import org.sonar.server.ws.TestRequest; @@ -90,7 +90,7 @@ public class SearchProjectsActionTest { private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); - private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); + private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es); private WsActionTester ws = new WsActionTester( new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client(), userSession), new ProjectMeasuresQueryValidator(dbClient))); @@ -237,7 +237,7 @@ public class SearchProjectsActionTest { try { es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc().setId(project.uuid()).setKey(project.key()).setName(project.name()).setMeasures(measures)); - authorizationIndexerTester.insertProjectAuthorization(project.uuid(), singletonList(DefaultGroups.ANYONE), Collections.emptyList()); + authorizationIndexerTester.indexProjectPermission(project.uuid(), singletonList(DefaultGroups.ANYONE), Collections.emptyList()); } catch (Exception e) { Throwables.propagate(e); } 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 e78f57338dd..fd83a6f5682 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 @@ -44,8 +44,8 @@ import org.sonar.server.computation.task.projectanalysis.component.ViewsComponen import org.sonar.server.computation.task.step.ComputationStep; import org.sonar.server.es.EsTester; import org.sonar.server.issue.index.IssueIndexDefinition; -import org.sonar.server.permission.index.AuthorizationIndexer; -import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexer; +import org.sonar.server.permission.index.PermissionIndexerTester; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -73,7 +73,7 @@ public class ApplyPermissionsStepTest extends BaseStepTest { @Rule public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.create(treeRootHolder); - private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(esTester); + private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(esTester); private DbSession dbSession; private DbClient dbClient = dbTester.getDbClient(); @@ -83,7 +83,7 @@ public class ApplyPermissionsStepTest extends BaseStepTest { @Before public void setUp() { dbSession = dbClient.openSession(false); - step = new ApplyPermissionsStep(dbClient, dbIdsRepository, new AuthorizationIndexer(dbClient, esTester.client()), new PermissionRepository(dbClient, settings), treeRootHolder); + step = new ApplyPermissionsStep(dbClient, dbIdsRepository, new PermissionIndexer(dbClient, esTester.client()), new PermissionRepository(dbClient, settings), treeRootHolder); } @After @@ -108,7 +108,7 @@ public class ApplyPermissionsStepTest extends BaseStepTest { assertThat(dbClient.componentDao().selectOrFailByKey(dbSession, ROOT_KEY).getAuthorizationUpdatedAt()).isNotNull(); assertThat(dbClient.roleDao().selectGroupPermissions(dbSession, DefaultGroups.ANYONE, projectDto.getId())).containsOnly(UserRole.USER); - authorizationIndexerTester.verifyProjectExistsWithAuthorization(ROOT_UUID, singletonList(DefaultGroups.ANYONE), emptyList()); + authorizationIndexerTester.verifyProjectExistsWithPermission(ROOT_UUID, singletonList(DefaultGroups.ANYONE), emptyList()); } @Test 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 4b208ff0c67..12c41e71352 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 @@ -40,7 +40,7 @@ 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.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.server.view.index.ViewIndexer; @@ -66,7 +66,7 @@ public class IssueIndexDebtTest { IssueIndex index; IssueIndexer issueIndexer; - AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(tester); + PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(tester); ViewIndexer viewIndexer; @Before @@ -286,7 +286,7 @@ public class IssueIndexDebtTest { } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable Long user) { - authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); + authorizationIndexerTester.indexProjectPermission(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 7ef1349c567..98399e67d2a 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,7 +50,7 @@ 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.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.view.index.ViewDoc; import org.sonar.server.view.index.ViewIndexDefinition; @@ -79,7 +79,7 @@ public class IssueIndexTest { IssueIndex underTest; IssueIndexer issueIndexer; - AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(tester); + PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(tester); ViewIndexer viewIndexer; @Before @@ -1289,7 +1289,7 @@ public class IssueIndexTest { } private void addIssueAuthorization(String projectUuid, @Nullable String group, @Nullable Long user) { - authorizationIndexerTester.insertProjectAuthorization(projectUuid, singletonList(group), singletonList(user)); + authorizationIndexerTester.indexProjectPermission(projectUuid, singletonList(group), singletonList(user)); } private void indexView(String viewUuid, List 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 deleted file mode 100644 index 7fa98596c8c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationDaoTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.permission.index; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.System2; -import org.sonar.core.util.stream.Collectors; -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.permission.GroupPermissionDto; -import org.sonar.db.user.GroupDto; -import org.sonar.db.user.UserDbTester; -import org.sonar.db.user.UserDto; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.security.DefaultGroups.ANYONE; -import static org.sonar.api.web.UserRole.ADMIN; -import static org.sonar.api.web.UserRole.USER; - -public class AuthorizationDaoTest { - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - DbClient dbClient = dbTester.getDbClient(); - DbSession dbSession = dbTester.getSession(); - - ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); - UserDbTester userDbTester = new UserDbTester(dbTester); - - ComponentDto project1; - ComponentDto project2; - UserDto user1; - UserDto user2; - GroupDto group; - - AuthorizationDao underTest = new AuthorizationDao(); - - @Before - public void setUp() throws Exception { - project1 = componentDbTester.insertProject(); - project2 = componentDbTester.insertProject(); - user1 = userDbTester.insertUser(); - user2 = userDbTester.insertUser(); - group = userDbTester.insertGroup(); - } - - @Test - public void select_all() { - insertTestDataForProject1And2(); - - Collection dtos = underTest.selectAll(dbClient, dbSession); - assertThat(dtos).hasSize(2); - - AuthorizationDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); - assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); - assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); - assertThat(project1Authorization.getUpdatedAt()).isNotNull(); - - AuthorizationDao.Dto project2Authorization = getByProjectUuid(project2.uuid(), dtos); - assertThat(project2Authorization.getGroups()).containsOnly(ANYONE); - assertThat(project2Authorization.getUsers()).containsOnly(user1.getId(), user2.getId()); - assertThat(project2Authorization.getUpdatedAt()).isNotNull(); - } - - @Test - public void select_by_project() throws Exception { - insertTestDataForProject1And2(); - - Collection 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()); - assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); - assertThat(project1Authorization.getUpdatedAt()).isNotNull(); - } - - @Test - public void select_by_projects() throws Exception { - insertTestDataForProject1And2(); - - Map dtos = underTest.selectByProjects(dbClient, dbSession, asList(project1.uuid(), project2.uuid())) - .stream() - .collect(Collectors.uniqueIndex(AuthorizationDao.Dto::getProjectUuid, Function.identity())); - assertThat(dtos).hasSize(2); - - AuthorizationDao.Dto project1Authorization = dtos.get(project1.uuid()); - assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); - assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); - assertThat(project1Authorization.getUpdatedAt()).isNotNull(); - - AuthorizationDao.Dto project2Authorization = dtos.get(project2.uuid()); - assertThat(project2Authorization.getGroups()).containsOnly(ANYONE); - assertThat(project2Authorization.getUsers()).containsOnly(user1.getId(), user2.getId()); - assertThat(project2Authorization.getUpdatedAt()).isNotNull(); - } - - @Test - public void select_by_projects_with_high_number_of_projects() throws Exception { - List projects = new ArrayList<>(); - for (int i = 0; i < 350; i++) { - ComponentDto project = ComponentTesting.newProjectDto(Integer.toString(i)); - dbClient.componentDao().insert(dbSession, project); - projects.add(project.uuid()); - GroupPermissionDto dto = new GroupPermissionDto() - .setOrganizationUuid(group.getOrganizationUuid()) - .setGroupId(group.getId()) - .setRole(USER) - .setResourceId(project.getId()); - dbClient.groupPermissionDao().insert(dbSession, dto); - } - dbSession.commit(); - - Map dtos = underTest.selectByProjects(dbClient, dbSession, projects) - .stream() - .collect(Collectors.uniqueIndex(AuthorizationDao.Dto::getProjectUuid, Function.identity())); - assertThat(dtos).hasSize(350); - } - - @Test - public void no_authorization() { - userDbTester.insertProjectPermissionOnUser(user1, USER, project2); - userDbTester.insertProjectPermissionOnGroup(group, USER, project2); - - Collection dtos = underTest.selectAll(dbClient, dbSession); - - assertThat(dtos).hasSize(2); - AuthorizationDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); - assertThat(project1Authorization.getGroups()).isEmpty(); - assertThat(project1Authorization.getUsers()).isEmpty(); - assertThat(project1Authorization.getUpdatedAt()).isNotNull(); - } - - private static AuthorizationDao.Dto getByProjectUuid(String projectUuid, Collection dtos) { - return dtos.stream().filter(dto -> dto.getProjectUuid().equals(projectUuid)).findFirst().orElseThrow(IllegalArgumentException::new); - } - - private void insertTestDataForProject1And2() { - // user1 can access both projects - userDbTester.insertProjectPermissionOnUser(user1, USER, project1); - userDbTester.insertProjectPermissionOnUser(user1, ADMIN, project1); - userDbTester.insertProjectPermissionOnUser(user1, USER, project2); - - // user2 has user access on project2 only - userDbTester.insertProjectPermissionOnUser(user2, USER, project2); - - // group1 has user access on project1 only - userDbTester.insertProjectPermissionOnGroup(group, USER, project1); - userDbTester.insertProjectPermissionOnGroup(group, ADMIN, project1); - - // Anyone group has user access on both projects - userDbTester.insertProjectPermissionOnAnyone(USER, project1); - userDbTester.insertProjectPermissionOnAnyone(ADMIN, project1); - userDbTester.insertProjectPermissionOnAnyone(USER, project2); - } -} 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 deleted file mode 100644 index b53c43f14fe..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.permission.index; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.MapSettings; -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; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.security.DefaultGroups.ANYONE; -import static org.sonar.api.web.UserRole.ADMIN; -import static org.sonar.api.web.UserRole.USER; - -public class AuthorizationIndexerTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - @Rule - public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); - - ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); - UserDbTester userDbTester = new UserDbTester(dbTester); - AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(esTester); - - AuthorizationIndexer underTest = new AuthorizationIndexer(dbTester.getDbClient(), esTester.client()); - - @Test - public void index_all_does_nothing_when_no_data() { - underTest.indexAllIfEmpty(); - - assertThat(esTester.countDocuments("issues", "authorization")).isZero(); - } - - @Test - public void index_all() { - ComponentDto project = componentDbTester.insertProject(); - UserDto user = userDbTester.insertUser(); - userDbTester.insertProjectPermissionOnUser(user, USER, project); - userDbTester.insertProjectPermissionOnUser(user, ADMIN, project); - GroupDto group = userDbTester.insertGroup(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project); - userDbTester.insertProjectPermissionOnAnyone(USER, project); - - underTest.indexAllIfEmpty(); - - authorizationIndexerTester.verifyProjectExistsWithAuthorization(project.uuid(), asList(group.getName(), ANYONE), singletonList(user.getId())); - } - - @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(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project1); - ComponentDto project2 = componentDbTester.insertProject(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project2); - - underTest.index(dbTester.getSession(), project1.uuid()); - - authorizationIndexerTester.verifyProjectExistsWithAuthorization(project1.uuid(), asList(group.getName(), ANYONE), emptyList()); - authorizationIndexerTester.verifyProjectDoesNotExist(project2.uuid()); - } - - @Test - public void index_projects() throws Exception { - GroupDto group = userDbTester.insertGroup(); - ComponentDto project1 = componentDbTester.insertProject(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project1); - ComponentDto project2 = componentDbTester.insertProject(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project2); - ComponentDto project3 = componentDbTester.insertProject(); - userDbTester.insertProjectPermissionOnGroup(group, USER, project3); - - // Only index projects 1 and 2 - underTest.index(dbTester.getSession(), asList(project1.uuid(), project2.uuid())); - - authorizationIndexerTester.verifyProjectExistsWithAuthorization(project1.uuid(), asList(group.getName(), ANYONE), emptyList()); - authorizationIndexerTester.verifyProjectExistsWithAuthorization(project2.uuid(), asList(group.getName(), ANYONE), emptyList()); - authorizationIndexerTester.verifyProjectDoesNotExist(project3.uuid()); - } - - @Test - public void update_existing_permissions() { - authorizationIndexerTester.insertProjectAuthorization("ABC", singletonList("dev"), singletonList(10L)); - - // remove permissions -> dto has no users nor groups - underTest.index(new AuthorizationDao.Dto("ABC", System.currentTimeMillis())); - - authorizationIndexerTester.verifyProjectExistsWithoutAuthorization("ABC"); - } - - @Test - public void fail_when_trying_to_index_empty_project_uuids() throws Exception { - expectedException.expect(IllegalArgumentException.class); - underTest.index(dbTester.getSession(), Collections.emptyList()); - } -} 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 deleted file mode 100644 index 3356e397410..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/index/AuthorizationIndexerTester.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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.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 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; - -public class AuthorizationIndexerTester { - - private final EsTester esTester; - - private final AuthorizationIndexer authorizationIndexer; - - public AuthorizationIndexerTester(EsTester esTester) { - this.esTester = esTester; - this.authorizationIndexer = new AuthorizationIndexer(null, esTester.client()); - } - - public void insertProjectAuthorization(String projectUuid, List groupNames, List userLogins) { - AuthorizationDao.Dto authorization = new AuthorizationDao.Dto(projectUuid, System.currentTimeMillis()); - groupNames.forEach(authorization::addGroup); - userLogins.forEach(authorization::addUser); - authorizationIndexer.index(authorization); - } - - public void verifyEmptyProjectAuthorization() { - 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(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); - assertThat(esTester.getIds(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); - } - - public void verifyProjectExistsWithoutAuthorization(String projectUuid) { - verifyProjectExistsWithAuthorization(projectUuid, emptyList(), emptyList()); - } - - public void verifyProjectExistsWithAuthorization(String projectUuid, List groupNames, List userLogins) { - 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 groupNames, List userLogins) { - assertThat(esTester.getIds(index, type)).contains(projectUuid); - BoolQueryBuilder queryBuilder = boolQuery().must(termQuery(projectField, projectUuid)); - if (groupNames.isEmpty()) { - queryBuilder.mustNot(existsQuery(groupField)); - } else { - queryBuilder.must(termsQuery(groupField, groupNames)); - } - if (userLogins.isEmpty()) { - queryBuilder.mustNot(existsQuery(userField)); - } else { - queryBuilder.must(termsQuery(userField, userLogins)); - } - SearchRequestBuilder request = esTester.client() - .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/index/PermissionIndexerDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerDaoTest.java new file mode 100644 index 00000000000..4b0630b1d95 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerDaoTest.java @@ -0,0 +1,186 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.permission.index; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.core.util.stream.Collectors; +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.permission.GroupPermissionDto; +import org.sonar.db.user.GroupDto; +import org.sonar.db.user.UserDbTester; +import org.sonar.db.user.UserDto; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.security.DefaultGroups.ANYONE; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.api.web.UserRole.USER; + +public class PermissionIndexerDaoTest { + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + DbClient dbClient = dbTester.getDbClient(); + DbSession dbSession = dbTester.getSession(); + + ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); + UserDbTester userDbTester = new UserDbTester(dbTester); + + ComponentDto project1; + ComponentDto project2; + UserDto user1; + UserDto user2; + GroupDto group; + + PermissionIndexerDao underTest = new PermissionIndexerDao(); + + @Before + public void setUp() throws Exception { + project1 = componentDbTester.insertProject(); + project2 = componentDbTester.insertProject(); + user1 = userDbTester.insertUser(); + user2 = userDbTester.insertUser(); + group = userDbTester.insertGroup(); + } + + @Test + public void select_all() { + insertTestDataForProject1And2(); + + Collection dtos = underTest.selectAll(dbClient, dbSession); + assertThat(dtos).hasSize(2); + + PermissionIndexerDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); + assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); + assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); + assertThat(project1Authorization.getUpdatedAt()).isNotNull(); + + PermissionIndexerDao.Dto project2Authorization = getByProjectUuid(project2.uuid(), dtos); + assertThat(project2Authorization.getGroups()).containsOnly(ANYONE); + assertThat(project2Authorization.getUsers()).containsOnly(user1.getId(), user2.getId()); + assertThat(project2Authorization.getUpdatedAt()).isNotNull(); + } + + @Test + public void select_by_project() throws Exception { + insertTestDataForProject1And2(); + + Collection dtos = underTest.selectByProjects(dbClient, dbSession, singletonList(project1.uuid())); + assertThat(dtos).hasSize(1); + PermissionIndexerDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); + assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); + assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); + assertThat(project1Authorization.getUpdatedAt()).isNotNull(); + } + + @Test + public void select_by_projects() throws Exception { + insertTestDataForProject1And2(); + + Map dtos = underTest.selectByProjects(dbClient, dbSession, asList(project1.uuid(), project2.uuid())) + .stream() + .collect(Collectors.uniqueIndex(PermissionIndexerDao.Dto::getProjectUuid, Function.identity())); + assertThat(dtos).hasSize(2); + + PermissionIndexerDao.Dto project1Authorization = dtos.get(project1.uuid()); + assertThat(project1Authorization.getGroups()).containsOnly(ANYONE, group.getName()); + assertThat(project1Authorization.getUsers()).containsOnly(user1.getId()); + assertThat(project1Authorization.getUpdatedAt()).isNotNull(); + + PermissionIndexerDao.Dto project2Authorization = dtos.get(project2.uuid()); + assertThat(project2Authorization.getGroups()).containsOnly(ANYONE); + assertThat(project2Authorization.getUsers()).containsOnly(user1.getId(), user2.getId()); + assertThat(project2Authorization.getUpdatedAt()).isNotNull(); + } + + @Test + public void select_by_projects_with_high_number_of_projects() throws Exception { + List projects = new ArrayList<>(); + for (int i = 0; i < 350; i++) { + ComponentDto project = ComponentTesting.newProjectDto(Integer.toString(i)); + dbClient.componentDao().insert(dbSession, project); + projects.add(project.uuid()); + GroupPermissionDto dto = new GroupPermissionDto() + .setOrganizationUuid(group.getOrganizationUuid()) + .setGroupId(group.getId()) + .setRole(USER) + .setResourceId(project.getId()); + dbClient.groupPermissionDao().insert(dbSession, dto); + } + dbSession.commit(); + + Map dtos = underTest.selectByProjects(dbClient, dbSession, projects) + .stream() + .collect(Collectors.uniqueIndex(PermissionIndexerDao.Dto::getProjectUuid, Function.identity())); + assertThat(dtos).hasSize(350); + } + + @Test + public void no_authorization() { + userDbTester.insertProjectPermissionOnUser(user1, USER, project2); + userDbTester.insertProjectPermissionOnGroup(group, USER, project2); + + Collection dtos = underTest.selectAll(dbClient, dbSession); + + assertThat(dtos).hasSize(2); + PermissionIndexerDao.Dto project1Authorization = getByProjectUuid(project1.uuid(), dtos); + assertThat(project1Authorization.getGroups()).isEmpty(); + assertThat(project1Authorization.getUsers()).isEmpty(); + assertThat(project1Authorization.getUpdatedAt()).isNotNull(); + } + + private static PermissionIndexerDao.Dto getByProjectUuid(String projectUuid, Collection dtos) { + return dtos.stream().filter(dto -> dto.getProjectUuid().equals(projectUuid)).findFirst().orElseThrow(IllegalArgumentException::new); + } + + private void insertTestDataForProject1And2() { + // user1 can access both projects + userDbTester.insertProjectPermissionOnUser(user1, USER, project1); + userDbTester.insertProjectPermissionOnUser(user1, ADMIN, project1); + userDbTester.insertProjectPermissionOnUser(user1, USER, project2); + + // user2 has user access on project2 only + userDbTester.insertProjectPermissionOnUser(user2, USER, project2); + + // group1 has user access on project1 only + userDbTester.insertProjectPermissionOnGroup(group, USER, project1); + userDbTester.insertProjectPermissionOnGroup(group, ADMIN, project1); + + // Anyone group has user access on both projects + userDbTester.insertProjectPermissionOnAnyone(USER, project1); + userDbTester.insertProjectPermissionOnAnyone(ADMIN, project1); + userDbTester.insertProjectPermissionOnAnyone(USER, project2); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java new file mode 100644 index 00000000000..e229c2e6a15 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTest.java @@ -0,0 +1,176 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.permission.index; + +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.config.MapSettings; +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; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.security.DefaultGroups.ANYONE; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.api.web.UserRole.USER; + +public class PermissionIndexerTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + @Rule + public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); + + ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); + UserDbTester userDbTester = new UserDbTester(dbTester); + + PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(esTester); + + PermissionIndexer underTest = new PermissionIndexer(dbTester.getDbClient(), esTester.client()); + + @Test + public void index_all_does_nothing_when_no_data() { + underTest.indexAllIfEmpty(); + + assertThat(esTester.countDocuments("issues", "authorization")).isZero(); + } + + @Test + public void index_all() { + ComponentDto project = componentDbTester.insertProject(); + UserDto user = userDbTester.insertUser(); + userDbTester.insertProjectPermissionOnUser(user, USER, project); + userDbTester.insertProjectPermissionOnUser(user, ADMIN, project); + GroupDto group = userDbTester.insertGroup(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project); + userDbTester.insertProjectPermissionOnAnyone(USER, project); + + underTest.indexAllIfEmpty(); + + authorizationIndexerTester.verifyProjectExistsWithPermission(project.uuid(), asList(group.getName(), ANYONE), singletonList(user.getId())); + } + + @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.verifyProjectExistsWithPermission(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(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project1); + ComponentDto project2 = componentDbTester.insertProject(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project2); + + underTest.index(dbTester.getSession(), project1.uuid()); + + authorizationIndexerTester.verifyProjectExistsWithPermission(project1.uuid(), asList(group.getName(), ANYONE), emptyList()); + authorizationIndexerTester.verifyProjectDoesNotExist(project2.uuid()); + } + + @Test + public void index_projects() throws Exception { + GroupDto group = userDbTester.insertGroup(); + ComponentDto project1 = componentDbTester.insertProject(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project1); + ComponentDto project2 = componentDbTester.insertProject(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project2); + ComponentDto project3 = componentDbTester.insertProject(); + userDbTester.insertProjectPermissionOnGroup(group, USER, project3); + + // Only index projects 1 and 2 + underTest.index(dbTester.getSession(), asList(project1.uuid(), project2.uuid())); + + authorizationIndexerTester.verifyProjectExistsWithPermission(project1.uuid(), asList(group.getName(), ANYONE), emptyList()); + authorizationIndexerTester.verifyProjectExistsWithPermission(project2.uuid(), asList(group.getName(), ANYONE), emptyList()); + authorizationIndexerTester.verifyProjectDoesNotExist(project3.uuid()); + } + + @Test + public void update_existing_permissions() { + authorizationIndexerTester.indexProjectPermission("ABC", singletonList("dev"), singletonList(10L)); + + // remove permissions -> dto has no users nor groups + underTest.index(new PermissionIndexerDao.Dto("ABC", System.currentTimeMillis())); + + authorizationIndexerTester.verifyProjectExistsWithoutPermission("ABC"); + } + + @Test + public void fail_when_trying_to_index_empty_project_uuids() throws Exception { + expectedException.expect(IllegalArgumentException.class); + underTest.index(dbTester.getSession(), Collections.emptyList()); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTester.java b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTester.java new file mode 100644 index 00000000000..70c8ef952f3 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerTester.java @@ -0,0 +1,99 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.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 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; + +public class PermissionIndexerTester { + + private final EsTester esTester; + + private final PermissionIndexer permissionIndexer; + + public PermissionIndexerTester(EsTester esTester) { + this.esTester = esTester; + this.permissionIndexer = new PermissionIndexer(null, esTester.client()); + } + + public void indexProjectPermission(String projectUuid, List groupNames, List userLogins) { + PermissionIndexerDao.Dto authorization = new PermissionIndexerDao.Dto(projectUuid, System.currentTimeMillis()); + groupNames.forEach(authorization::addGroup); + userLogins.forEach(authorization::addUser); + permissionIndexer.index(authorization); + } + + public void verifyEmptyProjectPermission() { + 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(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); + assertThat(esTester.getIds(ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES, ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION)).doesNotContain(projectUuid); + } + + public void verifyProjectExistsWithoutPermission(String projectUuid) { + verifyProjectExistsWithPermission(projectUuid, emptyList(), emptyList()); + } + + public void verifyProjectExistsWithPermission(String projectUuid, List groupNames, List userLogins) { + verifyProjectExistsWithPermissionInIndex(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, + IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS, IssueIndexDefinition.FIELD_AUTHORIZATION_USERS, + projectUuid, groupNames, userLogins); + verifyProjectExistsWithPermissionInIndex(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 verifyProjectExistsWithPermissionInIndex(String index, String type, String projectField, String groupField, String userField, String projectUuid, + List groupNames, List userLogins) { + assertThat(esTester.getIds(index, type)).contains(projectUuid); + BoolQueryBuilder queryBuilder = boolQuery().must(termQuery(projectField, projectUuid)); + if (groupNames.isEmpty()) { + queryBuilder.mustNot(existsQuery(groupField)); + } else { + queryBuilder.must(termsQuery(groupField, groupNames)); + } + if (userLogins.isEmpty()) { + queryBuilder.mustNot(existsQuery(userField)); + } else { + queryBuilder.must(termsQuery(userField, userLogins)); + } + SearchRequestBuilder request = esTester.client() + .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/BasePermissionWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java index 2a95ad0a6e8..9413b71354a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java @@ -35,7 +35,7 @@ import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.permission.UserPermissionChanger; -import org.sonar.server.permission.index.AuthorizationIndexer; +import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.usergroups.ws.GroupWsSupport; import org.sonar.server.ws.WsTester; @@ -77,7 +77,7 @@ public abstract class BasePermissionWsTest { protected PermissionUpdater newPermissionUpdater() { return new PermissionUpdater(db.getDbClient(), - mock(AuthorizationIndexer.class), + mock(PermissionIndexer.class), new UserPermissionChanger(db.getDbClient(), defaultOrganizationProvider), new GroupPermissionChanger(db.getDbClient(), defaultOrganizationProvider)); } 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 5c3957ea7de..9a216e68b7a 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 @@ -43,8 +43,8 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.permission.PermissionService; -import org.sonar.server.permission.index.AuthorizationIndexer; -import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.permission.index.PermissionIndexer; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.permission.ws.BasePermissionWsTest; import org.sonar.server.ws.WsTester; @@ -73,15 +73,15 @@ public class ApplyTemplateActionTest extends BasePermissionWsTest