From bbf5c35f095f2136e0f768bcc1f1b4eb8e856248 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 13 Feb 2017 23:23:26 +0100 Subject: [PATCH] SONAR-8647 Add filter on field organizationUuid in index projectmeasures --- .../ws/ProjectMeasuresQueryFactory.java | 15 ++++----- .../component/ws/SearchProjectsAction.java | 33 ++++--------------- .../measure/index/ProjectMeasuresIndex.java | 16 +++++---- .../measure/index/ProjectMeasuresQuery.java | 28 ++++++++-------- .../ws/ProjectMeasuresQueryFactoryTest.java | 16 ++++----- .../index/ProjectMeasuresIndexTest.java | 25 ++++++++++++-- .../index/ProjectMeasuresQueryTest.java | 18 ++++------ 7 files changed, 75 insertions(+), 76 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java index 5892a85cc6b..54b610e6453 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java @@ -22,6 +22,7 @@ package org.sonar.server.component.ws; import com.google.common.base.Splitter; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,12 +31,12 @@ import javax.annotation.Nullable; import org.sonar.api.measures.Metric.Level; import org.sonar.core.util.stream.Collectors; import org.sonar.server.measure.index.ProjectMeasuresQuery; +import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; +import org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Locale.ENGLISH; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; class ProjectMeasuresQueryFactory { private static final Splitter CRITERIA_SPLITTER = Splitter.on(Pattern.compile("and", Pattern.CASE_INSENSITIVE)); @@ -58,12 +59,10 @@ class ProjectMeasuresQueryFactory { } static ProjectMeasuresQuery newProjectMeasuresQuery(List criteria, @Nullable Set projectUuids) { - ProjectMeasuresQuery res = new ProjectMeasuresQuery(); - if (projectUuids != null) { - res.setProjectUuids(projectUuids); - } - criteria.forEach(criterion -> processCriterion(criterion, res)); - return res; + ProjectMeasuresQuery query = new ProjectMeasuresQuery(); + Optional.ofNullable(projectUuids).ifPresent(query::setProjectUuids); + criteria.forEach(criterion -> processCriterion(criterion, query)); + return query; } private static void processCriterion(String rawCriterion, ProjectMeasuresQuery query) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java index 30c1afd68cb..123c8d0e922 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java @@ -26,13 +26,13 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collector; import java.util.stream.Stream; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -171,9 +171,13 @@ public class SearchProjectsAction implements ComponentsWsAction { List criteria = toCriteria(firstNonNull(request.getFilter(), "")); List favoriteProjects = searchFavoriteProjects(dbSession); - Set projectUuids = buildFilterOnProjectUuids(dbSession, criteria, favoriteProjects, organization); + Set projectUuids = buildFilterOnFavoriteProjectUuids(criteria, favoriteProjects); ProjectMeasuresQuery query = newProjectMeasuresQuery(criteria, projectUuids); + Optional.ofNullable(organization) + .map(OrganizationDto::getUuid) + .ifPresent(query::setOrganizationUuid); + queryValidator.validate(dbSession, query); SearchIdResult esResults = index.search(query, new SearchOptions() @@ -186,37 +190,14 @@ public class SearchProjectsAction implements ComponentsWsAction { return new SearchResults(projects, favoriteProjects.stream().map(ComponentDto::uuid).collect(toSet()), esResults); } - /** - * Builds the set of project uuid on which the query on index measure should be filtering. - *
    - *
  • if neither isFavourite criterion nor an organization is specified, there is not filtering on projects at all
  • - *
  • if isFavourite criterion and an organization are specified, filtering is done on favourite projects of - * the user which belong to the specified organization
  • - *
  • if only isFavourite criterion is specified, filtering is done on favourite projects of the user
  • - *
  • if only an organization is specified, filtering is done on the projects of this organization
  • - *
- */ @CheckForNull - private Set buildFilterOnProjectUuids(DbSession dbSession, List criteria, List favoriteProjects, @Nullable OrganizationDto organization) { + private Set buildFilterOnFavoriteProjectUuids(List criteria, List favoriteProjects) { boolean hasIsFavouriteCriterion = hasIsFavouriteCriterion(criteria); - if (hasIsFavouriteCriterion && organization != null) { - return favoriteProjects.stream() - .filter(project -> project.getOrganizationUuid().equals(organization.getUuid())) - .map(ComponentDto::uuid) - .collect(toSet()); - } if (hasIsFavouriteCriterion) { return favoriteProjects.stream() .map(ComponentDto::uuid) .collect(toSet()); } - if (organization != null) { - return dbClient.componentDao().selectAllRootsByOrganization(dbSession, organization.getUuid()) - .stream() - .filter(componentDto -> Qualifiers.PROJECT.equals(componentDto.qualifier())) - .map(ComponentDto::uuid) - .collect(toSet()); - } return null; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java index df38b190e6d..dd481748d95 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java @@ -61,6 +61,7 @@ import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIEL import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_NAME; +import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_ORGANIZATION_UUID; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURE; @@ -209,12 +210,15 @@ public class ProjectMeasuresIndex extends BaseIndex { filters.put(entry.getKey(), metricFilters); }); - if (query.hasQualityGateStatus()) { - filters.put(ALERT_STATUS_KEY, termQuery(FIELD_QUALITY_GATE, query.getQualityGateStatus().name())); - } - if (query.doesFilterOnProjectUuids()) { - filters.put("ids", termsQuery("_id", query.getProjectUuids())); - } + + query.getQualityGateStatus() + .ifPresent(qualityGateStatus -> filters.put(ALERT_STATUS_KEY, termQuery(FIELD_QUALITY_GATE, qualityGateStatus.name()))); + + query.getProjectUuids() + .ifPresent(projectUuids -> filters.put("ids", termsQuery("_id", projectUuids))); + + query.getOrganizationUuid() + .ifPresent(organizationUuid -> filters.put(FIELD_ORGANIZATION_UUID, termQuery(FIELD_ORGANIZATION_UUID, organizationUuid))); return filters; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java index ce9198927a2..a70e8ac945d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java @@ -21,10 +21,11 @@ package org.sonar.server.measure.index; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; import org.sonar.api.measures.Metric; -import static com.google.common.base.Preconditions.checkState; import static java.lang.String.format; import static java.util.Arrays.stream; import static java.util.Objects.requireNonNull; @@ -32,6 +33,7 @@ import static java.util.Objects.requireNonNull; public class ProjectMeasuresQuery { private List metricCriteria = new ArrayList<>(); private Metric.Level qualityGateStatus; + private String organizationUuid = null; private Set projectUuids = null; public ProjectMeasuresQuery addMetricCriterion(MetricCriterion metricCriterion) { @@ -48,26 +50,26 @@ public class ProjectMeasuresQuery { return this; } - public boolean hasQualityGateStatus() { - return qualityGateStatus != null; + public Optional getQualityGateStatus() { + return Optional.ofNullable(qualityGateStatus); } - public Metric.Level getQualityGateStatus() { - checkState(qualityGateStatus != null); - return qualityGateStatus; + public ProjectMeasuresQuery setOrganizationUuid(@Nullable String organizationUuid) { + this.organizationUuid = organizationUuid; + return this; } - public ProjectMeasuresQuery setProjectUuids(Set projectUuids) { - this.projectUuids = requireNonNull(projectUuids); - return this; + public Optional getOrganizationUuid() { + return Optional.ofNullable(organizationUuid); } - public boolean doesFilterOnProjectUuids() { - return projectUuids != null; + public ProjectMeasuresQuery setProjectUuids(@Nullable Set projectUuids) { + this.projectUuids = projectUuids; + return this; } - public Set getProjectUuids() { - return requireNonNull(projectUuids); + public Optional> getProjectUuids() { + return Optional.ofNullable(projectUuids); } public enum Operator { diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java index 37e08431d25..80679803f8e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java @@ -24,6 +24,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.server.measure.index.ProjectMeasuresQuery; +import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; +import org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; import org.sonar.server.tester.UserSessionRule; import static java.util.Collections.emptyList; @@ -33,8 +35,6 @@ import static org.assertj.core.api.Assertions.tuple; import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery; import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.toCriteria; import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.OK; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; public class ProjectMeasuresQueryFactoryTest { @@ -103,42 +103,42 @@ public class ProjectMeasuresQueryFactoryTest { public void create_query_on_quality_gate() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("alert_status = OK"), emptySet()); - assertThat(query.getQualityGateStatus().name()).isEqualTo(OK.name()); + assertThat(query.getQualityGateStatus().get().name()).isEqualTo(OK.name()); } @Test public void do_not_filter_on_projectUuids_if_criteria_non_empty_and_projectUuid_is_null() { ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc = 10"), null); - assertThat(query.doesFilterOnProjectUuids()).isFalse(); + assertThat(query.getProjectUuids()).isEmpty(); } @Test public void filter_on_projectUuids_if_projectUuid_is_empty_and_criteria_non_empty() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10"), emptySet()); - assertThat(query.doesFilterOnProjectUuids()).isTrue(); + assertThat(query.getProjectUuids()).isPresent(); } @Test public void filter_on_projectUuids_if_projectUuid_is_non_empty_and_criteria_non_empty() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10"), Collections.singleton("foo")); - assertThat(query.doesFilterOnProjectUuids()).isTrue(); + assertThat(query.getProjectUuids()).isPresent(); } @Test public void filter_on_projectUuids_if_projectUuid_is_empty_and_criteria_is_empty() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(emptyList(), emptySet()); - assertThat(query.doesFilterOnProjectUuids()).isTrue(); + assertThat(query.getProjectUuids()).isPresent(); } @Test public void filter_on_projectUuids_if_projectUuid_is_non_empty_and_criteria_empty() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(emptyList(), Collections.singleton("foo")); - assertThat(query.doesFilterOnProjectUuids()).isTrue(); + assertThat(query.getProjectUuids()).isPresent(); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java index 1cf57c0aee6..ecb6a730b17 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java @@ -218,6 +218,24 @@ public class ProjectMeasuresIndexTest { assertResults(query, PROJECT1, PROJECT3); } + @Test + public void filter_on_organization() { + OrganizationDto org1 = OrganizationTesting.newOrganizationDto(); + OrganizationDto org2 = OrganizationTesting.newOrganizationDto(); + ComponentDto projectInOrg1 = newProjectDto(org1); + ComponentDto projectInOrg2 = newProjectDto(org2); + index(newDoc(projectInOrg1), newDoc(projectInOrg2)); + + ProjectMeasuresQuery query1 = new ProjectMeasuresQuery().setOrganizationUuid(org1.getUuid()); + assertResults(query1, projectInOrg1); + + ProjectMeasuresQuery query2 = new ProjectMeasuresQuery().setOrganizationUuid(org2.getUuid()); + assertResults(query2, projectInOrg2); + + ProjectMeasuresQuery query3 = new ProjectMeasuresQuery().setOrganizationUuid("another_org"); + assertNoResults(query3); + } + @Test public void return_only_projects_authorized_for_user() throws Exception { indexForUser(USER1, newDoc(PROJECT1), newDoc(PROJECT2)); @@ -878,9 +896,10 @@ public class ProjectMeasuresIndexTest { private static ProjectMeasuresDoc newDoc(ComponentDto project) { return new ProjectMeasuresDoc() - .setId(project.uuid()) - .setKey(project.key()) - .setName(project.name()); + .setOrganizationUuid(project.getOrganizationUuid()) + .setId(project.uuid()) + .setKey(project.key()) + .setName(project.name()); } private static ProjectMeasuresDoc newDoc() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java index 7fd086a95f5..a549026fc58 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java @@ -23,12 +23,11 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.measures.Metric.Level; -import org.sonar.server.measure.index.ProjectMeasuresQuery; +import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; import static org.sonar.api.measures.Metric.Level.OK; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.EQ; public class ProjectMeasuresQueryTest { @@ -36,12 +35,13 @@ public class ProjectMeasuresQueryTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - ProjectMeasuresQuery underTest = new ProjectMeasuresQuery(); + private ProjectMeasuresQuery underTest = new ProjectMeasuresQuery(); @Test public void empty_query() throws Exception { assertThat(underTest.getMetricCriteria()).isEmpty(); - assertThat(underTest.hasQualityGateStatus()).isFalse(); + assertThat(underTest.getQualityGateStatus()).isEmpty(); + assertThat(underTest.getOrganizationUuid()).isEmpty(); } @Test @@ -57,13 +57,7 @@ public class ProjectMeasuresQueryTest { public void set_quality_gate_status() throws Exception { underTest.setQualityGateStatus(OK); - assertThat(underTest.getQualityGateStatus()).isEqualTo(Level.OK); - } - - @Test - public void fail_to_get_quality_gate_status_if_no_set() throws Exception { - expectedException.expect(IllegalStateException.class); - underTest.getQualityGateStatus(); + assertThat(underTest.getQualityGateStatus().get()).isEqualTo(Level.OK); } @Test -- 2.39.5