From b1c661b552fc1f76db2ed76b0c624712f2d8f3b2 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Thu, 4 Sep 2014 10:38:18 +0200 Subject: [PATCH] SONAR-5559 Implemente IssueAuthorization mapping --- .../java/org/sonar/server/db/DbClient.java | 7 + .../issue/db/IssueAuthorizationDao.java | 72 +++ .../sonar/server/issue/db/package-info.java | 24 + .../issue/index/IssueAuthorizationDoc.java | 50 +++ .../issue/index/IssueAuthorizationIndex.java | 76 ++++ .../index/IssueAuthorizationNormalizer.java | 93 ++++ .../sonar/server/issue/index/IssueIndex.java | 2 +- .../server/issue/index/package-info.java | 24 + .../server/platform/ServerComponents.java | 157 +------ .../sonar/server/search/IndexDefinition.java | 3 +- .../issue/db/IssueBackendMediumTest.java | 213 ++------- .../issue/db/IssueBackendMediumTest2.java | 421 ------------------ .../core/issue/db/IssueAuthorizationDto.java | 75 ++++ .../issue/db/IssueAuthorizationMapper.java | 27 ++ .../org/sonar/core/persistence/MyBatis.java | 3 +- .../issue/db/IssueAuthorizationMapper.xml | 17 + 16 files changed, 526 insertions(+), 738 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java create mode 100644 sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java index 846357d0bc4..d9fc72df394 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java +++ b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java @@ -34,6 +34,7 @@ import org.sonar.core.user.AuthorizationDao; import org.sonar.core.user.UserDao; import org.sonar.server.activity.db.ActivityDao; import org.sonar.server.component.persistence.ComponentDao; +import org.sonar.server.issue.db.IssueAuthorizationDao; import org.sonar.server.issue.db.IssueDao; import org.sonar.server.measure.persistence.MeasureDao; import org.sonar.server.measure.persistence.MetricDao; @@ -63,6 +64,7 @@ public class DbClient implements ServerComponent { private final AuthorizationDao authorizationDao; private final UserDao userDao; private final IssueDao issueDao; + private final IssueAuthorizationDao issueAuthorizationDao; public DbClient(Database db, MyBatis myBatis, DaoComponent... daoComponents) { this.db = db; @@ -86,6 +88,7 @@ public class DbClient implements ServerComponent { authorizationDao = getDao(map, AuthorizationDao.class); userDao = getDao(map, UserDao.class); issueDao = getDao(map, IssueDao.class); + issueAuthorizationDao = getDao(map, IssueAuthorizationDao.class); } public Database database() { @@ -108,6 +111,10 @@ public class DbClient implements ServerComponent { return issueDao; } + public IssueAuthorizationDao issueAuthorizationDao() { + return issueAuthorizationDao; + } + public QualityProfileDao qualityProfileDao() { return qualityProfileDao; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java b/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java new file mode 100644 index 00000000000..24ae9bf7d31 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java @@ -0,0 +1,72 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.issue.db; + +import com.google.common.annotations.VisibleForTesting; +import org.sonar.api.utils.System2; +import org.sonar.core.issue.db.IssueAuthorizationDto; +import org.sonar.core.issue.db.IssueAuthorizationMapper; +import org.sonar.core.persistence.DaoComponent; +import org.sonar.core.persistence.DbSession; +import org.sonar.server.db.BaseDao; +import org.sonar.server.search.IndexDefinition; + +import java.util.Date; + +public class IssueAuthorizationDao extends BaseDao implements DaoComponent { + + public IssueAuthorizationDao() { + this(System2.INSTANCE); + } + + @VisibleForTesting + public IssueAuthorizationDao(System2 system) { + super(IndexDefinition.ISSUES_AUTHORIZATION, IssueAuthorizationMapper.class, system); + } + + @Override + protected IssueAuthorizationDto doGetNullableByKey(DbSession session, String key) { + return mapper(session).selectByKey(key); + } + + @Override + protected IssueAuthorizationDto doUpdate(DbSession session, IssueAuthorizationDto issueAuthorization) { + // TODO ? + // mapper(session).update(issueAuthorization); + return issueAuthorization; + } + + @Override + protected IssueAuthorizationDto doInsert(DbSession session, IssueAuthorizationDto issueAuthorization) { + // TODO ? + // Preconditions.checkNotNull(issueAuthorization.getKey(), "Cannot insert IssueAuthorization with empty key!"); + // Preconditions.checkNotNull(issueAuthorization.getPermission(), "Cannot insert IssueAuthorization with no permission!"); + // mapper(session).insert(issueAuthorization); + return issueAuthorization; + } + + @Override + protected Iterable findAfterDate(DbSession session, Date date) { + // TODO ? + // return mapper(session).selectAfterDate(new Timestamp(date.getTime())); + return null; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java new file mode 100644 index 00000000000..9d25d51cf30 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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. + */ + +@ParametersAreNonnullByDefault +package org.sonar.server.issue.db; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java new file mode 100644 index 00000000000..f0f9fd79973 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.issue.index; + +import org.sonar.server.search.BaseDoc; + +import java.util.List; +import java.util.Map; + +public class IssueAuthorizationDoc extends BaseDoc { + + public IssueAuthorizationDoc(Map fields) { + super(fields); + } + + public String project() { + return getField(IssueAuthorizationNormalizer.IssueAuthorizationField.PROJECT.field()); + } + + public String permission() { + return getField(IssueAuthorizationNormalizer.IssueAuthorizationField.PERMISSION.field()); + } + + public List groups() { + return (List) getField(IssueAuthorizationNormalizer.IssueAuthorizationField.GROUPS.field()); + } + + public List users() { + return (List) getField(IssueAuthorizationNormalizer.IssueAuthorizationField.USERS.field()); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java new file mode 100644 index 00000000000..c746fb2523c --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java @@ -0,0 +1,76 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.issue.index; + +import com.google.common.base.Preconditions; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.sonar.core.issue.db.IssueAuthorizationDto; +import org.sonar.server.search.BaseIndex; +import org.sonar.server.search.IndexDefinition; +import org.sonar.server.search.IndexField; +import org.sonar.server.search.SearchClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class IssueAuthorizationIndex extends BaseIndex { + + public IssueAuthorizationIndex(IssueAuthorizationNormalizer normalizer, SearchClient client) { + super(IndexDefinition.ISSUES_AUTHORIZATION, normalizer, client); + } + + @Override + protected String getKeyValue(String s) { + return s; + } + + @Override + protected Settings getIndexSettings() throws IOException { + return ImmutableSettings.builder() + .put("index.number_of_replicas", 0) + .put("index.number_of_shards", 1) + .build(); + } + + @Override + protected Map mapProperties() { + Map mapping = new HashMap(); + for (IndexField field : IssueAuthorizationNormalizer.IssueAuthorizationField.ALL_FIELDS) { + mapping.put(field.field(), mapField(field)); + } + return mapping; + } + + @Override + protected Map mapKey() { + Map mapping = new HashMap(); + mapping.put("path", IssueAuthorizationNormalizer.IssueAuthorizationField.PROJECT.field()); + return mapping; + } + + @Override + public IssueAuthorizationDoc toDoc(Map fields) { + Preconditions.checkNotNull(fields, "Cannot construct IssueAuthorization with null response"); + return new IssueAuthorizationDoc(fields); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java new file mode 100644 index 00000000000..001ad5f6d90 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java @@ -0,0 +1,93 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.issue.index; + +import com.google.common.collect.ImmutableList; +import org.elasticsearch.action.update.UpdateRequest; +import org.sonar.core.issue.db.IssueAuthorizationDto; +import org.sonar.server.db.DbClient; +import org.sonar.server.search.BaseNormalizer; +import org.sonar.server.search.IndexDefinition; +import org.sonar.server.search.IndexField; +import org.sonar.server.search.Indexable; + +import java.lang.reflect.Field; +import java.util.*; + +public class IssueAuthorizationNormalizer extends BaseNormalizer { + + public IssueAuthorizationNormalizer(DbClient db) { + super(IndexDefinition.ISSUES, db); + } + + public static final class IssueAuthorizationField extends Indexable { + + public static final IndexField PROJECT = add(IndexField.Type.STRING, "project"); + public static final IndexField PERMISSION = add(IndexField.Type.STRING, "permission"); + public static final IndexField GROUPS = add(IndexField.Type.STRING, "groups"); + public static final IndexField USERS = add(IndexField.Type.STRING, "users"); + + public static final Set ALL_FIELDS = getAllFields(); + + private static final Set getAllFields() { + Set fields = new HashSet(); + for (Field classField : IssueAuthorizationField.class.getDeclaredFields()) { + if (classField.getType().isAssignableFrom(IndexField.class)) { + try { + fields.add(IndexField.class.cast(classField.get(null))); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Could not access Field '" + classField.getName() + "'", e); + } + } + } + return fields; + } + + public static final IndexField of(String fieldName) { + for (IndexField field : ALL_FIELDS) { + if (field.field().equals(fieldName)) { + return field; + } + } + throw new IllegalStateException("Could not find an IndexField for '" + fieldName + "'"); + } + } + + @Override + public List normalize(IssueAuthorizationDto dto) { + Map update = new HashMap(); + + update.put(IssueAuthorizationField.PROJECT.field(), dto.getProject()); + update.put(IssueAuthorizationField.PERMISSION.field(), dto.getPermission()); + update.put(IssueAuthorizationField.USERS.field(), dto.getUsers()); + update.put(IssueAuthorizationField.GROUPS.field(), dto.getGroups()); + + /** Upsert elements */ + Map upsert = getUpsertFor(IssueAuthorizationField.ALL_FIELDS, update); + upsert.put(IssueAuthorizationField.PROJECT.field(), dto.getKey()); + + return ImmutableList.of( + new UpdateRequest() + .id(dto.getKey()) + .doc(update) + .upsert(upsert)); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java index ff2f9be83fa..465013a2b91 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -78,7 +78,7 @@ public class IssueIndex extends BaseIndex { } private String getParentType() { - return IndexDefinition.ISSUES_PROJECT.getIndexType(); + return IndexDefinition.ISSUES_AUTHORIZATION.getIndexType(); } private Map mapRouting() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java new file mode 100644 index 00000000000..da175d852d0 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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. + */ + +@ParametersAreNonnullByDefault +package org.sonar.server.issue.index; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 70d00ae0069..c92fa04d428 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -52,13 +52,7 @@ import org.sonar.core.measure.db.MeasureFilterDao; import org.sonar.core.metric.DefaultMetricFinder; import org.sonar.core.notification.DefaultNotificationManager; import org.sonar.core.permission.PermissionFacade; -import org.sonar.core.persistence.DaoUtils; -import org.sonar.core.persistence.DatabaseVersion; -import org.sonar.core.persistence.DefaultDatabase; -import org.sonar.core.persistence.MyBatis; -import org.sonar.core.persistence.PreviewDatabaseFactory; -import org.sonar.core.persistence.SemaphoreUpdater; -import org.sonar.core.persistence.SemaphoresImpl; +import org.sonar.core.persistence.*; import org.sonar.core.preview.PreviewCache; import org.sonar.core.profiling.Profiling; import org.sonar.core.purge.PurgeProfiler; @@ -92,50 +86,26 @@ import org.sonar.server.charts.ChartFactory; import org.sonar.server.component.DefaultComponentFinder; import org.sonar.server.component.DefaultRubyComponentService; import org.sonar.server.component.persistence.ComponentDao; -import org.sonar.server.component.ws.ComponentAppAction; -import org.sonar.server.component.ws.ComponentsWs; -import org.sonar.server.component.ws.EventsWs; -import org.sonar.server.component.ws.ProjectsWs; -import org.sonar.server.component.ws.ResourcesWs; +import org.sonar.server.component.ws.*; import org.sonar.server.config.ws.PropertiesWs; import org.sonar.server.db.DatabaseChecker; import org.sonar.server.db.DbClient; import org.sonar.server.db.EmbeddedDatabaseFactory; import org.sonar.server.db.migrations.DatabaseMigrations; import org.sonar.server.db.migrations.DatabaseMigrator; -import org.sonar.server.debt.DebtCharacteristicsXMLImporter; -import org.sonar.server.debt.DebtModelBackup; -import org.sonar.server.debt.DebtModelLookup; -import org.sonar.server.debt.DebtModelOperations; -import org.sonar.server.debt.DebtModelPluginRepository; -import org.sonar.server.debt.DebtModelService; -import org.sonar.server.debt.DebtModelXMLExporter; -import org.sonar.server.debt.DebtRulesXMLImporter; +import org.sonar.server.debt.*; import org.sonar.server.duplication.ws.DuplicationsJsonWriter; import org.sonar.server.duplication.ws.DuplicationsParser; import org.sonar.server.duplication.ws.DuplicationsWs; -import org.sonar.server.issue.ActionService; -import org.sonar.server.issue.AssignAction; -import org.sonar.server.issue.CommentAction; -import org.sonar.server.issue.DefaultIssueFinder; -import org.sonar.server.issue.InternalRubyIssueService; -import org.sonar.server.issue.IssueBulkChangeService; -import org.sonar.server.issue.IssueChangelogFormatter; -import org.sonar.server.issue.IssueChangelogService; -import org.sonar.server.issue.IssueCommentService; -import org.sonar.server.issue.IssueService; -import org.sonar.server.issue.IssueStatsFinder; -import org.sonar.server.issue.PlanAction; -import org.sonar.server.issue.PublicRubyIssueService; -import org.sonar.server.issue.ServerIssueStorage; -import org.sonar.server.issue.SetSeverityAction; -import org.sonar.server.issue.TransitionAction; +import org.sonar.server.issue.*; import org.sonar.server.issue.actionplan.ActionPlanService; import org.sonar.server.issue.actionplan.ActionPlanWs; import org.sonar.server.issue.db.IssueDao; import org.sonar.server.issue.filter.IssueFilterService; import org.sonar.server.issue.filter.IssueFilterWriter; import org.sonar.server.issue.filter.IssueFilterWs; +import org.sonar.server.issue.index.IssueAuthorizationIndex; +import org.sonar.server.issue.index.IssueAuthorizationNormalizer; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.issue.index.IssueNormalizer; import org.sonar.server.issue.ws.IssueActionsWriter; @@ -160,84 +130,22 @@ import org.sonar.server.platform.ws.L10nWs; import org.sonar.server.platform.ws.RestartHandler; import org.sonar.server.platform.ws.ServerWs; import org.sonar.server.platform.ws.SystemWs; -import org.sonar.server.plugins.InstalledPluginReferentialFactory; -import org.sonar.server.plugins.PluginDownloader; -import org.sonar.server.plugins.ServerExtensionInstaller; -import org.sonar.server.plugins.ServerPluginJarInstaller; -import org.sonar.server.plugins.ServerPluginJarsInstaller; -import org.sonar.server.plugins.ServerPluginRepository; -import org.sonar.server.plugins.UpdateCenterClient; -import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.plugins.*; import org.sonar.server.qualitygate.QgateProjectFinder; import org.sonar.server.qualitygate.QualityGates; import org.sonar.server.qualitygate.RegisterQualityGates; -import org.sonar.server.qualitygate.ws.QGatesAppAction; -import org.sonar.server.qualitygate.ws.QGatesCopyAction; -import org.sonar.server.qualitygate.ws.QGatesCreateAction; -import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction; -import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction; -import org.sonar.server.qualitygate.ws.QGatesDeselectAction; -import org.sonar.server.qualitygate.ws.QGatesDestroyAction; -import org.sonar.server.qualitygate.ws.QGatesListAction; -import org.sonar.server.qualitygate.ws.QGatesRenameAction; -import org.sonar.server.qualitygate.ws.QGatesSearchAction; -import org.sonar.server.qualitygate.ws.QGatesSelectAction; -import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction; -import org.sonar.server.qualitygate.ws.QGatesShowAction; -import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction; -import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction; -import org.sonar.server.qualitygate.ws.QGatesWs; -import org.sonar.server.qualityprofile.BuiltInProfiles; -import org.sonar.server.qualityprofile.QProfileBackuper; -import org.sonar.server.qualityprofile.QProfileCopier; -import org.sonar.server.qualityprofile.QProfileExporters; -import org.sonar.server.qualityprofile.QProfileFactory; -import org.sonar.server.qualityprofile.QProfileLoader; -import org.sonar.server.qualityprofile.QProfileLookup; -import org.sonar.server.qualityprofile.QProfileProjectLookup; -import org.sonar.server.qualityprofile.QProfileProjectOperations; -import org.sonar.server.qualityprofile.QProfileRepositoryExporter; -import org.sonar.server.qualityprofile.QProfileReset; -import org.sonar.server.qualityprofile.QProfileService; -import org.sonar.server.qualityprofile.QProfiles; -import org.sonar.server.qualityprofile.RegisterQualityProfiles; -import org.sonar.server.qualityprofile.RuleActivator; -import org.sonar.server.qualityprofile.RuleActivatorContextFactory; +import org.sonar.server.qualitygate.ws.*; +import org.sonar.server.qualityprofile.*; import org.sonar.server.qualityprofile.db.ActiveRuleDao; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; -import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions; -import org.sonar.server.qualityprofile.ws.ProfilesWs; -import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction; -import org.sonar.server.qualityprofile.ws.QProfilesWs; -import org.sonar.server.qualityprofile.ws.RuleActivationActions; -import org.sonar.server.rule.DefaultRuleFinder; -import org.sonar.server.rule.DeprecatedRulesDefinition; -import org.sonar.server.rule.RegisterRules; -import org.sonar.server.rule.RubyRuleService; -import org.sonar.server.rule.RuleCreator; -import org.sonar.server.rule.RuleDefinitionsLoader; -import org.sonar.server.rule.RuleDeleter; -import org.sonar.server.rule.RuleOperations; -import org.sonar.server.rule.RuleRepositories; -import org.sonar.server.rule.RuleService; -import org.sonar.server.rule.RuleUpdater; +import org.sonar.server.qualityprofile.ws.*; +import org.sonar.server.rule.*; import org.sonar.server.rule.db.RuleDao; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleNormalizer; -import org.sonar.server.rule.ws.ActiveRuleCompleter; -import org.sonar.server.rule.ws.AppAction; -import org.sonar.server.rule.ws.DeleteAction; -import org.sonar.server.rule.ws.RuleMapping; -import org.sonar.server.rule.ws.RulesWebService; -import org.sonar.server.rule.ws.SearchAction; -import org.sonar.server.rule.ws.TagsAction; -import org.sonar.server.rule.ws.UpdateAction; -import org.sonar.server.search.IndexClient; -import org.sonar.server.search.IndexQueue; -import org.sonar.server.search.IndexSynchronizer; -import org.sonar.server.search.SearchClient; -import org.sonar.server.search.SearchHealth; +import org.sonar.server.rule.ws.*; +import org.sonar.server.search.*; import org.sonar.server.source.CodeColorizers; import org.sonar.server.source.DeprecatedSourceDecorator; import org.sonar.server.source.HtmlSourceDecorator; @@ -246,27 +154,9 @@ import org.sonar.server.source.ws.ScmAction; import org.sonar.server.source.ws.ScmWriter; import org.sonar.server.source.ws.ShowAction; import org.sonar.server.source.ws.SourcesWs; -import org.sonar.server.startup.CleanPreviewAnalysisCache; -import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules; -import org.sonar.server.startup.GeneratePluginIndex; -import org.sonar.server.startup.GwtPublisher; -import org.sonar.server.startup.JdbcDriverDeployer; -import org.sonar.server.startup.LogServerId; -import org.sonar.server.startup.RegisterDashboards; -import org.sonar.server.startup.RegisterDebtModel; -import org.sonar.server.startup.RegisterMetrics; -import org.sonar.server.startup.RegisterNewMeasureFilters; -import org.sonar.server.startup.RegisterPermissionTemplates; -import org.sonar.server.startup.RegisterServletFilters; -import org.sonar.server.startup.RenameDeprecatedPropertyKeys; -import org.sonar.server.startup.ServerMetadataPersister; +import org.sonar.server.startup.*; import org.sonar.server.test.CoverageService; -import org.sonar.server.test.ws.CoverageShowAction; -import org.sonar.server.test.ws.CoverageWs; -import org.sonar.server.test.ws.TestsCoveredFilesAction; -import org.sonar.server.test.ws.TestsShowAction; -import org.sonar.server.test.ws.TestsTestCasesAction; -import org.sonar.server.test.ws.TestsWs; +import org.sonar.server.test.ws.*; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.text.RubyTextService; import org.sonar.server.ui.JRubyI18n; @@ -274,22 +164,11 @@ import org.sonar.server.ui.JRubyProfiling; import org.sonar.server.ui.PageDecorations; import org.sonar.server.ui.Views; import org.sonar.server.updatecenter.ws.UpdateCenterWs; -import org.sonar.server.user.DefaultUserService; -import org.sonar.server.user.DoPrivileged; -import org.sonar.server.user.GroupMembershipFinder; -import org.sonar.server.user.GroupMembershipService; -import org.sonar.server.user.NewUserNotifier; -import org.sonar.server.user.SecurityRealmFactory; +import org.sonar.server.user.*; import org.sonar.server.user.ws.FavoritesWs; import org.sonar.server.user.ws.UserPropertiesWs; import org.sonar.server.user.ws.UsersWs; -import org.sonar.server.util.BooleanTypeValidation; -import org.sonar.server.util.FloatTypeValidation; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.StringListTypeValidation; -import org.sonar.server.util.StringTypeValidation; -import org.sonar.server.util.TextTypeValidation; -import org.sonar.server.util.TypeValidations; +import org.sonar.server.util.*; import org.sonar.server.ws.ListingWs; import org.sonar.server.ws.WebServiceEngine; @@ -347,11 +226,13 @@ class ServerComponents { SearchClient.class, ActivityNormalizer.class, IssueNormalizer.class, + IssueAuthorizationNormalizer.class, RuleNormalizer.class, ActiveRuleNormalizer.class, RuleIndex.class, ActiveRuleIndex.class, IssueIndex.class, + IssueAuthorizationIndex.class, ActivityIndex.class, IndexClient.class, SearchHealth.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java index 39ce5c7ba7f..0b7a06a6ce6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java @@ -52,8 +52,7 @@ public class IndexDefinition { public static final IndexDefinition RULE = new IndexDefinition("rules", "rule"); public static final IndexDefinition ACTIVE_RULE = new IndexDefinition("rules", "activeRule"); - public static final IndexDefinition ISSUES_PROJECT = new IndexDefinition("issues", "issueProject"); - public static final IndexDefinition ISSUES_PERMISSION = new IndexDefinition("issues", "issuePermission"); + public static final IndexDefinition ISSUES_AUTHORIZATION = new IndexDefinition("issues", "issueAuthorization"); public static final IndexDefinition ISSUES = new IndexDefinition("issues", "issue"); public static final IndexDefinition LOG = new IndexDefinition("logs", "sonarLog"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java index fe15c037a39..b83fc24095d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java @@ -17,13 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + package org.sonar.server.issue.db; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.index.query.BoolFilterBuilder; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.index.query.OrFilterBuilder; @@ -44,16 +44,17 @@ import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.platform.Platform; import org.sonar.server.rule.RuleTesting; import org.sonar.server.rule.db.RuleDao; -import org.sonar.server.search.BaseIndex; import org.sonar.server.search.IndexClient; import org.sonar.server.search.IndexDefinition; import org.sonar.server.search.SearchClient; import org.sonar.server.tester.ServerTester; -import java.io.IOException; -import java.io.Serializable; -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static org.fest.assertions.Assertions.assertThat; @@ -192,8 +193,6 @@ public class IssueBackendMediumTest { @Test public void issue_authorization_on_group() throws Exception { SearchClient searchClient = tester.get(SearchClient.class); - createIssuePermissionIndex(searchClient); - createIssueProjectIndex(searchClient); RuleDto rule = RuleTesting.newXooX1(); tester.get(RuleDao.class).insert(dbSession, rule); @@ -201,18 +200,17 @@ public class IssueBackendMediumTest { ComponentDto project1 = addComponent(1L, 1L, "SonarQube :: Server"); ComponentDto file1 = addComponent(2L, 1L, "IssueAction.java"); addIssue(rule, project1, file1); - addIssueAuthorization(searchClient, project1, null, "user"); + addIssueAuthorization(searchClient, project1, null, newArrayList("user")).get(); ComponentDto project2 = addComponent(10L, 10L, "SonarQube :: Core"); ComponentDto file2 = addComponent(11L, 10L, "IssueDao.java"); addIssue(rule, project2, file2); - addIssueAuthorization(searchClient, project2, null, "reviewer"); + addIssueAuthorization(searchClient, project2, null, newArrayList("reviewer")).get(); ComponentDto project3 = addComponent(20L, 20L, "SonarQube :: WS"); ComponentDto file3 = addComponent(21L, 20L, "IssueWS.java"); addIssue(rule, project3, file3); - addIssueAuthorization(searchClient, project3, null, "user"); - addIssueAuthorization(searchClient, project3, null, "reviewer"); + addIssueAuthorization(searchClient, project3, null, newArrayList("user", "reviewer")).get(); dbSession.commit(); @@ -225,8 +223,6 @@ public class IssueBackendMediumTest { @Test public void issue_authorization_on_user() throws Exception { SearchClient searchClient = tester.get(SearchClient.class); - createIssuePermissionIndex(searchClient); - createIssueProjectIndex(searchClient); RuleDto rule = RuleTesting.newXooX1(); tester.get(RuleDao.class).insert(dbSession, rule); @@ -234,7 +230,7 @@ public class IssueBackendMediumTest { ComponentDto project = addComponent(1L, 1L, "SonarQube"); ComponentDto file = addComponent(2L, 1L, "IssueAction.java"); addIssue(rule, project, file); - addIssueAuthorization(searchClient, project, "julien", null); + addIssueAuthorization(searchClient, project, newArrayList("julien"), null).get(); dbSession.commit(); @@ -242,15 +238,11 @@ public class IssueBackendMediumTest { assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(1); // The issue is not visible for user simon assertThat(searchIssueWithAuthorization(searchClient, "simon", "user").getHits().getTotalHits()).isEqualTo(0); - -// Thread.sleep(Integer.MAX_VALUE); } @Test public void issue_authorization_with_a_lot_of_issues() throws Exception { SearchClient searchClient = tester.get(SearchClient.class); - createIssuePermissionIndex(searchClient); - createIssueProjectIndex(searchClient); RuleDto rule = RuleTesting.newXooX1(); tester.get(RuleDao.class).insert(dbSession, rule); @@ -261,17 +253,23 @@ public class IssueBackendMediumTest { Long projectId = 1L; Long componentId = 1L; - BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient); + + List users = newArrayList(); + for (int u = 0; u < nbUser; u++) { + users.add("user-" + u); + } + + BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient).setRefresh(true); for (int p = 0; p < nbProject; p++) { ComponentDto project = addComponent(projectId, projectId, "Project-" + projectId.toString()); - addIssueAuthorization(searchClient, bulkRequestBuilder, project, null, "anyone"); + List groups = newArrayList(); + groups.add("anyone"); if (p % 2 == 0) { - addIssueAuthorization(searchClient, bulkRequestBuilder, project, null, "user"); - } - for (int u = 0; u < nbUser; u++) { - addIssueAuthorization(searchClient, bulkRequestBuilder, project, "user-" + u, null); + groups.add("user"); } + + bulkRequestBuilder.add(addIssueAuthorization(searchClient, project, users, groups, false)); for (int c = 0; c < componentPerProject; c++) { ComponentDto file = addComponent(componentId, projectId, "Component-" + componentId.toString()); addIssue(rule, project, file); @@ -294,15 +292,15 @@ public class IssueBackendMediumTest { // user-1 should see all issues assertThat(searchIssueWithAuthorization(searchClient, "user-1", "").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject); -// Thread.sleep(Integer.MAX_VALUE); + // Thread.sleep(Integer.MAX_VALUE); } private SearchResponse searchIssueWithAuthorization(SearchClient searchClient, String user, String... groups) { BoolFilterBuilder fb = FilterBuilders.boolFilter(); - OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("user", user)); + OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("users", user)); for (String group : groups) { - or.add(FilterBuilders.termFilter("group", group)); + or.add(FilterBuilders.termFilter("groups", group)); } fb.must(FilterBuilders.termFilter("permission", "read"), or).cache(true); // fb.must(FilterBuilders.termFilter("permission", "read"), or); @@ -311,11 +309,9 @@ public class IssueBackendMediumTest { .setQuery( QueryBuilders.filteredQuery( QueryBuilders.matchAllQuery(), - FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_PROJECT.getIndexType(), - QueryBuilders.hasChildQuery(IndexDefinition.ISSUES_PERMISSION.getIndexType(), - QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), fb) - ) + FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_AUTHORIZATION.getIndexType(), + QueryBuilders.filteredQuery( + QueryBuilders.matchAllQuery(), fb) ) ) ) @@ -346,159 +342,26 @@ public class IssueBackendMediumTest { return issue; } - private void addIssueAuthorization(SearchClient searchClient, ComponentDto project, String user, String group) { - addIssueAuthorization(searchClient, null, project, user, group); + private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List users, List groups) { + return addIssueAuthorization(searchClient, project, users, groups, true); } - private void addIssueAuthorization(SearchClient searchClient, BulkRequestBuilder bulkRequestBuilder, ComponentDto project, String user, String group) { + private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List users, List groups, boolean refresh) { Map permissionSource = newHashMap(); permissionSource.put("_parent", project.key()); permissionSource.put("permission", "read"); permissionSource.put("project", project.key()); - if (user != null) { - permissionSource.put("user", user); - } - if (group != null) { - permissionSource.put("group", group); + if (users != null) { + permissionSource.put("users", users); } - - IndexRequestBuilder permissionRequestBuilder = searchClient.prepareIndex(IndexDefinition.ISSUES_PERMISSION.getIndexName(), IndexDefinition.ISSUES_PERMISSION.getIndexType()) - .setSource(permissionSource); - if (bulkRequestBuilder != null) { - bulkRequestBuilder.add(permissionRequestBuilder); - } else { - permissionRequestBuilder.setRefresh(true).get(); + if (groups != null) { + permissionSource.put("groups", groups); } - Map projectSource = newHashMap(); - projectSource.put("key", project.key()); - - IndexRequestBuilder projectRequestBuilder = searchClient.prepareIndex(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()) + return searchClient.prepareIndex(IndexDefinition.ISSUES_AUTHORIZATION.getIndexName(), IndexDefinition.ISSUES_AUTHORIZATION.getIndexType()) .setId(project.key()) - .setSource(projectSource); - if (bulkRequestBuilder != null) { - bulkRequestBuilder.add(projectRequestBuilder); - } else { - projectRequestBuilder.setRefresh(true).get(); - } + .setSource(permissionSource) + .setRefresh(refresh); } - private BaseIndex createIssueProjectIndex(final SearchClient searchClient) { - BaseIndex baseIndex = new BaseIndex( - IndexDefinition.createFor(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()), - null, searchClient) { - @Override - protected String getKeyValue(Serializable key) { - return null; - } - - @Override - protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException { - return ImmutableSettings.builder().build(); - } - - @Override - protected Map mapProperties() { - Map mapping = new HashMap(); - mapping.put("project", mapStringField()); - return mapping; - } - - protected Map mapStringField() { - Map mapping = new HashMap(); - mapping.put("type", "string"); - mapping.put("index", "analyzed"); - mapping.put("index_analyzer", "keyword"); - mapping.put("search_analyzer", "whitespace"); - return mapping; - } - - @Override - protected Map mapKey() { - return Collections.emptyMap(); - } - - @Override - public Object toDoc(Map fields) { - return null; - } - }; - baseIndex.start(); - return baseIndex; - } - - private BaseIndex createIssuePermissionIndex(final SearchClient searchClient) { - BaseIndex baseIndex = new BaseIndex( - IndexDefinition.createFor(IndexDefinition.ISSUES_PERMISSION.getIndexName(), IndexDefinition.ISSUES_PERMISSION.getIndexType()), - null, searchClient) { - @Override - protected String getKeyValue(Serializable key) { - return null; - } - - @Override - protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException { - return ImmutableSettings.builder().build(); - } - - @Override - protected Map mapDomain() { - Map mapping = new HashMap(); - mapping.put("dynamic", false); - mapping.put("_parent", mapParent()); - mapping.put("_routing", mapRouting()); - mapping.put("properties", mapProperties()); - return mapping; - } - - private Object mapParent() { - Map mapping = new HashMap(); - mapping.put("type", getParentType()); - return mapping; - } - - private String getParentType() { - return IndexDefinition.ISSUES_PROJECT.getIndexType(); - } - - private Map mapRouting() { - Map mapping = new HashMap(); - mapping.put("required", true); - mapping.put("path", "project"); - return mapping; - } - - @Override - protected Map mapProperties() { - Map mapping = new HashMap(); - mapping.put("permission", mapStringField()); - mapping.put("project", mapStringField()); - mapping.put("group", mapStringField()); - mapping.put("user", mapStringField()); - return mapping; - } - - protected Map mapStringField() { - Map mapping = new HashMap(); - mapping.put("type", "string"); - mapping.put("index", "analyzed"); - mapping.put("index_analyzer", "keyword"); - mapping.put("search_analyzer", "whitespace"); - return mapping; - } - - @Override - protected Map mapKey() { - Map mapping = new HashMap(); - return mapping; - } - - @Override - public Object toDoc(Map fields) { - return null; - } - }; - baseIndex.start(); - return baseIndex; - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java b/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java deleted file mode 100644 index b0415a60580..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.server.issue.db; - -import org.elasticsearch.action.bulk.BulkRequestBuilder; -import org.elasticsearch.action.index.IndexRequestBuilder; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.common.settings.ImmutableSettings; -import org.elasticsearch.index.query.BoolFilterBuilder; -import org.elasticsearch.index.query.FilterBuilders; -import org.elasticsearch.index.query.OrFilterBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonar.api.rule.RuleKey; -import org.sonar.core.component.ComponentDto; -import org.sonar.core.issue.db.IssueDto; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.rule.RuleDto; -import org.sonar.server.component.persistence.ComponentDao; -import org.sonar.server.db.DbClient; -import org.sonar.server.issue.index.IssueDoc; -import org.sonar.server.issue.index.IssueIndex; -import org.sonar.server.platform.Platform; -import org.sonar.server.rule.RuleTesting; -import org.sonar.server.rule.db.RuleDao; -import org.sonar.server.search.BaseIndex; -import org.sonar.server.search.IndexClient; -import org.sonar.server.search.IndexDefinition; -import org.sonar.server.search.SearchClient; -import org.sonar.server.tester.ServerTester; - -import java.io.IOException; -import java.io.Serializable; -import java.util.*; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; -import static org.fest.assertions.Assertions.assertThat; - -public class IssueBackendMediumTest2 { - - @ClassRule - public static ServerTester tester = new ServerTester(); - - DbClient dbClient; - IndexClient indexClient; - Platform platform; - DbSession dbSession; - - @Before - public void setUp() throws Exception { - dbClient = tester.get(DbClient.class); - indexClient = tester.get(IndexClient.class); - platform = tester.get(Platform.class); - dbSession = dbClient.openSession(false); - tester.clearDbAndIndexes(); - } - - @After - public void tearDown() throws Exception { - if (dbSession != null) { - dbSession.close(); - } - } - - @Test - public void insert_and_find_by_key() throws Exception { - RuleDto rule = RuleTesting.newXooX1(); - tester.get(RuleDao.class).insert(dbSession, rule); - - ComponentDto project = new ComponentDto() - .setId(1L) - .setKey("MyProject") - .setProjectId(1L); - tester.get(ComponentDao.class).insert(dbSession, project); - - ComponentDto resource = new ComponentDto() - .setProjectId(1L) - .setKey("MyComponent") - .setId(2L); - tester.get(ComponentDao.class).insert(dbSession, resource); - - IssueDto issue = new IssueDto() - .setIssueCreationDate(new Date()) - .setIssueUpdateDate(new Date()) - .setRule(rule) - .setRootComponent(project) - .setComponent(resource) - .setStatus("OPEN").setResolution("OPEN") - .setKee(UUID.randomUUID().toString()) - .setSeverity("MAJOR"); - dbClient.issueDao().insert(dbSession, issue); - - dbSession.commit(); - - // Check that Issue is in Index - assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(1); - - // should find by key - IssueDoc issueDoc = indexClient.get(IssueIndex.class).getByKey(issue.getKey()); - assertThat(issueDoc).isNotNull(); - - // Check all normalized fields - assertThat(issueDoc.actionPlanKey()).isEqualTo(issue.getActionPlanKey()); - assertThat(issueDoc.assignee()).isEqualTo(issue.getAssignee()); - assertThat(issueDoc.authorLogin()).isEqualTo(issue.getAuthorLogin()); - assertThat(issueDoc.closeDate()).isEqualTo(issue.getIssueCloseDate()); - assertThat(issueDoc.componentKey()).isEqualTo(issue.getComponentKey()); - assertThat(issueDoc.creationDate()).isEqualTo(issue.getCreatedAt()); - assertThat(issueDoc.effortToFix()).isEqualTo(issue.getEffortToFix()); - assertThat(issueDoc.resolution()).isEqualTo(issue.getResolution()); - assertThat(issueDoc.ruleKey()).isEqualTo(RuleKey.of(issue.getRuleRepo(), issue.getRule())); - assertThat(issueDoc.line()).isEqualTo(issue.getLine()); - assertThat(issueDoc.message()).isEqualTo(issue.getMessage()); - assertThat(issueDoc.reporter()).isEqualTo(issue.getReporter()); - assertThat(issueDoc.key()).isEqualTo(issue.getKey()); - assertThat(issueDoc.updateDate()).isEqualTo(issue.getIssueUpdateDate()); - assertThat(issueDoc.status()).isEqualTo(issue.getStatus()); - assertThat(issueDoc.severity()).isEqualTo(issue.getSeverity()); - - // assertThat(issueDoc.attributes()).isEqualTo(issue.getIssueAttributes()); - // assertThat(issueDoc.isNew()).isEqualTo(issue.isN()); - // assertThat(issueDoc.comments()).isEqualTo(issue.()); - } - - @Test - public void insert_and_find_after_date() throws Exception { - - RuleDto rule = RuleTesting.newXooX1(); - tester.get(RuleDao.class).insert(dbSession, rule); - - ComponentDto project = new ComponentDto() - .setId(1L) - .setKey("MyProject") - .setProjectId(1L); - tester.get(ComponentDao.class).insert(dbSession, project); - - ComponentDto resource = new ComponentDto() - .setId(2L) - .setKey("MyComponent") - .setProjectId(1L); - tester.get(ComponentDao.class).insert(dbSession, resource); - - IssueDto issue = new IssueDto().setId(1L) - .setRuleId(rule.getId()) - .setRootComponentId(project.getId()) - .setRootComponentKey_unit_test_only(project.key()) - .setComponentId(resource.getId()) - .setComponentKey_unit_test_only(resource.key()) - .setStatus("OPEN").setResolution("OPEN") - .setKee(UUID.randomUUID().toString()); - dbClient.issueDao().insert(dbSession, issue); - - dbSession.commit(); - assertThat(issue.getId()).isNotNull(); - - // Find Issues since forever - Date t0 = new Date(0); - assertThat(dbClient.issueDao().findAfterDate(dbSession, t0)).hasSize(1); - - // Should not find any new issues - Date t1 = new Date(); - assertThat(dbClient.issueDao().findAfterDate(dbSession, t1)).hasSize(0); - - // Should synchronise - tester.clearIndexes(); - assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(0); - tester.get(Platform.class).executeStartupTasks(); - assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(1); - } - - @Test - public void issue_authorization_on_group() throws Exception { - SearchClient searchClient = tester.get(SearchClient.class); - // createIssuePermissionIndex(searchClient); - createIssueAuthorizationIndex(searchClient); - - RuleDto rule = RuleTesting.newXooX1(); - tester.get(RuleDao.class).insert(dbSession, rule); - - ComponentDto project1 = addComponent(1L, 1L, "SonarQube :: Server"); - ComponentDto file1 = addComponent(2L, 1L, "IssueAction.java"); - addIssue(rule, project1, file1); - addIssueAuthorization(searchClient, project1, null, newArrayList("user")).get(); - - ComponentDto project2 = addComponent(10L, 10L, "SonarQube :: Core"); - ComponentDto file2 = addComponent(11L, 10L, "IssueDao.java"); - addIssue(rule, project2, file2); - addIssueAuthorization(searchClient, project2, null, newArrayList("reviewer")).get(); - - ComponentDto project3 = addComponent(20L, 20L, "SonarQube :: WS"); - ComponentDto file3 = addComponent(21L, 20L, "IssueWS.java"); - addIssue(rule, project3, file3); - addIssueAuthorization(searchClient, project3, null, newArrayList("user", "reviewer")).get(); - - dbSession.commit(); - - assertThat(searchIssueWithAuthorization(searchClient, "julien", "user", "reviewer").getHits().getTotalHits()).isEqualTo(3); // ok - assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(2); // ko -> 1 - assertThat(searchIssueWithAuthorization(searchClient, "julien", "reviewer").getHits().getTotalHits()).isEqualTo(2); // ko -> 1 - assertThat(searchIssueWithAuthorization(searchClient, "julien", "unknown").getHits().getTotalHits()).isEqualTo(0); - } - - @Test - public void issue_authorization_on_user() throws Exception { - SearchClient searchClient = tester.get(SearchClient.class); - // createIssuePermissionIndex(searchClient); - createIssueAuthorizationIndex(searchClient); - - RuleDto rule = RuleTesting.newXooX1(); - tester.get(RuleDao.class).insert(dbSession, rule); - - ComponentDto project = addComponent(1L, 1L, "SonarQube"); - ComponentDto file = addComponent(2L, 1L, "IssueAction.java"); - addIssue(rule, project, file); - addIssueAuthorization(searchClient, project, newArrayList("julien"), null).get(); - - dbSession.commit(); - - // The issue is visible for user julien - assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(1); - // The issue is not visible for user simon - assertThat(searchIssueWithAuthorization(searchClient, "simon", "user").getHits().getTotalHits()).isEqualTo(0); - } - - @Test - public void issue_authorization_with_a_lot_of_issues() throws Exception { - SearchClient searchClient = tester.get(SearchClient.class); - // createIssuePermissionIndex(searchClient); - createIssueAuthorizationIndex(searchClient); - - RuleDto rule = RuleTesting.newXooX1(); - tester.get(RuleDao.class).insert(dbSession, rule); - - int nbProject = 10; - int nbUser = 5; - int componentPerProject = 5; - - Long projectId = 1L; - Long componentId = 1L; - - List users = newArrayList(); - for (int u = 0; u < nbUser; u++) { - users.add("user-" + u); - } - - BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient).setRefresh(true); - for (int p = 0; p < nbProject; p++) { - ComponentDto project = addComponent(projectId, projectId, "Project-" + projectId.toString()); - - List groups = newArrayList(); - groups.add("anyone"); - if (p % 2 == 0) { - groups.add("user"); - } - - bulkRequestBuilder.add(addIssueAuthorization(searchClient, project, users, groups, false)); - for (int c = 0; c < componentPerProject; c++) { - ComponentDto file = addComponent(componentId, projectId, "Component-" + componentId.toString()); - addIssue(rule, project, file); - componentId++; - } - projectId++; - - if (bulkRequestBuilder.numberOfActions() == nbProject) { - bulkRequestBuilder.get(); - dbSession.commit(); - } - } - bulkRequestBuilder.setRefresh(true).get(); - dbSession.commit(); - - // All issues are visible by group anyone - assertThat(searchIssueWithAuthorization(searchClient, "", "anyone").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject); - // Half of issues are visible by group user - assertThat(searchIssueWithAuthorization(searchClient, "", "user").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject / 2); - // user-1 should see all issues - assertThat(searchIssueWithAuthorization(searchClient, "user-1", "").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject); - -// Thread.sleep(Integer.MAX_VALUE); - } - - private SearchResponse searchIssueWithAuthorization(SearchClient searchClient, String user, String... groups) { - BoolFilterBuilder fb = FilterBuilders.boolFilter(); - - OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("users", user)); - for (String group : groups) { - or.add(FilterBuilders.termFilter("groups", group)); - } - fb.must(FilterBuilders.termFilter("permission", "read"), or).cache(true); - // fb.must(FilterBuilders.termFilter("permission", "read"), or); - - SearchRequestBuilder request = searchClient.prepareSearch(IndexDefinition.ISSUES.getIndexName()).setTypes(IndexDefinition.ISSUES.getIndexType()) - .setQuery( - QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), - FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_PROJECT.getIndexType(), - QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), fb) - ) - ) - ) - .setSize(Integer.MAX_VALUE); - - return searchClient.execute(request); - } - - private ComponentDto addComponent(Long id, Long projectId, String key) { - ComponentDto project = new ComponentDto() - .setId(id) - .setProjectId(projectId) - .setKey(key); - tester.get(ComponentDao.class).insert(dbSession, project); - return project; - } - - private IssueDto addIssue(RuleDto rule, ComponentDto project, ComponentDto file) { - IssueDto issue = new IssueDto() - .setRuleId(rule.getId()) - .setRootComponentKey_unit_test_only(project.key()) - .setRootComponentId(project.getId()) - .setComponentKey_unit_test_only(file.key()) - .setComponentId(file.getId()) - .setStatus("OPEN").setResolution("OPEN") - .setKee(UUID.randomUUID().toString()); - dbClient.issueDao().insert(dbSession, issue); - return issue; - } - - private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List users, List groups) { - return addIssueAuthorization(searchClient, project, users, groups, true); - } - - private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List users, List groups, boolean refresh) { - Map permissionSource = newHashMap(); - permissionSource.put("_parent", project.key()); - permissionSource.put("permission", "read"); - permissionSource.put("project", project.key()); - if (users != null) { - permissionSource.put("users", users); - } - if (groups != null) { - permissionSource.put("groups", groups); - } - - return searchClient.prepareIndex(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()) - .setId(project.key()) - .setSource(permissionSource) - .setRefresh(refresh); - } - - private BaseIndex createIssueAuthorizationIndex(final SearchClient searchClient) { - BaseIndex baseIndex = new BaseIndex( - IndexDefinition.createFor(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()), - null, searchClient) { - @Override - protected String getKeyValue(Serializable key) { - return null; - } - - @Override - protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException { - return ImmutableSettings.builder().build(); - } - - @Override - protected Map mapProperties() { - Map mapping = new HashMap(); - mapping.put("project", mapStringField()); - mapping.put("permission", mapStringField()); - mapping.put("groups", mapStringField()); - mapping.put("users", mapStringField()); - return mapping; - } - - protected Map mapStringField() { - Map mapping = new HashMap(); - mapping.put("type", "string"); - mapping.put("index", "analyzed"); - mapping.put("index_analyzer", "keyword"); - mapping.put("search_analyzer", "whitespace"); - return mapping; - } - - @Override - protected Map mapKey() { - return Collections.emptyMap(); - } - - @Override - public Object toDoc(Map fields) { - return null; - } - }; - baseIndex.start(); - return baseIndex; - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java new file mode 100644 index 00000000000..d66f0c9d231 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java @@ -0,0 +1,75 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.issue.db; + +import org.sonar.core.persistence.Dto; + +import java.io.Serializable; +import java.util.List; + +public final class IssueAuthorizationDto extends Dto implements Serializable { + + private String project; + private String permission; + private List groups; + private List users; + + @Override + public String getKey() { + return null; + } + + public String getProject() { + return project; + } + + public IssueAuthorizationDto setProject(String project) { + this.project = project; + return this; + } + + public String getPermission() { + return permission; + } + + public IssueAuthorizationDto setPermission(String permission) { + this.permission = permission; + return this; + } + + public List getGroups() { + return groups; + } + + public IssueAuthorizationDto setGroups(List groups) { + this.groups = groups; + return this; + } + + public List getUsers() { + return users; + } + + public IssueAuthorizationDto setUsers(List users) { + this.users = users; + return this; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java new file mode 100644 index 00000000000..d327f7f938d --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java @@ -0,0 +1,27 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.issue.db; + +public interface IssueAuthorizationMapper { + + IssueAuthorizationDto selectByKey(String key); + +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java index 3e9c9d2f5f4..58d40c93502 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java @@ -137,6 +137,7 @@ public class MyBatis implements BatchComponent, ServerComponent { loadAlias(conf, "Measure", MeasureDto.class); loadAlias(conf, "Metric", MetricDto.class); loadAlias(conf, "Issue", IssueDto.class); + loadAlias(conf, "IssueAuthorization", IssueAuthorizationDto.class); loadAlias(conf, "IssueChange", IssueChangeDto.class); loadAlias(conf, "IssueFilter", IssueFilterDto.class); loadAlias(conf, "IssueFilterFavourite", IssueFilterFavouriteDto.class); @@ -163,7 +164,7 @@ public class MyBatis implements BatchComponent, ServerComponent { loadMapper(conf, "org.sonar.core.permission.PermissionMapper"); Class[] mappers = {ActivityMapper.class, ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class, DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, - IssueMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class, + IssueMapper.class, IssueAuthorizationMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class, LoadedTemplateMapper.class, MeasureFilterMapper.class, Migration44Mapper.class, PermissionTemplateMapper.class, PropertiesMapper.class, PurgeMapper.class, ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceSnapshotMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml new file mode 100644 index 00000000000..59dd1496014 --- /dev/null +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + -- 2.39.5