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;
import org.sonar.server.issue.notification.NewIssuesNotificationFactory;
import org.sonar.server.issue.workflow.FunctionExecutor;
import org.sonar.server.issue.workflow.IssueWorkflow;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.metric.CoreCustomMetrics;
import org.sonar.server.metric.DefaultMetricFinder;
import org.sonar.server.notification.DefaultNotificationManager;
import org.sonar.db.DbSession;
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.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.test.index.TestIndexer;
@ServerSide
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.user.UserSession;
import static com.google.common.collect.Lists.newArrayList;
+++ /dev/null
-/*
- * 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.ImmutableMap;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.core.util.stream.Collectors;
-import org.sonar.server.es.BaseDoc;
-
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
-
-public class ProjectMeasuresDoc extends BaseDoc {
-
- public ProjectMeasuresDoc() {
- super(new HashMap<>(4));
- }
-
- @Override
- public String getId() {
- return getField("_id");
- }
-
- @Override
- public String getRouting() {
- return getId();
- }
-
- @Override
- public String getParent() {
- return getId();
- }
-
- public ProjectMeasuresDoc setId(String s) {
- setField("_id", s);
- return this;
- }
-
- public String getKey() {
- return getField(ProjectMeasuresIndexDefinition.FIELD_KEY);
- }
-
- public ProjectMeasuresDoc setKey(String s) {
- setField(ProjectMeasuresIndexDefinition.FIELD_KEY, s);
- return this;
- }
-
- public String getName() {
- return getField(ProjectMeasuresIndexDefinition.FIELD_NAME);
- }
-
- public ProjectMeasuresDoc setName(String s) {
- setField(ProjectMeasuresIndexDefinition.FIELD_NAME, s);
- return this;
- }
-
- @CheckForNull
- public Date getAnalysedAt() {
- return getNullableField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT);
- }
-
- public ProjectMeasuresDoc setAnalysedAt(@Nullable Date d) {
- setField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, d);
- return this;
- }
-
- public Collection<Map<String, Object>> getMeasures() {
- return getField(FIELD_MEASURES);
- }
-
- public ProjectMeasuresDoc setMeasures(Collection<Map<String, Object>> measures) {
- setField(FIELD_MEASURES, measures);
- return this;
- }
-
- public ProjectMeasuresDoc setMeasuresFromMap(Map<String, Double> measures) {
- setMeasures(
- measures.entrySet().stream()
- .map(entry -> ImmutableMap.<String, Object>of(
- ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY, entry.getKey(),
- ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE, entry.getValue()))
- .collect(Collectors.toList()));
- return this;
- }
-
- @CheckForNull
- public String getQualityGate() {
- return getField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE);
- }
-
- public ProjectMeasuresDoc setQualityGate(@Nullable String s) {
- setField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE, s);
- return this;
- }
-}
+++ /dev/null
-/*
- * 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.ArrayListMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.IntStream;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.aggregations.AggregationBuilder;
-import org.elasticsearch.search.aggregations.AggregationBuilders;
-import org.elasticsearch.search.aggregations.bucket.range.RangeBuilder;
-import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.api.measures.Metric;
-import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
-import org.sonar.server.es.BaseIndex;
-import org.sonar.server.es.EsClient;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.es.StickyFacetBuilder;
-import org.sonar.server.user.UserSession;
-
-import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
-import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
-import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
-import static org.elasticsearch.search.aggregations.AggregationBuilders.filters;
-import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
-import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
-import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY_KEY;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
-import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_GROUPS;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_USERS;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_NAME;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndex extends BaseIndex {
-
- public static final List<String> SUPPORTED_FACETS = ImmutableList.of(
- NCLOC_KEY,
- DUPLICATED_LINES_DENSITY_KEY,
- COVERAGE_KEY,
- SQALE_RATING_KEY,
- RELIABILITY_RATING_KEY,
- SECURITY_RATING_KEY,
- ALERT_STATUS_KEY);
-
- private static final String FIELD_KEY = FIELD_MEASURES + "." + FIELD_MEASURES_KEY;
- private static final String FIELD_VALUE = FIELD_MEASURES + "." + FIELD_MEASURES_VALUE;
-
- private final UserSession userSession;
-
- public ProjectMeasuresIndex(EsClient client, UserSession userSession) {
- super(client);
- this.userSession = userSession;
- }
-
- public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
- SearchRequestBuilder requestBuilder = getClient()
- .prepareSearch(INDEX_PROJECT_MEASURES)
- .setTypes(TYPE_PROJECT_MEASURES)
- .setFetchSource(false)
- .setFrom(searchOptions.getOffset())
- .setSize(searchOptions.getLimit())
- .addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
-
- BoolQueryBuilder esFilter = boolQuery();
- Map<String, QueryBuilder> filters = createFilters(query);
- filters.values().forEach(esFilter::must);
- requestBuilder.setQuery(esFilter);
-
- addFacets(requestBuilder, searchOptions, filters);
- return new SearchIdResult<>(requestBuilder.get(), id -> id);
- }
-
- private static void addFacets(SearchRequestBuilder esSearch, SearchOptions options, Map<String, QueryBuilder> filters) {
- if (!options.getFacets().isEmpty()) {
- if (options.getFacets().contains(NCLOC_KEY)) {
- addRangeFacet(esSearch, NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d), filters);
- }
- if (options.getFacets().contains(DUPLICATED_LINES_DENSITY_KEY)) {
- addRangeFacet(esSearch, DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d), filters);
- }
- if (options.getFacets().contains(COVERAGE_KEY)) {
- addRangeFacet(esSearch, COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d), filters);
- }
- if (options.getFacets().contains(SQALE_RATING_KEY)) {
- addRatingFacet(esSearch, SQALE_RATING_KEY, filters);
- }
- if (options.getFacets().contains(RELIABILITY_RATING_KEY)) {
- addRatingFacet(esSearch, RELIABILITY_RATING_KEY, filters);
- }
- if (options.getFacets().contains(SECURITY_RATING_KEY)) {
- addRatingFacet(esSearch, SECURITY_RATING_KEY, filters);
- }
- if (options.getFacets().contains(ALERT_STATUS_KEY)) {
- esSearch.addAggregation(createStickyFacet(ALERT_STATUS_KEY, filters, createQualityGateFacet()));
- }
- }
- }
-
- private static void addRangeFacet(SearchRequestBuilder esSearch, String metricKey, List<Double> thresholds, Map<String, QueryBuilder> filters) {
- esSearch.addAggregation(createStickyFacet(metricKey, filters, createRangeFacet(metricKey, thresholds)));
- }
-
- private static void addRatingFacet(SearchRequestBuilder esSearch, String metricKey, Map<String, QueryBuilder> filters) {
- esSearch.addAggregation(createStickyFacet(metricKey, filters, createRatingFacet(metricKey)));
- }
-
- private static AggregationBuilder createStickyFacet(String metricKey, Map<String, QueryBuilder> filters, AggregationBuilder aggregationBuilder) {
- StickyFacetBuilder facetBuilder = new StickyFacetBuilder(matchAllQuery(), filters);
- BoolQueryBuilder facetFilter = facetBuilder.getStickyFacetFilter(metricKey);
- return AggregationBuilders
- .global(metricKey)
- .subAggregation(AggregationBuilders.filter("facet_filter_" + metricKey)
- .filter(facetFilter)
- .subAggregation(aggregationBuilder));
- }
-
- private static AggregationBuilder createRangeFacet(String metricKey, List<Double> thresholds) {
- RangeBuilder rangeAgg = AggregationBuilders.range(metricKey)
- .field(FIELD_VALUE);
- final int lastIndex = thresholds.size() - 1;
- IntStream.range(0, thresholds.size())
- .forEach(i -> {
- if (i == 0) {
- rangeAgg.addUnboundedTo(thresholds.get(0));
- rangeAgg.addRange(thresholds.get(0), thresholds.get(1));
- } else if (i == lastIndex) {
- rangeAgg.addUnboundedFrom(thresholds.get(lastIndex));
- } else {
- rangeAgg.addRange(thresholds.get(i), thresholds.get(i + 1));
- }
- });
-
- return AggregationBuilders.nested("nested_" + metricKey)
- .path(FIELD_MEASURES)
- .subAggregation(
- AggregationBuilders.filter("filter_" + metricKey)
- .filter(termsQuery(FIELD_KEY, metricKey))
- .subAggregation(rangeAgg));
- }
-
- private static AggregationBuilder createRatingFacet(String metricKey) {
- return AggregationBuilders.nested("nested_" + metricKey)
- .path(FIELD_MEASURES)
- .subAggregation(
- AggregationBuilders.filter("filter_" + metricKey)
- .filter(termsQuery(FIELD_KEY, metricKey))
- .subAggregation(filters(metricKey)
- .filter("1", termQuery(FIELD_VALUE, 1d))
- .filter("2", termQuery(FIELD_VALUE, 2d))
- .filter("3", termQuery(FIELD_VALUE, 3d))
- .filter("4", termQuery(FIELD_VALUE, 4d))
- .filter("5", termQuery(FIELD_VALUE, 5d))));
- }
-
- private static AggregationBuilder createQualityGateFacet() {
- return AggregationBuilders.filters(ALERT_STATUS_KEY)
- .filter(Metric.Level.ERROR.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.ERROR.name()))
- .filter(Metric.Level.WARN.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.WARN.name()))
- .filter(Metric.Level.OK.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.OK.name()));
- }
-
- private Map<String, QueryBuilder> createFilters(ProjectMeasuresQuery query) {
- Map<String, QueryBuilder> filters = new HashMap<>();
- filters.put("__authorization", createAuthorizationFilter());
- Multimap<String, MetricCriterion> metricCriterionMultimap = ArrayListMultimap.create();
- query.getMetricCriteria().forEach(metricCriterion -> metricCriterionMultimap.put(metricCriterion.getMetricKey(), metricCriterion));
- metricCriterionMultimap.asMap().entrySet().forEach(entry -> {
- BoolQueryBuilder metricFilters = boolQuery();
- entry.getValue()
- .stream()
- .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery()
- .filter(termQuery(FIELD_KEY, criterion.getMetricKey()))
- .filter(toValueQuery(criterion))))
- .forEach(metricFilters::must);
- 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()));
- }
- return filters;
- }
-
- private static QueryBuilder toValueQuery(MetricCriterion criterion) {
- String fieldName = FIELD_VALUE;
-
- switch (criterion.getOperator()) {
- case GT:
- return rangeQuery(fieldName).gt(criterion.getValue());
- case GTE:
- return rangeQuery(fieldName).gte(criterion.getValue());
- case LT:
- return rangeQuery(fieldName).lt(criterion.getValue());
- case LTE:
- return rangeQuery(fieldName).lte(criterion.getValue());
- case EQ:
- return termQuery(fieldName, criterion.getValue());
- default:
- throw new IllegalStateException("Metric criteria non supported: " + criterion.getOperator().name());
- }
- }
-
- private QueryBuilder createAuthorizationFilter() {
- Integer userLogin = userSession.getUserId();
- Set<String> userGroupNames = userSession.getUserGroups();
- BoolQueryBuilder groupsAndUser = boolQuery();
- if (userLogin != null) {
- groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_USERS, userLogin.longValue()));
- }
- for (String group : userGroupNames) {
- groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_GROUPS, group));
- }
- return QueryBuilders.hasParentQuery(TYPE_AUTHORIZATION,
- QueryBuilders.boolQuery().must(matchAllQuery()).filter(groupsAndUser));
- }
-}
+++ /dev/null
-/*
- * 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.ImmutableMap;
-import org.sonar.api.config.Settings;
-import org.sonar.server.es.IndexDefinition;
-import org.sonar.server.es.NewIndex;
-
-public class ProjectMeasuresIndexDefinition implements IndexDefinition {
-
- public static final String INDEX_PROJECT_MEASURES = "projectmeasures";
-
- public static final String TYPE_PROJECT_MEASURES = "projectmeasures";
- public static final String FIELD_KEY = "key";
- public static final String FIELD_NAME = "name";
- public static final String FIELD_ANALYSED_AT = "analysedAt";
- public static final String FIELD_QUALITY_GATE = "qualityGate";
- public static final String FIELD_MEASURES = "measures";
- public static final String FIELD_MEASURES_KEY = "key";
- public static final String FIELD_MEASURES_VALUE = "value";
-
- public static final String TYPE_AUTHORIZATION = "authorization";
- public static final String FIELD_AUTHORIZATION_PROJECT_UUID = "project";
- public static final String FIELD_AUTHORIZATION_GROUPS = "groupNames";
- public static final String FIELD_AUTHORIZATION_USERS = "users";
- public static final String FIELD_AUTHORIZATION_UPDATED_AT = "updatedAt";
-
- private final Settings settings;
-
- public ProjectMeasuresIndexDefinition(Settings settings) {
- this.settings = settings;
- }
-
- @Override
- public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_PROJECT_MEASURES);
- index.refreshHandledByIndexer();
- index.configureShards(settings, 5);
-
- // type "projectmeasures"
- NewIndex.NewIndexType mapping = index.createType(TYPE_PROJECT_MEASURES);
- mapping.setAttribute("_parent", ImmutableMap.of("type", TYPE_AUTHORIZATION));
- mapping.setAttribute("_routing", ImmutableMap.of("required", "true"));
- mapping.stringFieldBuilder(FIELD_KEY).disableNorms().build();
- mapping.stringFieldBuilder(FIELD_NAME).enableSorting().build();
- mapping.stringFieldBuilder(FIELD_QUALITY_GATE).build();
- mapping.createDateTimeField(FIELD_ANALYSED_AT);
- mapping.nestedFieldBuilder(FIELD_MEASURES)
- .addStringFied(FIELD_MEASURES_KEY)
- .addDoubleField(FIELD_MEASURES_VALUE)
- .build();
-
- // do not store document but only indexation of information
- mapping.setEnableSource(false);
-
- // type "authorization"
- NewIndex.NewIndexType authorizationMapping = index.createType(TYPE_AUTHORIZATION);
- authorizationMapping.setAttribute("_routing", ImmutableMap.of("required", "true"));
- authorizationMapping.createDateTimeField(FIELD_AUTHORIZATION_UPDATED_AT);
- authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_PROJECT_UUID).disableNorms().build();
- authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_GROUPS).disableNorms().build();
- authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_USERS).disableNorms().build();
- authorizationMapping.setEnableSource(false);
- }
-}
+++ /dev/null
-/*
- * 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 java.util.Date;
-import java.util.Iterator;
-import javax.annotation.Nullable;
-import org.elasticsearch.action.index.IndexRequest;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.measure.ProjectMeasuresIndexerIterator;
-import org.sonar.db.measure.ProjectMeasuresIndexerIterator.ProjectMeasures;
-import org.sonar.server.es.BaseIndexer;
-import org.sonar.server.es.BulkIndexer;
-import org.sonar.server.es.EsClient;
-
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexer extends BaseIndexer {
-
- private final DbClient dbClient;
-
- public ProjectMeasuresIndexer(System2 system2, DbClient dbClient, EsClient esClient) {
- super(system2, esClient, 300, INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, FIELD_ANALYSED_AT);
- this.dbClient = dbClient;
- }
-
- @Override
- protected long doIndex(long lastUpdatedAt) {
- return doIndex(createBulkIndexer(false), lastUpdatedAt, null);
- }
-
- public void index(String projectUuid) {
- doIndex(createBulkIndexer(false), 0L, projectUuid);
- }
-
- public void deleteProject(String uuid) {
- esClient
- .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, uuid)
- .setRouting(uuid)
- .setRefresh(true)
- .get();
- esClient
- .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION, uuid)
- .setRouting(uuid)
- .setRefresh(true)
- .get();
- }
-
- private long doIndex(BulkIndexer bulk, long lastUpdatedAt, @Nullable String projectUuid) {
- try (DbSession dbSession = dbClient.openSession(false);
- ProjectMeasuresIndexerIterator rowIt = ProjectMeasuresIndexerIterator.create(dbSession, lastUpdatedAt, projectUuid)) {
- return doIndex(bulk, rowIt);
- }
- }
-
- private static long doIndex(BulkIndexer bulk, Iterator<ProjectMeasures> docs) {
- bulk.start();
- long maxDate = 0L;
- while (docs.hasNext()) {
- ProjectMeasures doc = docs.next();
- bulk.add(newIndexRequest(toProjectMeasuresDoc(doc)));
-
- Long analysisDate = doc.getProject().getAnalysisDate();
- // it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
- maxDate = Math.max(maxDate, analysisDate == null ? 0L : analysisDate);
- }
- bulk.stop();
- return maxDate;
- }
-
- private BulkIndexer createBulkIndexer(boolean large) {
- BulkIndexer bulk = new BulkIndexer(esClient, INDEX_PROJECT_MEASURES);
- bulk.setLarge(large);
- return bulk;
- }
-
- private static IndexRequest newIndexRequest(ProjectMeasuresDoc doc) {
- String projectUuid = doc.getId();
- return new IndexRequest(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, projectUuid)
- .routing(projectUuid)
- .parent(projectUuid)
- .source(doc.getFields());
- }
-
- private static ProjectMeasuresDoc toProjectMeasuresDoc(ProjectMeasures projectMeasures) {
- Long analysisDate = projectMeasures.getProject().getAnalysisDate();
- return new ProjectMeasuresDoc()
- .setId(projectMeasures.getProject().getUuid())
- .setKey(projectMeasures.getProject().getKey())
- .setName(projectMeasures.getProject().getName())
- .setQualityGate(projectMeasures.getMeasures().getQualityGateStatus())
- .setAnalysedAt(analysisDate == null ? null : new Date(analysisDate))
- .setMeasuresFromMap(projectMeasures.getMeasures().getNumericMeasures());
- }
-}
+++ /dev/null
-/*
- * 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 java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-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;
-
-public class ProjectMeasuresQuery {
- private List<MetricCriterion> metricCriteria = new ArrayList<>();
- private Metric.Level qualityGateStatus;
- private Set<String> projectUuids = null;
-
- public ProjectMeasuresQuery addMetricCriterion(MetricCriterion metricCriterion) {
- this.metricCriteria.add(metricCriterion);
- return this;
- }
-
- public List<MetricCriterion> getMetricCriteria() {
- return metricCriteria;
- }
-
- public ProjectMeasuresQuery setQualityGateStatus(Metric.Level qualityGateStatus) {
- this.qualityGateStatus = requireNonNull(qualityGateStatus);
- return this;
- }
-
- public boolean hasQualityGateStatus() {
- return qualityGateStatus != null;
- }
-
- public Metric.Level getQualityGateStatus() {
- checkState(qualityGateStatus != null);
- return qualityGateStatus;
- }
-
- public ProjectMeasuresQuery setProjectUuids(Set<String> projectUuids) {
- this.projectUuids = requireNonNull(projectUuids);
- return this;
- }
-
- public boolean doesFilterOnProjectUuids() {
- return projectUuids != null;
- }
-
- public Set<String> getProjectUuids() {
- return requireNonNull(projectUuids);
- }
-
- public enum Operator {
- LT("<"), LTE("<="), GT(">"), GTE(">="), EQ("=");
-
- String value;
-
- Operator(String value) {
- this.value = value;
- }
-
- String getValue() {
- return value;
- }
-
- public static Operator getByValue(String value) {
- return stream(Operator.values())
- .filter(operator -> operator.getValue().equals(value))
- .findFirst()
- .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value)));
- }
- }
-
- public static class MetricCriterion {
- private final String metricKey;
- private final Operator operator;
- private final double value;
-
- public MetricCriterion(String metricKey, Operator operator, double value) {
- this.metricKey = requireNonNull(metricKey);
- this.operator = requireNonNull(operator);
- this.value = requireNonNull(value);
- }
-
- public String getMetricKey() {
- return metricKey;
- }
-
- public Operator getOperator() {
- return operator;
- }
-
- public double getValue() {
- return value;
- }
- }
-}
+++ /dev/null
-/*
- * 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 org.sonar.core.platform.Module;
-
-public class ProjectsEsModule extends Module {
- @Override
- protected void configureModule() {
- add(
- ProjectMeasuresIndexDefinition.class,
- ProjectMeasuresIndex.class,
- ProjectMeasuresIndexer.class);
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.component.es;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.measures.Metric.Level;
-import org.sonar.server.component.es.ProjectMeasuresQuery;
+import org.sonar.server.measure.index.ProjectMeasuresQuery;
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.component.es.ProjectMeasuresQuery.MetricCriterion;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
+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));
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.metric.MetricDto;
-import org.sonar.server.component.es.ProjectMeasuresQuery;
+import org.sonar.server.measure.index.ProjectMeasuresQuery;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
+import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion;
public class ProjectMeasuresQueryValidator {
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.property.PropertyQuery;
-import org.sonar.server.component.es.ProjectMeasuresIndex;
-import org.sonar.server.component.es.ProjectMeasuresQuery;
import org.sonar.server.es.Facets;
import org.sonar.server.es.SearchIdResult;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.measure.index.ProjectMeasuresIndex;
+import org.sonar.server.measure.index.ProjectMeasuresQuery;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.WsComponents.Component;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.String.format;
-import static org.sonar.server.component.es.ProjectMeasuresIndex.SUPPORTED_FACETS;
import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
+import static org.sonar.server.measure.index.ProjectMeasuresIndex.SUPPORTED_FACETS;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER;
import static org.sonarqube.ws.client.component.SearchProjectsRequest.DEFAULT_PAGE_SIZE;
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
import org.sonar.server.computation.task.step.ComputationStep;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
public class IndexProjectMeasuresStep implements ComputationStep {
import org.sonar.api.config.Settings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.permission.index.PermissionIndexer;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.server.user.index.UserIndexer;
--- /dev/null
+/*
+ * 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.measure.index;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.server.es.BaseDoc;
+
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
+
+public class ProjectMeasuresDoc extends BaseDoc {
+
+ public ProjectMeasuresDoc() {
+ super(new HashMap<>(4));
+ }
+
+ @Override
+ public String getId() {
+ return getField("_id");
+ }
+
+ @Override
+ public String getRouting() {
+ return getId();
+ }
+
+ @Override
+ public String getParent() {
+ return getId();
+ }
+
+ public ProjectMeasuresDoc setId(String s) {
+ setField("_id", s);
+ return this;
+ }
+
+ public String getKey() {
+ return getField(ProjectMeasuresIndexDefinition.FIELD_KEY);
+ }
+
+ public ProjectMeasuresDoc setKey(String s) {
+ setField(ProjectMeasuresIndexDefinition.FIELD_KEY, s);
+ return this;
+ }
+
+ public String getName() {
+ return getField(ProjectMeasuresIndexDefinition.FIELD_NAME);
+ }
+
+ public ProjectMeasuresDoc setName(String s) {
+ setField(ProjectMeasuresIndexDefinition.FIELD_NAME, s);
+ return this;
+ }
+
+ @CheckForNull
+ public Date getAnalysedAt() {
+ return getNullableField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT);
+ }
+
+ public ProjectMeasuresDoc setAnalysedAt(@Nullable Date d) {
+ setField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, d);
+ return this;
+ }
+
+ public Collection<Map<String, Object>> getMeasures() {
+ return getField(FIELD_MEASURES);
+ }
+
+ public ProjectMeasuresDoc setMeasures(Collection<Map<String, Object>> measures) {
+ setField(FIELD_MEASURES, measures);
+ return this;
+ }
+
+ public ProjectMeasuresDoc setMeasuresFromMap(Map<String, Double> measures) {
+ setMeasures(
+ measures.entrySet().stream()
+ .map(entry -> ImmutableMap.<String, Object>of(
+ ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY, entry.getKey(),
+ ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE, entry.getValue()))
+ .collect(Collectors.toList()));
+ return this;
+ }
+
+ @CheckForNull
+ public String getQualityGate() {
+ return getField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE);
+ }
+
+ public ProjectMeasuresDoc setQualityGate(@Nullable String s) {
+ setField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE, s);
+ return this;
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.IntStream;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.aggregations.AggregationBuilder;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.range.RangeBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+import org.sonar.api.measures.Metric;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.StickyFacetBuilder;
+import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion;
+import org.sonar.server.user.UserSession;
+
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
+import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
+import static org.elasticsearch.search.aggregations.AggregationBuilders.filters;
+import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
+import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
+import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_GROUPS;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_AUTHORIZATION_USERS;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
+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_QUALITY_GATE;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndex extends BaseIndex {
+
+ public static final List<String> SUPPORTED_FACETS = ImmutableList.of(
+ NCLOC_KEY,
+ DUPLICATED_LINES_DENSITY_KEY,
+ COVERAGE_KEY,
+ SQALE_RATING_KEY,
+ RELIABILITY_RATING_KEY,
+ SECURITY_RATING_KEY,
+ ALERT_STATUS_KEY);
+
+ private static final String FIELD_KEY = FIELD_MEASURES + "." + FIELD_MEASURES_KEY;
+ private static final String FIELD_VALUE = FIELD_MEASURES + "." + FIELD_MEASURES_VALUE;
+
+ private final UserSession userSession;
+
+ public ProjectMeasuresIndex(EsClient client, UserSession userSession) {
+ super(client);
+ this.userSession = userSession;
+ }
+
+ public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
+ SearchRequestBuilder requestBuilder = getClient()
+ .prepareSearch(INDEX_PROJECT_MEASURES)
+ .setTypes(TYPE_PROJECT_MEASURES)
+ .setFetchSource(false)
+ .setFrom(searchOptions.getOffset())
+ .setSize(searchOptions.getLimit())
+ .addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
+
+ BoolQueryBuilder esFilter = boolQuery();
+ Map<String, QueryBuilder> filters = createFilters(query);
+ filters.values().forEach(esFilter::must);
+ requestBuilder.setQuery(esFilter);
+
+ addFacets(requestBuilder, searchOptions, filters);
+ return new SearchIdResult<>(requestBuilder.get(), id -> id);
+ }
+
+ private static void addFacets(SearchRequestBuilder esSearch, SearchOptions options, Map<String, QueryBuilder> filters) {
+ if (!options.getFacets().isEmpty()) {
+ if (options.getFacets().contains(NCLOC_KEY)) {
+ addRangeFacet(esSearch, NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d), filters);
+ }
+ if (options.getFacets().contains(DUPLICATED_LINES_DENSITY_KEY)) {
+ addRangeFacet(esSearch, DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d), filters);
+ }
+ if (options.getFacets().contains(COVERAGE_KEY)) {
+ addRangeFacet(esSearch, COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d), filters);
+ }
+ if (options.getFacets().contains(SQALE_RATING_KEY)) {
+ addRatingFacet(esSearch, SQALE_RATING_KEY, filters);
+ }
+ if (options.getFacets().contains(RELIABILITY_RATING_KEY)) {
+ addRatingFacet(esSearch, RELIABILITY_RATING_KEY, filters);
+ }
+ if (options.getFacets().contains(SECURITY_RATING_KEY)) {
+ addRatingFacet(esSearch, SECURITY_RATING_KEY, filters);
+ }
+ if (options.getFacets().contains(ALERT_STATUS_KEY)) {
+ esSearch.addAggregation(createStickyFacet(ALERT_STATUS_KEY, filters, createQualityGateFacet()));
+ }
+ }
+ }
+
+ private static void addRangeFacet(SearchRequestBuilder esSearch, String metricKey, List<Double> thresholds, Map<String, QueryBuilder> filters) {
+ esSearch.addAggregation(createStickyFacet(metricKey, filters, createRangeFacet(metricKey, thresholds)));
+ }
+
+ private static void addRatingFacet(SearchRequestBuilder esSearch, String metricKey, Map<String, QueryBuilder> filters) {
+ esSearch.addAggregation(createStickyFacet(metricKey, filters, createRatingFacet(metricKey)));
+ }
+
+ private static AggregationBuilder createStickyFacet(String metricKey, Map<String, QueryBuilder> filters, AggregationBuilder aggregationBuilder) {
+ StickyFacetBuilder facetBuilder = new StickyFacetBuilder(matchAllQuery(), filters);
+ BoolQueryBuilder facetFilter = facetBuilder.getStickyFacetFilter(metricKey);
+ return AggregationBuilders
+ .global(metricKey)
+ .subAggregation(AggregationBuilders.filter("facet_filter_" + metricKey)
+ .filter(facetFilter)
+ .subAggregation(aggregationBuilder));
+ }
+
+ private static AggregationBuilder createRangeFacet(String metricKey, List<Double> thresholds) {
+ RangeBuilder rangeAgg = AggregationBuilders.range(metricKey)
+ .field(FIELD_VALUE);
+ final int lastIndex = thresholds.size() - 1;
+ IntStream.range(0, thresholds.size())
+ .forEach(i -> {
+ if (i == 0) {
+ rangeAgg.addUnboundedTo(thresholds.get(0));
+ rangeAgg.addRange(thresholds.get(0), thresholds.get(1));
+ } else if (i == lastIndex) {
+ rangeAgg.addUnboundedFrom(thresholds.get(lastIndex));
+ } else {
+ rangeAgg.addRange(thresholds.get(i), thresholds.get(i + 1));
+ }
+ });
+
+ return AggregationBuilders.nested("nested_" + metricKey)
+ .path(FIELD_MEASURES)
+ .subAggregation(
+ AggregationBuilders.filter("filter_" + metricKey)
+ .filter(termsQuery(FIELD_KEY, metricKey))
+ .subAggregation(rangeAgg));
+ }
+
+ private static AggregationBuilder createRatingFacet(String metricKey) {
+ return AggregationBuilders.nested("nested_" + metricKey)
+ .path(FIELD_MEASURES)
+ .subAggregation(
+ AggregationBuilders.filter("filter_" + metricKey)
+ .filter(termsQuery(FIELD_KEY, metricKey))
+ .subAggregation(filters(metricKey)
+ .filter("1", termQuery(FIELD_VALUE, 1d))
+ .filter("2", termQuery(FIELD_VALUE, 2d))
+ .filter("3", termQuery(FIELD_VALUE, 3d))
+ .filter("4", termQuery(FIELD_VALUE, 4d))
+ .filter("5", termQuery(FIELD_VALUE, 5d))));
+ }
+
+ private static AggregationBuilder createQualityGateFacet() {
+ return AggregationBuilders.filters(ALERT_STATUS_KEY)
+ .filter(Metric.Level.ERROR.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.ERROR.name()))
+ .filter(Metric.Level.WARN.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.WARN.name()))
+ .filter(Metric.Level.OK.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.OK.name()));
+ }
+
+ private Map<String, QueryBuilder> createFilters(ProjectMeasuresQuery query) {
+ Map<String, QueryBuilder> filters = new HashMap<>();
+ filters.put("__authorization", createAuthorizationFilter());
+ Multimap<String, MetricCriterion> metricCriterionMultimap = ArrayListMultimap.create();
+ query.getMetricCriteria().forEach(metricCriterion -> metricCriterionMultimap.put(metricCriterion.getMetricKey(), metricCriterion));
+ metricCriterionMultimap.asMap().entrySet().forEach(entry -> {
+ BoolQueryBuilder metricFilters = boolQuery();
+ entry.getValue()
+ .stream()
+ .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery()
+ .filter(termQuery(FIELD_KEY, criterion.getMetricKey()))
+ .filter(toValueQuery(criterion))))
+ .forEach(metricFilters::must);
+ 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()));
+ }
+ return filters;
+ }
+
+ private static QueryBuilder toValueQuery(MetricCriterion criterion) {
+ String fieldName = FIELD_VALUE;
+
+ switch (criterion.getOperator()) {
+ case GT:
+ return rangeQuery(fieldName).gt(criterion.getValue());
+ case GTE:
+ return rangeQuery(fieldName).gte(criterion.getValue());
+ case LT:
+ return rangeQuery(fieldName).lt(criterion.getValue());
+ case LTE:
+ return rangeQuery(fieldName).lte(criterion.getValue());
+ case EQ:
+ return termQuery(fieldName, criterion.getValue());
+ default:
+ throw new IllegalStateException("Metric criteria non supported: " + criterion.getOperator().name());
+ }
+ }
+
+ private QueryBuilder createAuthorizationFilter() {
+ Integer userLogin = userSession.getUserId();
+ Set<String> userGroupNames = userSession.getUserGroups();
+ BoolQueryBuilder groupsAndUser = boolQuery();
+ if (userLogin != null) {
+ groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_USERS, userLogin.longValue()));
+ }
+ for (String group : userGroupNames) {
+ groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_GROUPS, group));
+ }
+ return QueryBuilders.hasParentQuery(TYPE_AUTHORIZATION,
+ QueryBuilders.boolQuery().must(matchAllQuery()).filter(groupsAndUser));
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import com.google.common.collect.ImmutableMap;
+import org.sonar.api.config.Settings;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+public class ProjectMeasuresIndexDefinition implements IndexDefinition {
+
+ public static final String INDEX_PROJECT_MEASURES = "projectmeasures";
+
+ public static final String TYPE_PROJECT_MEASURES = "projectmeasures";
+ public static final String FIELD_KEY = "key";
+ public static final String FIELD_NAME = "name";
+ public static final String FIELD_ANALYSED_AT = "analysedAt";
+ public static final String FIELD_QUALITY_GATE = "qualityGate";
+ public static final String FIELD_MEASURES = "measures";
+ public static final String FIELD_MEASURES_KEY = "key";
+ public static final String FIELD_MEASURES_VALUE = "value";
+
+ public static final String TYPE_AUTHORIZATION = "authorization";
+ public static final String FIELD_AUTHORIZATION_PROJECT_UUID = "project";
+ public static final String FIELD_AUTHORIZATION_GROUPS = "groupNames";
+ public static final String FIELD_AUTHORIZATION_USERS = "users";
+ public static final String FIELD_AUTHORIZATION_UPDATED_AT = "updatedAt";
+
+ private final Settings settings;
+
+ public ProjectMeasuresIndexDefinition(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public void define(IndexDefinitionContext context) {
+ NewIndex index = context.create(INDEX_PROJECT_MEASURES);
+ index.refreshHandledByIndexer();
+ index.configureShards(settings, 5);
+
+ // type "projectmeasures"
+ NewIndex.NewIndexType mapping = index.createType(TYPE_PROJECT_MEASURES);
+ mapping.setAttribute("_parent", ImmutableMap.of("type", TYPE_AUTHORIZATION));
+ mapping.setAttribute("_routing", ImmutableMap.of("required", "true"));
+ mapping.stringFieldBuilder(FIELD_KEY).disableNorms().build();
+ mapping.stringFieldBuilder(FIELD_NAME).enableSorting().build();
+ mapping.stringFieldBuilder(FIELD_QUALITY_GATE).build();
+ mapping.createDateTimeField(FIELD_ANALYSED_AT);
+ mapping.nestedFieldBuilder(FIELD_MEASURES)
+ .addStringFied(FIELD_MEASURES_KEY)
+ .addDoubleField(FIELD_MEASURES_VALUE)
+ .build();
+
+ // do not store document but only indexation of information
+ mapping.setEnableSource(false);
+
+ // type "authorization"
+ NewIndex.NewIndexType authorizationMapping = index.createType(TYPE_AUTHORIZATION);
+ authorizationMapping.setAttribute("_routing", ImmutableMap.of("required", "true"));
+ authorizationMapping.createDateTimeField(FIELD_AUTHORIZATION_UPDATED_AT);
+ authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_PROJECT_UUID).disableNorms().build();
+ authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_GROUPS).disableNorms().build();
+ authorizationMapping.stringFieldBuilder(FIELD_AUTHORIZATION_USERS).disableNorms().build();
+ authorizationMapping.setEnableSource(false);
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import java.util.Date;
+import java.util.Iterator;
+import javax.annotation.Nullable;
+import org.elasticsearch.action.index.IndexRequest;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.measure.ProjectMeasuresIndexerIterator;
+import org.sonar.db.measure.ProjectMeasuresIndexerIterator.ProjectMeasures;
+import org.sonar.server.es.BaseIndexer;
+import org.sonar.server.es.BulkIndexer;
+import org.sonar.server.es.EsClient;
+
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexer extends BaseIndexer {
+
+ private final DbClient dbClient;
+
+ public ProjectMeasuresIndexer(System2 system2, DbClient dbClient, EsClient esClient) {
+ super(system2, esClient, 300, INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, FIELD_ANALYSED_AT);
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ protected long doIndex(long lastUpdatedAt) {
+ return doIndex(createBulkIndexer(false), lastUpdatedAt, null);
+ }
+
+ public void index(String projectUuid) {
+ doIndex(createBulkIndexer(false), 0L, projectUuid);
+ }
+
+ public void deleteProject(String uuid) {
+ esClient
+ .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, uuid)
+ .setRouting(uuid)
+ .setRefresh(true)
+ .get();
+ esClient
+ .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION, uuid)
+ .setRouting(uuid)
+ .setRefresh(true)
+ .get();
+ }
+
+ private long doIndex(BulkIndexer bulk, long lastUpdatedAt, @Nullable String projectUuid) {
+ try (DbSession dbSession = dbClient.openSession(false);
+ ProjectMeasuresIndexerIterator rowIt = ProjectMeasuresIndexerIterator.create(dbSession, lastUpdatedAt, projectUuid)) {
+ return doIndex(bulk, rowIt);
+ }
+ }
+
+ private static long doIndex(BulkIndexer bulk, Iterator<ProjectMeasures> docs) {
+ bulk.start();
+ long maxDate = 0L;
+ while (docs.hasNext()) {
+ ProjectMeasures doc = docs.next();
+ bulk.add(newIndexRequest(toProjectMeasuresDoc(doc)));
+
+ Long analysisDate = doc.getProject().getAnalysisDate();
+ // it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
+ maxDate = Math.max(maxDate, analysisDate == null ? 0L : analysisDate);
+ }
+ bulk.stop();
+ return maxDate;
+ }
+
+ private BulkIndexer createBulkIndexer(boolean large) {
+ BulkIndexer bulk = new BulkIndexer(esClient, INDEX_PROJECT_MEASURES);
+ bulk.setLarge(large);
+ return bulk;
+ }
+
+ private static IndexRequest newIndexRequest(ProjectMeasuresDoc doc) {
+ String projectUuid = doc.getId();
+ return new IndexRequest(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, projectUuid)
+ .routing(projectUuid)
+ .parent(projectUuid)
+ .source(doc.getFields());
+ }
+
+ private static ProjectMeasuresDoc toProjectMeasuresDoc(ProjectMeasures projectMeasures) {
+ Long analysisDate = projectMeasures.getProject().getAnalysisDate();
+ return new ProjectMeasuresDoc()
+ .setId(projectMeasures.getProject().getUuid())
+ .setKey(projectMeasures.getProject().getKey())
+ .setName(projectMeasures.getProject().getName())
+ .setQualityGate(projectMeasures.getMeasures().getQualityGateStatus())
+ .setAnalysedAt(analysisDate == null ? null : new Date(analysisDate))
+ .setMeasuresFromMap(projectMeasures.getMeasures().getNumericMeasures());
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+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;
+
+public class ProjectMeasuresQuery {
+ private List<MetricCriterion> metricCriteria = new ArrayList<>();
+ private Metric.Level qualityGateStatus;
+ private Set<String> projectUuids = null;
+
+ public ProjectMeasuresQuery addMetricCriterion(MetricCriterion metricCriterion) {
+ this.metricCriteria.add(metricCriterion);
+ return this;
+ }
+
+ public List<MetricCriterion> getMetricCriteria() {
+ return metricCriteria;
+ }
+
+ public ProjectMeasuresQuery setQualityGateStatus(Metric.Level qualityGateStatus) {
+ this.qualityGateStatus = requireNonNull(qualityGateStatus);
+ return this;
+ }
+
+ public boolean hasQualityGateStatus() {
+ return qualityGateStatus != null;
+ }
+
+ public Metric.Level getQualityGateStatus() {
+ checkState(qualityGateStatus != null);
+ return qualityGateStatus;
+ }
+
+ public ProjectMeasuresQuery setProjectUuids(Set<String> projectUuids) {
+ this.projectUuids = requireNonNull(projectUuids);
+ return this;
+ }
+
+ public boolean doesFilterOnProjectUuids() {
+ return projectUuids != null;
+ }
+
+ public Set<String> getProjectUuids() {
+ return requireNonNull(projectUuids);
+ }
+
+ public enum Operator {
+ LT("<"), LTE("<="), GT(">"), GTE(">="), EQ("=");
+
+ String value;
+
+ Operator(String value) {
+ this.value = value;
+ }
+
+ String getValue() {
+ return value;
+ }
+
+ public static Operator getByValue(String value) {
+ return stream(Operator.values())
+ .filter(operator -> operator.getValue().equals(value))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value)));
+ }
+ }
+
+ public static class MetricCriterion {
+ private final String metricKey;
+ private final Operator operator;
+ private final double value;
+
+ public MetricCriterion(String metricKey, Operator operator, double value) {
+ this.metricKey = requireNonNull(metricKey);
+ this.operator = requireNonNull(operator);
+ this.value = requireNonNull(value);
+ }
+
+ public String getMetricKey() {
+ return metricKey;
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public double getValue() {
+ return value;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import org.sonar.core.platform.Module;
+
+public class ProjectsEsModule extends Module {
+ @Override
+ protected void configureModule() {
+ add(
+ ProjectMeasuresIndexDefinition.class,
+ ProjectMeasuresIndex.class,
+ ProjectMeasuresIndexer.class);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.measure.index;
+
+import javax.annotation.ParametersAreNonnullByDefault;
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 org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Collections.singletonList;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.version.SqTables;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.EsClient;
import org.sonar.server.issue.index.IssueIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import org.sonar.server.property.InternalProperties;
import org.sonar.server.view.index.ViewIndexDefinition;
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.debt.DebtModelBackup;
import org.sonar.server.debt.DebtModelPluginRepository;
import org.sonar.server.language.ws.LanguageWs;
import org.sonar.server.license.ws.LicensesWsModule;
import org.sonar.server.measure.custom.ws.CustomMeasuresWsModule;
+import org.sonar.server.measure.index.ProjectsEsModule;
import org.sonar.server.measure.template.MyFavouritesFilter;
import org.sonar.server.measure.template.ProjectFilter;
import org.sonar.server.measure.ws.MeasuresWsModule;
import org.sonar.db.issue.IssueTesting;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.IssueDocTesting;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.permission.index.PermissionIndexer;
import org.sonar.server.test.index.TestDoc;
import org.sonar.server.test.index.TestIndexDefinition;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ResourceIndexDao;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.tester.UserSessionRule;
import static com.google.common.collect.Lists.newArrayList;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
public class ComponentServiceTest {
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.tester.UserSessionRule;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
public class ComponentServiceUpdateKeyTest {
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceDao;
import org.sonar.db.component.ResourceDto;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.favorite.FavoriteUpdater;
import org.sonar.server.i18n.I18nRule;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.tester.UserSessionRule;
+++ /dev/null
-/*
- * 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.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.IntStream;
-import javax.annotation.Nullable;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.MapSettings;
-import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
-import org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.es.Facets;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.permission.index.PermissionIndexerTester;
-import org.sonar.server.tester.UserSessionRule;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Sets.newHashSet;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
-import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
-import static org.sonar.api.measures.Metric.Level.ERROR;
-import static org.sonar.api.measures.Metric.Level.OK;
-import static org.sonar.api.measures.Metric.Level.WARN;
-import static org.sonar.api.security.DefaultGroups.ANYONE;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexTest {
-
- private static final String MAINTAINABILITY_RATING = "sqale_rating";
- private static final String RELIABILITY_RATING = "reliability_rating";
- private static final String SECURITY_RATING = "security_rating";
- private static final String COVERAGE = "coverage";
- private static final String DUPLICATION = "duplicated_lines_density";
- private static final String NCLOC = "ncloc";
-
- @Rule
- public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
-
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
-
- private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es);
-
- private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client(), userSession);
-
- @Test
- public void empty_search() {
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).isEmpty();
- }
-
- @Test
- public void search_sort_by_name_case_insensitive() {
- addDocs(newDoc("P1", "K1", "Windows"),
- newDoc("P3", "K3", "apachee"),
- newDoc("P2", "K2", "Apache"));
-
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P2", "P3", "P1");
- }
-
- @Test
- public void search_paginate_results() {
- IntStream.rangeClosed(1, 9)
- .forEach(i -> addDocs(newDoc("P" + i, "K" + i, "P" + i)));
-
- SearchIdResult<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().setPage(2, 3));
-
- assertThat(result.getIds()).containsExactly("P4", "P5", "P6");
- assertThat(result.getTotal()).isEqualTo(9);
- }
-
- @Test
- public void filter_with_lower_than() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
-
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 80d));
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P1");
- }
-
- @Test
- public void filter_with_lower_than_or_equals() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
-
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d));
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P1", "P2");
- }
-
- @Test
- public void filter_with_greater_than() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_000d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))));
-
- assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 30_000d)),
- new SearchOptions()).getIds()).containsExactly("P2", "P3");
- assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 100_000d)),
- new SearchOptions()).getIds()).isEmpty();
- }
-
- @Test
- public void filter_with_greater_than_or_equals() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_000d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))));
-
- assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 30_001d)),
- new SearchOptions()).getIds()).containsExactly("P2", "P3");
- assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 100_000d)),
- new SearchOptions()).getIds()).isEmpty();
- }
-
- @Test
- public void filter_with_equals() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
-
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.EQ, 80d));
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P2");
- }
-
- @Test
- public void filter_on_several_metrics() {
- addDocs(
- newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_001d))),
- newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
- newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))));
-
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d))
- .addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 10_000d))
- .addMetricCriterion(new MetricCriterion(NCLOC, Operator.LT, 11_000d));
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P2");
- }
-
- @Test
- public void filter_on_quality_gate_status() {
- addDocs(
- newDoc("P1", "K1", "N1").setQualityGate("OK"),
- newDoc("P2", "K2", "N2").setQualityGate("OK"),
- newDoc("P3", "K3", "N3").setQualityGate("WARN"));
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery().setQualityGateStatus(OK);
-
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P1", "P2");
- }
-
- @Test
- public void filter_on_ids() {
- addDocs(
- newDoc("P1", "K1", "N1"),
- newDoc("P2", "K2", "N2"),
- newDoc("P3", "K3", "N3"));
- ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery().setProjectUuids(newHashSet("P1", "P3"));
-
- List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
- assertThat(result).containsExactly("P1", "P3");
- }
-
- @Test
- public void return_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
- addDocs(10L, null, newDoc("P1", "K1", "Windows"));
- addDocs(10L, "dev", newDoc("P2", "K2", "apachee"));
- addDocs(33L, null, newDoc("P10", "K10", "N10"));
-
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).containsOnly("P1", "P2");
- }
-
- @Test
- public void return_only_projects_authorized_for_user_groups() throws Exception {
- userSession.setUserGroups("dev");
- addDocs(10L, "dev", newDoc("P1", "K1", "apachee"));
- addDocs(null, ANYONE, newDoc("P2", "K2", "N2"));
- addDocs(null, "admin", newDoc("P10", "K10", "N10"));
-
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).containsOnly("P1", "P2");
- }
-
- @Test
- public void return_only_projects_authorized_for_user_and_groups() throws Exception {
- userSession.login("john").setUserId(10).setUserGroups("dev");
- addDocs(10L, null, newDoc("P1", "K1", "Windows"));
- addDocs(null, "dev", newDoc("P2", "K2", "Apache"));
- addDocs(10L, "dev", newDoc("P3", "K3", "apachee"));
- // Current user is not able to see following projects
- addDocs(null, "another group", newDoc("P5", "K5", "N5"));
- addDocs(33L, null, newDoc("P6", "K6", "N6"));
- addDocs((Long) null, null, newDoc("P7", "K7", "N7"));
-
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).containsOnly("P1", "P2", "P3");
- }
-
- @Test
- public void anyone_user_can_only_access_projects_authorized_for_anyone() throws Exception {
- userSession.anonymous();
- addDocs(null, ANYONE, newDoc("P1", "K1", "N1"));
- addDocs(10L, null, newDoc("P2", "K2", "Windows"));
- addDocs(null, "admin", newDoc("P3", "K3", "N3"));
-
- List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
-
- assertThat(result).containsOnly("P1");
- }
-
- @Test
- public void does_not_return_facet_when_no_facets_in_options() throws Exception {
- addDocs(
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE_KEY, 30d), newMeasure(MAINTAINABILITY_RATING, 3d)))
- .setQualityGate(OK.name()));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getFacets();
-
- assertThat(facets.getAll()).isEmpty();
- }
-
- @Test
- public void facet_ncloc() {
- addDocs(
- // 3 docs with ncloc<1K
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d))),
- // 2 docs with ncloc>=1K and ncloc<10K
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d))),
- // 4 docs with ncloc>=10K and ncloc<100K
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d))),
- // 2 docs with ncloc>=100K and ncloc<500K
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d))),
- // 5 docs with ncloc>= 500K
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 500_000d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000_000d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 500_000d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 1_000_000d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000_000_000d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(NCLOC)).getFacets();
-
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 3L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 4L),
- entry("100000.0-500000.0", 2L),
- entry("500000.0-*", 5L));
- }
-
- @Test
- public void facet_ncloc_is_sticky() {
- addDocs(
- // 1 docs with ncloc<1K
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d), newMeasure(DUPLICATION, 0d))),
- // 2 docs with ncloc>=1K and ncloc<10K
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d), newMeasure(COVERAGE, 10d), newMeasure(DUPLICATION, 0d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d), newMeasure(COVERAGE, 20d), newMeasure(DUPLICATION, 0d))),
- // 3 docs with ncloc>=10K and ncloc<100K
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d), newMeasure(COVERAGE, 31d), newMeasure(DUPLICATION, 0d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d), newMeasure(COVERAGE, 40d), newMeasure(DUPLICATION, 0d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d), newMeasure(COVERAGE, 50d), newMeasure(DUPLICATION, 0d))),
- // 2 docs with ncloc>=100K and ncloc<500K
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d), newMeasure(COVERAGE, 71d), newMeasure(DUPLICATION, 0d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d), newMeasure(COVERAGE, 80d), newMeasure(DUPLICATION, 0d))),
- // 1 docs with ncloc>= 500K
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d), newMeasure(COVERAGE, 81d), newMeasure(DUPLICATION, 20d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(NCLOC, Operator.LT, 10_000d))
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
- new SearchOptions().addFacets(NCLOC, COVERAGE)).getFacets();
-
- // Sticky facet on ncloc does not take into account ncloc filter
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 1L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 3L),
- entry("100000.0-500000.0", 2L),
- entry("500000.0-*", 0L));
- // But facet on coverage does well take into into filters
- assertThat(facets.get(COVERAGE)).containsExactly(
- entry("*-30.0", 3L),
- entry("30.0-50.0", 0L),
- entry("50.0-70.0", 0L),
- entry("70.0-80.0", 0L),
- entry("80.0-*", 0L));
- }
-
- @Test
- public void facet_ncloc_contains_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
-
- // User can see these projects
- addDocs(10L, null,
- // docs with ncloc<1K
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 100d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d))),
- // docs with ncloc>=1K and ncloc<10K
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d))));
-
- // User cannot see these projects
- addDocs(33L, null,
- // doc with ncloc>=10K and ncloc<100K
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d))),
- // doc with ncloc>=100K and ncloc<500K
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d))),
- // doc with ncloc>= 500K
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(NCLOC)).getFacets();
-
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 3L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 0L),
- entry("100000.0-500000.0", 0L),
- entry("500000.0-*", 0L));
- }
-
- @Test
- public void facet_coverage() {
- addDocs(
- // 3 docs with coverage<30%
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 29d))),
- // 2 docs with coverage>=30% and coverage<50%
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 30d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 49d))),
- // 4 docs with coverage>=50% and coverage<70%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 50d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 60d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 60d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 69d))),
- // 2 docs with coverage>=70% and coverage<80%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 70d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d))),
- // 5 docs with coverage>= 80%
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 90d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 90.5d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 100d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(COVERAGE)).getFacets();
-
- assertThat(facets.get(COVERAGE)).containsExactly(
- entry("*-30.0", 3L),
- entry("30.0-50.0", 2L),
- entry("50.0-70.0", 4L),
- entry("70.0-80.0", 2L),
- entry("80.0-*", 5L));
- }
-
- @Test
- public void facet_coverage_is_sticky() {
- addDocs(
- // docs with coverage<30%
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d), newMeasure(DUPLICATION, 0d))),
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d), newMeasure(COVERAGE, 10d), newMeasure(DUPLICATION, 0d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d), newMeasure(COVERAGE, 20d), newMeasure(DUPLICATION, 0d))),
- // docs with coverage>=30% and coverage<50%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d), newMeasure(COVERAGE, 31d), newMeasure(DUPLICATION, 0d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d), newMeasure(COVERAGE, 40d), newMeasure(DUPLICATION, 0d))),
- // docs with coverage>=50% and coverage<70%
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d), newMeasure(COVERAGE, 50d), newMeasure(DUPLICATION, 0d))),
- // docs with coverage>=70% and coverage<80%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d), newMeasure(COVERAGE, 71d), newMeasure(DUPLICATION, 0d))),
- // docs with coverage>= 80%
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d), newMeasure(COVERAGE, 80d), newMeasure(DUPLICATION, 15d))),
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d), newMeasure(COVERAGE, 810d), newMeasure(DUPLICATION, 20d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d))
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
- new SearchOptions().addFacets(COVERAGE, NCLOC)).getFacets();
-
- // Sticky facet on coverage does not take into account coverage filter
- assertThat(facets.get(COVERAGE)).containsExactly(
- entry("*-30.0", 3L),
- entry("30.0-50.0", 2L),
- entry("50.0-70.0", 1L),
- entry("70.0-80.0", 1L),
- entry("80.0-*", 0L));
- // But facet on ncloc does well take into into filters
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 1L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 0L),
- entry("100000.0-500000.0", 0L),
- entry("500000.0-*", 0L));
- }
-
- @Test
- public void facet_coverage_contains_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
-
- // User can see these projects
- addDocs(10L, null,
- // docs with coverage<30%
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 29d))),
- // docs with coverage>=30% and coverage<50%
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 30d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 49d))));
-
- // User cannot see these projects
- addDocs(33L, null,
- // docs with coverage>=50% and coverage<70%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 50d))),
- // docs with coverage>=70% and coverage<80%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 70d))),
- // docs with coverage>= 80%
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(COVERAGE)).getFacets();
-
- assertThat(facets.get(COVERAGE)).containsExactly(
- entry("*-30.0", 3L),
- entry("30.0-50.0", 2L),
- entry("50.0-70.0", 0L),
- entry("70.0-80.0", 0L),
- entry("80.0-*", 0L));
- }
-
- @Test
- public void facet_duplicated_lines_density() {
- addDocs(
- // 3 docs with duplication<3%
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 2.9d))),
- // 2 docs with duplication>=3% and duplication<5%
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d))),
- // 4 docs with duplication>=5% and duplication<10%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 6d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 6d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 9.9d))),
- // 2 docs with duplication>=10% and duplication<20%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 19.9d))),
- // 5 docs with duplication>= 20%
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 50d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 80d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 100d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(DUPLICATION)).getFacets();
-
- assertThat(facets.get(DUPLICATION)).containsExactly(
- entry("*-3.0", 3L),
- entry("3.0-5.0", 2L),
- entry("5.0-10.0", 4L),
- entry("10.0-20.0", 2L),
- entry("20.0-*", 5L));
- }
-
- @Test
- public void facet_duplicated_lines_density_is_sticky() {
- addDocs(
- // docs with duplication<3%
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d), newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d))),
- // docs with duplication>=3% and duplication<5%
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d), newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 0d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d), newMeasure(NCLOC, 6000d), newMeasure(COVERAGE, 0d))),
- // docs with duplication>=5% and duplication<10%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d), newMeasure(NCLOC, 11000d), newMeasure(COVERAGE, 0d))),
- // docs with duplication>=10% and duplication<20%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d), newMeasure(NCLOC, 120000d), newMeasure(COVERAGE, 10d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 19.9d), newMeasure(NCLOC, 130000d), newMeasure(COVERAGE, 20d))),
- // docs with duplication>= 20%
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d), newMeasure(NCLOC, 1000000d), newMeasure(COVERAGE, 40d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d))
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
- new SearchOptions().addFacets(DUPLICATION, NCLOC)).getFacets();
-
- // Sticky facet on duplication does not take into account duplication filter
- assertThat(facets.get(DUPLICATION)).containsExactly(
- entry("*-3.0", 1L),
- entry("3.0-5.0", 2L),
- entry("5.0-10.0", 1L),
- entry("10.0-20.0", 2L),
- entry("20.0-*", 0L));
- // But facet on ncloc does well take into into filters
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 1L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 1L),
- entry("100000.0-500000.0", 0L),
- entry("500000.0-*", 0L));
- }
-
- @Test
- public void facet_duplicated_lines_density_contains_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
-
- // User can see these projects
- addDocs(10L, null,
- // docs with duplication<3%
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 2.9d))),
- // docs with duplication>=3% and duplication<5%
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d))));
-
- // User cannot see these projects
- addDocs(33L, null,
- // docs with duplication>=5% and duplication<10%
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d))),
- // docs with duplication>=10% and duplication<20%
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d))),
- // docs with duplication>= 20%
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(DUPLICATION)).getFacets();
-
- assertThat(facets.get(DUPLICATION)).containsExactly(
- entry("*-3.0", 3L),
- entry("3.0-5.0", 2L),
- entry("5.0-10.0", 0L),
- entry("10.0-20.0", 0L),
- entry("20.0-*", 0L));
- }
-
- @Test
- public void facet_maintainability_rating() {
- addDocs(
- // 3 docs with rating A
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- // 2 docs with rating B
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
- // 4 docs with rating C
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
- // 2 docs with rating D
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
- // 5 docs with rating E
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(MAINTAINABILITY_RATING)).getFacets();
-
- assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
- entry("1", 3L),
- entry("2", 2L),
- entry("3", 4L),
- entry("4", 2L),
- entry("5", 5L));
- }
-
- @Test
- public void facet_maintainability_rating_is_sticky() {
- addDocs(
- // docs with rating A
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 200d), newMeasure(COVERAGE, 0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d))),
- // docs with rating B
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d), newMeasure(NCLOC, 2000d), newMeasure(COVERAGE, 0d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d), newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 0d))),
- // docs with rating C
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 20000d), newMeasure(COVERAGE, 0d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 30000d), newMeasure(COVERAGE, 0d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 40000d), newMeasure(COVERAGE, 0d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 50000d), newMeasure(COVERAGE, 0d))),
- // docs with rating D
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d), newMeasure(NCLOC, 120000d), newMeasure(COVERAGE, 0d))),
- // docs with rating E
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 600000d), newMeasure(COVERAGE, 40d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 700000d), newMeasure(COVERAGE, 50d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 800000d), newMeasure(COVERAGE, 60d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(MAINTAINABILITY_RATING, Operator.LT, 3d))
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
- new SearchOptions().addFacets(MAINTAINABILITY_RATING, NCLOC)).getFacets();
-
- // Sticky facet on maintainability rating does not take into account maintainability rating filter
- assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
- entry("1", 3L),
- entry("2", 2L),
- entry("3", 4L),
- entry("4", 1L),
- entry("5", 0L));
- // But facet on ncloc does well take into into filters
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 3L),
- entry("1000.0-10000.0", 2L),
- entry("10000.0-100000.0", 0L),
- entry("100000.0-500000.0", 0L),
- entry("500000.0-*", 0L));
- }
-
- @Test
- public void facet_maintainability_rating_contains_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
-
- // User can see these projects
- addDocs(10L, null,
- // 3 docs with rating A
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
- // 2 docs with rating B
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))));
-
- // User cannot see these projects
- addDocs(33L, null,
- // docs with rating C
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
- // docs with rating D
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
- // docs with rating E
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(MAINTAINABILITY_RATING)).getFacets();
-
- assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
- entry("1", 3L),
- entry("2", 2L),
- entry("3", 0L),
- entry("4", 0L),
- entry("5", 0L));
- }
-
- @Test
- public void facet_reliability_rating() {
- addDocs(
- // 3 docs with rating A
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
- // 2 docs with rating B
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 2d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 2d))),
- // 4 docs with rating C
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
- // 2 docs with rating D
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 4d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 4d))),
- // 5 docs with rating E
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(RELIABILITY_RATING)).getFacets();
-
- assertThat(facets.get(RELIABILITY_RATING)).containsExactly(
- entry("1", 3L),
- entry("2", 2L),
- entry("3", 4L),
- entry("4", 2L),
- entry("5", 5L));
- }
-
- @Test
- public void facet_security_rating() {
- addDocs(
- // 3 docs with rating A
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
- newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
- newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
- // 2 docs with rating B
- newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 2.0d))),
- newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 2.0d))),
- // 4 docs with rating C
- newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
- newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
- newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
- newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
- // 2 docs with rating D
- newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 4.0d))),
- newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 4.0d))),
- // 5 docs with rating E
- newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
- newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
- newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
- newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
- newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(SECURITY_RATING)).getFacets();
-
- assertThat(facets.get(SECURITY_RATING)).containsExactly(
- entry("1", 3L),
- entry("2", 2L),
- entry("3", 4L),
- entry("4", 2L),
- entry("5", 5L));
- }
-
- @Test
- public void facet_quality_gate() {
- addDocs(
- // 2 docs with QG OK
- newDoc("P11", "K1", "N1").setQualityGate(OK.name()),
- newDoc("P12", "K1", "N1").setQualityGate(OK.name()),
- // 3 docs with QG WARN
- newDoc("P21", "K1", "N1").setQualityGate(WARN.name()),
- newDoc("P22", "K1", "N1").setQualityGate(WARN.name()),
- newDoc("P23", "K1", "N1").setQualityGate(WARN.name()),
- // 4 docs with QG ERROR
- newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()));
-
- LinkedHashMap<String, Long> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(ALERT_STATUS_KEY)).getFacets().get(ALERT_STATUS_KEY);
-
- assertThat(result).containsExactly(
- entry(ERROR.name(), 4L),
- entry(WARN.name(), 3L),
- entry(OK.name(), 2L));
- }
-
- @Test
- public void facet_quality_gate_is_sticky() {
- addDocs(
- // 2 docs with QG OK
- newDoc("P11", "K1", "N1").setQualityGate(OK.name()).setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE, 0d))),
- newDoc("P12", "K1", "N1").setQualityGate(OK.name()).setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE, 0d))),
- // 3 docs with QG WARN
- newDoc("P21", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
- newDoc("P22", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
- newDoc("P23", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
- // 4 docs with QG ERROR
- newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
- newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 40d))),
- newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 12000d), newMeasure(COVERAGE, 50d))),
- newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 13000d), newMeasure(COVERAGE, 60d))));
-
- Facets facets = underTest.search(new ProjectMeasuresQuery()
- .setQualityGateStatus(ERROR)
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 55d)),
- new SearchOptions().addFacets(ALERT_STATUS_KEY, NCLOC)).getFacets();
-
- // Sticky facet on quality gate does not take into account quality gate filter
- assertThat(facets.get(ALERT_STATUS_KEY)).containsOnly(
- entry(OK.name(), 2L),
- entry(WARN.name(), 3L),
- entry(ERROR.name(), 3L));
- // But facet on ncloc does well take into into filters
- assertThat(facets.get(NCLOC)).containsExactly(
- entry("*-1000.0", 1L),
- entry("1000.0-10000.0", 1L),
- entry("10000.0-100000.0", 1L),
- entry("100000.0-500000.0", 0L),
- entry("500000.0-*", 0L));
- }
-
- @Test
- public void facet_quality_gate_contains_only_projects_authorized_for_user() throws Exception {
- userSession.login("john").setUserId(10);
-
- // User can see these projects
- addDocs(10L, null,
- // 2 docs with QG OK
- newDoc("P11", "K1", "N1").setQualityGate(OK.name()),
- newDoc("P12", "K1", "N1").setQualityGate(OK.name()),
- // 3 docs with QG WARN
- newDoc("P21", "K1", "N1").setQualityGate(WARN.name()),
- newDoc("P22", "K1", "N1").setQualityGate(WARN.name()),
- newDoc("P23", "K1", "N1").setQualityGate(WARN.name()));
-
- // User cannot see these projects
- addDocs(33L, null,
- // 4 docs with QG ERROR
- newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()),
- newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()));
-
- LinkedHashMap<String, Long> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(ALERT_STATUS_KEY)).getFacets().get(ALERT_STATUS_KEY);
-
- assertThat(result).containsExactly(
- entry(ERROR.name(), 0L),
- entry(WARN.name(), 3L),
- entry(OK.name(), 2L));
- }
-
- private void addDocs(ProjectMeasuresDoc... docs) {
- addDocs(null, ANYONE, docs);
- }
-
- private void addDocs(@Nullable Long authorizeUser, @Nullable String authorizedGroup, ProjectMeasuresDoc... docs) {
- try {
- es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
- for (ProjectMeasuresDoc doc : docs) {
- authorizationIndexerTester.indexProjectPermission(doc.getId(),
- authorizedGroup != null ? singletonList(authorizedGroup) : emptyList(),
- authorizeUser != null ? singletonList(authorizeUser) : emptyList());
- }
- } catch (Exception e) {
- Throwables.propagate(e);
- }
- }
-
- private static ProjectMeasuresDoc newDoc(String uuid, String key, String name) {
- return new ProjectMeasuresDoc()
- .setId(uuid)
- .setKey(key)
- .setName(name);
- }
-
- private Map<String, Object> newMeasure(String key, Object value) {
- return ImmutableMap.of("key", key, "value", value);
- }
-}
+++ /dev/null
-/*
- * 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 java.util.Date;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.junit.Rule;
-import org.junit.Test;
-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.SnapshotDto;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.permission.index.PermissionIndexerTester;
-
-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.matchAllQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexerTest {
-
- private System2 system2 = System2.INSTANCE;
-
- @Rule
- public EsTester esTester = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
-
- @Rule
- public DbTester dbTester = DbTester.create(system2);
-
- ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
- PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(esTester);
-
- ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(system2, dbTester.getDbClient(), esTester.client());
-
- @Test
- public void index_nothing() {
- underTest.index();
-
- assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isZero();
- }
-
- @Test
- public void index_all_project() {
- OrganizationDto organizationDto = dbTester.organizations().insert();
- componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
- componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
- componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
-
- underTest.index();
-
- assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isEqualTo(3);
- }
-
- @Test
- public void index_projects_even_when_no_analysis() {
- ComponentDto project = componentDbTester.insertProject();
-
- underTest.index();
-
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
- }
-
- @Test
- public void index_one_project() throws Exception {
- OrganizationDto organizationDto = dbTester.organizations().insert();
- ComponentDto project = newProjectDto(organizationDto);
- componentDbTester.insertProjectAndSnapshot(project);
- componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
-
- underTest.index(project.uuid());
-
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
- }
-
- @Test
- public void update_existing_document_when_indexing_one_project() throws Exception {
- String uuid = "PROJECT-UUID";
- esTester.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc()
- .setId(uuid)
- .setKey("Old Key")
- .setName("Old Name")
- .setAnalysedAt(new Date(1_000_000L)));
- ComponentDto project = newProjectDto(dbTester.getDefaultOrganization(), uuid).setKey("New key").setName("New name");
- SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
-
- underTest.index(project.uuid());
-
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(uuid);
- SearchRequestBuilder request = esTester.client()
- .prepareSearch(INDEX_PROJECT_MEASURES)
- .setTypes(TYPE_PROJECT_MEASURES)
- .setQuery(boolQuery().must(matchAllQuery()).filter(
- boolQuery()
- .must(termQuery("_id", uuid))
- .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_KEY, "New key"))
- .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_NAME, "New name"))
- .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, new Date(analysis.getCreatedAt())))));
- assertThat(request.get().getHits()).hasSize(1);
- }
-
- @Test
- public void delete_project() {
- OrganizationDto organizationDto = dbTester.organizations().insert();
- ComponentDto project1 = newProjectDto(organizationDto);
- componentDbTester.insertProjectAndSnapshot(project1);
- ComponentDto project2 = newProjectDto(organizationDto);
- componentDbTester.insertProjectAndSnapshot(project2);
- ComponentDto project3 = newProjectDto(organizationDto);
- componentDbTester.insertProjectAndSnapshot(project3);
- underTest.index();
- authorizationIndexerTester.indexProjectPermission(project1.uuid(), emptyList(), emptyList());
- authorizationIndexerTester.indexProjectPermission(project2.uuid(), emptyList(), emptyList());
- authorizationIndexerTester.indexProjectPermission(project3.uuid(), emptyList(), emptyList());
-
- underTest.deleteProject(project1.uuid());
-
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project2.uuid(), project3.uuid());
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION)).containsOnly(project2.uuid(), project3.uuid());
- }
-
- @Test
- public void does_nothing_when_deleting_unknown_project() throws Exception {
- ComponentDto project = newProjectDto(dbTester.organizations().insert());
- componentDbTester.insertProjectAndSnapshot(project);
- underTest.index();
- authorizationIndexerTester.indexProjectPermission(project.uuid(), emptyList(), emptyList());
-
- underTest.deleteProject("UNKNOWN");
-
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
- assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION)).containsOnly(project.uuid());
- }
-}
+++ /dev/null
-/*
- * 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 org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.measures.Metric.Level;
-
-import static org.assertj.core.api.Java6Assertions.assertThat;
-import static org.assertj.core.groups.Tuple.tuple;
-import static org.sonar.api.measures.Metric.Level.OK;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator.EQ;
-
-public class ProjectMeasuresQueryTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- ProjectMeasuresQuery underTest = new ProjectMeasuresQuery();
-
- @Test
- public void empty_query() throws Exception {
- assertThat(underTest.getMetricCriteria()).isEmpty();
- assertThat(underTest.hasQualityGateStatus()).isFalse();
- }
-
- @Test
- public void add_metric_criterion() throws Exception {
- underTest.addMetricCriterion(new MetricCriterion("coverage", EQ, 10d));
-
- assertThat(underTest.getMetricCriteria())
- .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
- .containsOnly(tuple("coverage", EQ, 10d));
- }
-
- @Test
- 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();
- }
-
- @Test
- public void fail_to_create_operator_from_unknown_value() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
- ProjectMeasuresQuery.Operator.valueOf("UNKNOWN");
- }
-}
+++ /dev/null
-/*
- * 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 org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProjectsEsModuleTest {
- @Test
- public void verify_count_of_added_components() {
- ComponentContainer container = new ComponentContainer();
- new ProjectsEsModule().configure(container);
- assertThat(container.size()).isEqualTo(3 + 2);
- }
-}
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentService;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.server.component.es.ProjectMeasuresQuery;
+import org.sonar.server.measure.index.ProjectMeasuresQuery;
import org.sonar.server.tester.UserSessionRule;
import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
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 {
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.property.PropertyDto;
-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.measure.index.ProjectMeasuresDoc;
+import org.sonar.server.measure.index.ProjectMeasuresIndex;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.KeyExamples;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.component.ComponentTesting.newView;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
--- /dev/null
+/*
+ * 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.measure.index;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.MapSettings;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.Facets;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.measure.index.ProjectMeasuresDoc;
+import org.sonar.server.measure.index.ProjectMeasuresIndex;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+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.permission.index.PermissionIndexerTester;
+import org.sonar.server.tester.UserSessionRule;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
+import static org.sonar.api.measures.Metric.Level.ERROR;
+import static org.sonar.api.measures.Metric.Level.OK;
+import static org.sonar.api.measures.Metric.Level.WARN;
+import static org.sonar.api.security.DefaultGroups.ANYONE;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexTest {
+
+ private static final String MAINTAINABILITY_RATING = "sqale_rating";
+ private static final String RELIABILITY_RATING = "reliability_rating";
+ private static final String SECURITY_RATING = "security_rating";
+ private static final String COVERAGE = "coverage";
+ private static final String DUPLICATION = "duplicated_lines_density";
+ private static final String NCLOC = "ncloc";
+
+ @Rule
+ public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es);
+
+ private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client(), userSession);
+
+ @Test
+ public void empty_search() {
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void search_sort_by_name_case_insensitive() {
+ addDocs(newDoc("P1", "K1", "Windows"),
+ newDoc("P3", "K3", "apachee"),
+ newDoc("P2", "K2", "Apache"));
+
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P2", "P3", "P1");
+ }
+
+ @Test
+ public void search_paginate_results() {
+ IntStream.rangeClosed(1, 9)
+ .forEach(i -> addDocs(newDoc("P" + i, "K" + i, "P" + i)));
+
+ SearchIdResult<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().setPage(2, 3));
+
+ assertThat(result.getIds()).containsExactly("P4", "P5", "P6");
+ assertThat(result.getTotal()).isEqualTo(9);
+ }
+
+ @Test
+ public void filter_with_lower_than() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
+
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 80d));
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P1");
+ }
+
+ @Test
+ public void filter_with_lower_than_or_equals() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
+
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d));
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P1", "P2");
+ }
+
+ @Test
+ public void filter_with_greater_than() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_000d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))));
+
+ assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 30_000d)),
+ new SearchOptions()).getIds()).containsExactly("P2", "P3");
+ assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 100_000d)),
+ new SearchOptions()).getIds()).isEmpty();
+ }
+
+ @Test
+ public void filter_with_greater_than_or_equals() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_000d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 30_001d))));
+
+ assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 30_001d)),
+ new SearchOptions()).getIds()).containsExactly("P2", "P3");
+ assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 100_000d)),
+ new SearchOptions()).getIds()).isEmpty();
+ }
+
+ @Test
+ public void filter_with_equals() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
+
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.EQ, 80d));
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P2");
+ }
+
+ @Test
+ public void filter_on_several_metrics() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_001d))),
+ newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
+ newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))));
+
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d))
+ .addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 10_000d))
+ .addMetricCriterion(new MetricCriterion(NCLOC, Operator.LT, 11_000d));
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P2");
+ }
+
+ @Test
+ public void filter_on_quality_gate_status() {
+ addDocs(
+ newDoc("P1", "K1", "N1").setQualityGate("OK"),
+ newDoc("P2", "K2", "N2").setQualityGate("OK"),
+ newDoc("P3", "K3", "N3").setQualityGate("WARN"));
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery().setQualityGateStatus(OK);
+
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P1", "P2");
+ }
+
+ @Test
+ public void filter_on_ids() {
+ addDocs(
+ newDoc("P1", "K1", "N1"),
+ newDoc("P2", "K2", "N2"),
+ newDoc("P3", "K3", "N3"));
+ ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery().setProjectUuids(newHashSet("P1", "P3"));
+
+ List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+ assertThat(result).containsExactly("P1", "P3");
+ }
+
+ @Test
+ public void return_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+ addDocs(10L, null, newDoc("P1", "K1", "Windows"));
+ addDocs(10L, "dev", newDoc("P2", "K2", "apachee"));
+ addDocs(33L, null, newDoc("P10", "K10", "N10"));
+
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).containsOnly("P1", "P2");
+ }
+
+ @Test
+ public void return_only_projects_authorized_for_user_groups() throws Exception {
+ userSession.setUserGroups("dev");
+ addDocs(10L, "dev", newDoc("P1", "K1", "apachee"));
+ addDocs(null, ANYONE, newDoc("P2", "K2", "N2"));
+ addDocs(null, "admin", newDoc("P10", "K10", "N10"));
+
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).containsOnly("P1", "P2");
+ }
+
+ @Test
+ public void return_only_projects_authorized_for_user_and_groups() throws Exception {
+ userSession.login("john").setUserId(10).setUserGroups("dev");
+ addDocs(10L, null, newDoc("P1", "K1", "Windows"));
+ addDocs(null, "dev", newDoc("P2", "K2", "Apache"));
+ addDocs(10L, "dev", newDoc("P3", "K3", "apachee"));
+ // Current user is not able to see following projects
+ addDocs(null, "another group", newDoc("P5", "K5", "N5"));
+ addDocs(33L, null, newDoc("P6", "K6", "N6"));
+ addDocs((Long) null, null, newDoc("P7", "K7", "N7"));
+
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).containsOnly("P1", "P2", "P3");
+ }
+
+ @Test
+ public void anyone_user_can_only_access_projects_authorized_for_anyone() throws Exception {
+ userSession.anonymous();
+ addDocs(null, ANYONE, newDoc("P1", "K1", "N1"));
+ addDocs(10L, null, newDoc("P2", "K2", "Windows"));
+ addDocs(null, "admin", newDoc("P3", "K3", "N3"));
+
+ List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+ assertThat(result).containsOnly("P1");
+ }
+
+ @Test
+ public void does_not_return_facet_when_no_facets_in_options() throws Exception {
+ addDocs(
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE_KEY, 30d), newMeasure(MAINTAINABILITY_RATING, 3d)))
+ .setQualityGate(OK.name()));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getFacets();
+
+ assertThat(facets.getAll()).isEmpty();
+ }
+
+ @Test
+ public void facet_ncloc() {
+ addDocs(
+ // 3 docs with ncloc<1K
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d))),
+ // 2 docs with ncloc>=1K and ncloc<10K
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d))),
+ // 4 docs with ncloc>=10K and ncloc<100K
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d))),
+ // 2 docs with ncloc>=100K and ncloc<500K
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d))),
+ // 5 docs with ncloc>= 500K
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 500_000d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000_000d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 500_000d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 1_000_000d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000_000_000d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(NCLOC)).getFacets();
+
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 3L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 4L),
+ entry("100000.0-500000.0", 2L),
+ entry("500000.0-*", 5L));
+ }
+
+ @Test
+ public void facet_ncloc_is_sticky() {
+ addDocs(
+ // 1 docs with ncloc<1K
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d), newMeasure(DUPLICATION, 0d))),
+ // 2 docs with ncloc>=1K and ncloc<10K
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d), newMeasure(COVERAGE, 10d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d), newMeasure(COVERAGE, 20d), newMeasure(DUPLICATION, 0d))),
+ // 3 docs with ncloc>=10K and ncloc<100K
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d), newMeasure(COVERAGE, 31d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d), newMeasure(COVERAGE, 40d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d), newMeasure(COVERAGE, 50d), newMeasure(DUPLICATION, 0d))),
+ // 2 docs with ncloc>=100K and ncloc<500K
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d), newMeasure(COVERAGE, 71d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d), newMeasure(COVERAGE, 80d), newMeasure(DUPLICATION, 0d))),
+ // 1 docs with ncloc>= 500K
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d), newMeasure(COVERAGE, 81d), newMeasure(DUPLICATION, 20d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(NCLOC, Operator.LT, 10_000d))
+ .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
+ new SearchOptions().addFacets(NCLOC, COVERAGE)).getFacets();
+
+ // Sticky facet on ncloc does not take into account ncloc filter
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 1L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 3L),
+ entry("100000.0-500000.0", 2L),
+ entry("500000.0-*", 0L));
+ // But facet on coverage does well take into into filters
+ assertThat(facets.get(COVERAGE)).containsExactly(
+ entry("*-30.0", 3L),
+ entry("30.0-50.0", 0L),
+ entry("50.0-70.0", 0L),
+ entry("70.0-80.0", 0L),
+ entry("80.0-*", 0L));
+ }
+
+ @Test
+ public void facet_ncloc_contains_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+
+ // User can see these projects
+ addDocs(10L, null,
+ // docs with ncloc<1K
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 100d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d))),
+ // docs with ncloc>=1K and ncloc<10K
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d))));
+
+ // User cannot see these projects
+ addDocs(33L, null,
+ // doc with ncloc>=10K and ncloc<100K
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d))),
+ // doc with ncloc>=100K and ncloc<500K
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d))),
+ // doc with ncloc>= 500K
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(NCLOC)).getFacets();
+
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 3L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 0L),
+ entry("100000.0-500000.0", 0L),
+ entry("500000.0-*", 0L));
+ }
+
+ @Test
+ public void facet_coverage() {
+ addDocs(
+ // 3 docs with coverage<30%
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 29d))),
+ // 2 docs with coverage>=30% and coverage<50%
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 30d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 49d))),
+ // 4 docs with coverage>=50% and coverage<70%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 50d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 60d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 60d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 69d))),
+ // 2 docs with coverage>=70% and coverage<80%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 70d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d))),
+ // 5 docs with coverage>= 80%
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 90d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 90.5d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 100d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(COVERAGE)).getFacets();
+
+ assertThat(facets.get(COVERAGE)).containsExactly(
+ entry("*-30.0", 3L),
+ entry("30.0-50.0", 2L),
+ entry("50.0-70.0", 4L),
+ entry("70.0-80.0", 2L),
+ entry("80.0-*", 5L));
+ }
+
+ @Test
+ public void facet_coverage_is_sticky() {
+ addDocs(
+ // docs with coverage<30%
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 1_000d), newMeasure(COVERAGE, 10d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(NCLOC, 9_999d), newMeasure(COVERAGE, 20d), newMeasure(DUPLICATION, 0d))),
+ // docs with coverage>=30% and coverage<50%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 10_000d), newMeasure(COVERAGE, 31d), newMeasure(DUPLICATION, 0d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 11_000d), newMeasure(COVERAGE, 40d), newMeasure(DUPLICATION, 0d))),
+ // docs with coverage>=50% and coverage<70%
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 99_000d), newMeasure(COVERAGE, 50d), newMeasure(DUPLICATION, 0d))),
+ // docs with coverage>=70% and coverage<80%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000d), newMeasure(COVERAGE, 71d), newMeasure(DUPLICATION, 0d))),
+ // docs with coverage>= 80%
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 499_000d), newMeasure(COVERAGE, 80d), newMeasure(DUPLICATION, 15d))),
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 501_000d), newMeasure(COVERAGE, 810d), newMeasure(DUPLICATION, 20d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d))
+ .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
+ new SearchOptions().addFacets(COVERAGE, NCLOC)).getFacets();
+
+ // Sticky facet on coverage does not take into account coverage filter
+ assertThat(facets.get(COVERAGE)).containsExactly(
+ entry("*-30.0", 3L),
+ entry("30.0-50.0", 2L),
+ entry("50.0-70.0", 1L),
+ entry("70.0-80.0", 1L),
+ entry("80.0-*", 0L));
+ // But facet on ncloc does well take into into filters
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 1L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 0L),
+ entry("100000.0-500000.0", 0L),
+ entry("500000.0-*", 0L));
+ }
+
+ @Test
+ public void facet_coverage_contains_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+
+ // User can see these projects
+ addDocs(10L, null,
+ // docs with coverage<30%
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 29d))),
+ // docs with coverage>=30% and coverage<50%
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 30d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 49d))));
+
+ // User cannot see these projects
+ addDocs(33L, null,
+ // docs with coverage>=50% and coverage<70%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 50d))),
+ // docs with coverage>=70% and coverage<80%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 70d))),
+ // docs with coverage>= 80%
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(COVERAGE)).getFacets();
+
+ assertThat(facets.get(COVERAGE)).containsExactly(
+ entry("*-30.0", 3L),
+ entry("30.0-50.0", 2L),
+ entry("50.0-70.0", 0L),
+ entry("70.0-80.0", 0L),
+ entry("80.0-*", 0L));
+ }
+
+ @Test
+ public void facet_duplicated_lines_density() {
+ addDocs(
+ // 3 docs with duplication<3%
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 2.9d))),
+ // 2 docs with duplication>=3% and duplication<5%
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d))),
+ // 4 docs with duplication>=5% and duplication<10%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 6d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 6d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 9.9d))),
+ // 2 docs with duplication>=10% and duplication<20%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 19.9d))),
+ // 5 docs with duplication>= 20%
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 50d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 80d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 100d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(DUPLICATION)).getFacets();
+
+ assertThat(facets.get(DUPLICATION)).containsExactly(
+ entry("*-3.0", 3L),
+ entry("3.0-5.0", 2L),
+ entry("5.0-10.0", 4L),
+ entry("10.0-20.0", 2L),
+ entry("20.0-*", 5L));
+ }
+
+ @Test
+ public void facet_duplicated_lines_density_is_sticky() {
+ addDocs(
+ // docs with duplication<3%
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d), newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d))),
+ // docs with duplication>=3% and duplication<5%
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d), newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 0d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d), newMeasure(NCLOC, 6000d), newMeasure(COVERAGE, 0d))),
+ // docs with duplication>=5% and duplication<10%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d), newMeasure(NCLOC, 11000d), newMeasure(COVERAGE, 0d))),
+ // docs with duplication>=10% and duplication<20%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d), newMeasure(NCLOC, 120000d), newMeasure(COVERAGE, 10d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 19.9d), newMeasure(NCLOC, 130000d), newMeasure(COVERAGE, 20d))),
+ // docs with duplication>= 20%
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d), newMeasure(NCLOC, 1000000d), newMeasure(COVERAGE, 40d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d))
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
+ new SearchOptions().addFacets(DUPLICATION, NCLOC)).getFacets();
+
+ // Sticky facet on duplication does not take into account duplication filter
+ assertThat(facets.get(DUPLICATION)).containsExactly(
+ entry("*-3.0", 1L),
+ entry("3.0-5.0", 2L),
+ entry("5.0-10.0", 1L),
+ entry("10.0-20.0", 2L),
+ entry("20.0-*", 0L));
+ // But facet on ncloc does well take into into filters
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 1L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 1L),
+ entry("100000.0-500000.0", 0L),
+ entry("500000.0-*", 0L));
+ }
+
+ @Test
+ public void facet_duplicated_lines_density_contains_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+
+ // User can see these projects
+ addDocs(10L, null,
+ // docs with duplication<3%
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(DUPLICATION, 2.9d))),
+ // docs with duplication>=3% and duplication<5%
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 3d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(DUPLICATION, 4.9d))));
+
+ // User cannot see these projects
+ addDocs(33L, null,
+ // docs with duplication>=5% and duplication<10%
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 5d))),
+ // docs with duplication>=10% and duplication<20%
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 10d))),
+ // docs with duplication>= 20%
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(DUPLICATION, 20d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(DUPLICATION)).getFacets();
+
+ assertThat(facets.get(DUPLICATION)).containsExactly(
+ entry("*-3.0", 3L),
+ entry("3.0-5.0", 2L),
+ entry("5.0-10.0", 0L),
+ entry("10.0-20.0", 0L),
+ entry("20.0-*", 0L));
+ }
+
+ @Test
+ public void facet_maintainability_rating() {
+ addDocs(
+ // 3 docs with rating A
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ // 2 docs with rating B
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
+ // 4 docs with rating C
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
+ // 2 docs with rating D
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
+ // 5 docs with rating E
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(MAINTAINABILITY_RATING)).getFacets();
+
+ assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 4L),
+ entry("4", 2L),
+ entry("5", 5L));
+ }
+
+ @Test
+ public void facet_maintainability_rating_is_sticky() {
+ addDocs(
+ // docs with rating A
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 200d), newMeasure(COVERAGE, 0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d), newMeasure(NCLOC, 999d), newMeasure(COVERAGE, 0d))),
+ // docs with rating B
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d), newMeasure(NCLOC, 2000d), newMeasure(COVERAGE, 0d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d), newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 0d))),
+ // docs with rating C
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 20000d), newMeasure(COVERAGE, 0d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 30000d), newMeasure(COVERAGE, 0d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 40000d), newMeasure(COVERAGE, 0d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d), newMeasure(NCLOC, 50000d), newMeasure(COVERAGE, 0d))),
+ // docs with rating D
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d), newMeasure(NCLOC, 120000d), newMeasure(COVERAGE, 0d))),
+ // docs with rating E
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 600000d), newMeasure(COVERAGE, 40d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 700000d), newMeasure(COVERAGE, 50d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d), newMeasure(NCLOC, 800000d), newMeasure(COVERAGE, 60d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery()
+ .addMetricCriterion(new MetricCriterion(MAINTAINABILITY_RATING, Operator.LT, 3d))
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
+ new SearchOptions().addFacets(MAINTAINABILITY_RATING, NCLOC)).getFacets();
+
+ // Sticky facet on maintainability rating does not take into account maintainability rating filter
+ assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 4L),
+ entry("4", 1L),
+ entry("5", 0L));
+ // But facet on ncloc does well take into into filters
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 3L),
+ entry("1000.0-10000.0", 2L),
+ entry("10000.0-100000.0", 0L),
+ entry("100000.0-500000.0", 0L),
+ entry("500000.0-*", 0L));
+ }
+
+ @Test
+ public void facet_maintainability_rating_contains_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+
+ // User can see these projects
+ addDocs(10L, null,
+ // 3 docs with rating A
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 1d))),
+ // 2 docs with rating B
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 2d))));
+
+ // User cannot see these projects
+ addDocs(33L, null,
+ // docs with rating C
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 3d))),
+ // docs with rating D
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 4d))),
+ // docs with rating E
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(MAINTAINABILITY_RATING, 5d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(MAINTAINABILITY_RATING)).getFacets();
+
+ assertThat(facets.get(MAINTAINABILITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 0L),
+ entry("4", 0L),
+ entry("5", 0L));
+ }
+
+ @Test
+ public void facet_reliability_rating() {
+ addDocs(
+ // 3 docs with rating A
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 1d))),
+ // 2 docs with rating B
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 2d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 2d))),
+ // 4 docs with rating C
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 3d))),
+ // 2 docs with rating D
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 4d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 4d))),
+ // 5 docs with rating E
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(RELIABILITY_RATING, 5d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(RELIABILITY_RATING)).getFacets();
+
+ assertThat(facets.get(RELIABILITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 4L),
+ entry("4", 2L),
+ entry("5", 5L));
+ }
+
+ @Test
+ public void facet_security_rating() {
+ addDocs(
+ // 3 docs with rating A
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
+ newDoc("P12", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
+ newDoc("P13", "K1", "N1").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 1.0d))),
+ // 2 docs with rating B
+ newDoc("P21", "K2", "N2").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 2.0d))),
+ newDoc("P22", "K2", "N2").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 2.0d))),
+ // 4 docs with rating C
+ newDoc("P31", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
+ newDoc("P32", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
+ newDoc("P33", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
+ newDoc("P34", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 3.0d))),
+ // 2 docs with rating D
+ newDoc("P41", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 4.0d))),
+ newDoc("P42", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 4.0d))),
+ // 5 docs with rating E
+ newDoc("P51", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
+ newDoc("P52", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
+ newDoc("P53", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
+ newDoc("P54", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))),
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(SECURITY_RATING, 5.0d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(SECURITY_RATING)).getFacets();
+
+ assertThat(facets.get(SECURITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 4L),
+ entry("4", 2L),
+ entry("5", 5L));
+ }
+
+ @Test
+ public void facet_quality_gate() {
+ addDocs(
+ // 2 docs with QG OK
+ newDoc("P11", "K1", "N1").setQualityGate(OK.name()),
+ newDoc("P12", "K1", "N1").setQualityGate(OK.name()),
+ // 3 docs with QG WARN
+ newDoc("P21", "K1", "N1").setQualityGate(WARN.name()),
+ newDoc("P22", "K1", "N1").setQualityGate(WARN.name()),
+ newDoc("P23", "K1", "N1").setQualityGate(WARN.name()),
+ // 4 docs with QG ERROR
+ newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()));
+
+ LinkedHashMap<String, Long> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(ALERT_STATUS_KEY)).getFacets().get(ALERT_STATUS_KEY);
+
+ assertThat(result).containsExactly(
+ entry(ERROR.name(), 4L),
+ entry(WARN.name(), 3L),
+ entry(OK.name(), 2L));
+ }
+
+ @Test
+ public void facet_quality_gate_is_sticky() {
+ addDocs(
+ // 2 docs with QG OK
+ newDoc("P11", "K1", "N1").setQualityGate(OK.name()).setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE, 0d))),
+ newDoc("P12", "K1", "N1").setQualityGate(OK.name()).setMeasures(newArrayList(newMeasure(NCLOC, 10d), newMeasure(COVERAGE, 0d))),
+ // 3 docs with QG WARN
+ newDoc("P21", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
+ newDoc("P22", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
+ newDoc("P23", "K1", "N1").setQualityGate(WARN.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
+ // 4 docs with QG ERROR
+ newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 100d), newMeasure(COVERAGE, 0d))),
+ newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 5000d), newMeasure(COVERAGE, 40d))),
+ newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 12000d), newMeasure(COVERAGE, 50d))),
+ newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()).setMeasures(newArrayList(newMeasure(NCLOC, 13000d), newMeasure(COVERAGE, 60d))));
+
+ Facets facets = underTest.search(new ProjectMeasuresQuery()
+ .setQualityGateStatus(ERROR)
+ .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 55d)),
+ new SearchOptions().addFacets(ALERT_STATUS_KEY, NCLOC)).getFacets();
+
+ // Sticky facet on quality gate does not take into account quality gate filter
+ assertThat(facets.get(ALERT_STATUS_KEY)).containsOnly(
+ entry(OK.name(), 2L),
+ entry(WARN.name(), 3L),
+ entry(ERROR.name(), 3L));
+ // But facet on ncloc does well take into into filters
+ assertThat(facets.get(NCLOC)).containsExactly(
+ entry("*-1000.0", 1L),
+ entry("1000.0-10000.0", 1L),
+ entry("10000.0-100000.0", 1L),
+ entry("100000.0-500000.0", 0L),
+ entry("500000.0-*", 0L));
+ }
+
+ @Test
+ public void facet_quality_gate_contains_only_projects_authorized_for_user() throws Exception {
+ userSession.login("john").setUserId(10);
+
+ // User can see these projects
+ addDocs(10L, null,
+ // 2 docs with QG OK
+ newDoc("P11", "K1", "N1").setQualityGate(OK.name()),
+ newDoc("P12", "K1", "N1").setQualityGate(OK.name()),
+ // 3 docs with QG WARN
+ newDoc("P21", "K1", "N1").setQualityGate(WARN.name()),
+ newDoc("P22", "K1", "N1").setQualityGate(WARN.name()),
+ newDoc("P23", "K1", "N1").setQualityGate(WARN.name()));
+
+ // User cannot see these projects
+ addDocs(33L, null,
+ // 4 docs with QG ERROR
+ newDoc("P31", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P32", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P33", "K1", "N1").setQualityGate(ERROR.name()),
+ newDoc("P34", "K1", "N1").setQualityGate(ERROR.name()));
+
+ LinkedHashMap<String, Long> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(ALERT_STATUS_KEY)).getFacets().get(ALERT_STATUS_KEY);
+
+ assertThat(result).containsExactly(
+ entry(ERROR.name(), 0L),
+ entry(WARN.name(), 3L),
+ entry(OK.name(), 2L));
+ }
+
+ private void addDocs(ProjectMeasuresDoc... docs) {
+ addDocs(null, ANYONE, docs);
+ }
+
+ private void addDocs(@Nullable Long authorizeUser, @Nullable String authorizedGroup, ProjectMeasuresDoc... docs) {
+ try {
+ es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
+ for (ProjectMeasuresDoc doc : docs) {
+ authorizationIndexerTester.indexProjectPermission(doc.getId(),
+ authorizedGroup != null ? singletonList(authorizedGroup) : emptyList(),
+ authorizeUser != null ? singletonList(authorizeUser) : emptyList());
+ }
+ } catch (Exception e) {
+ Throwables.propagate(e);
+ }
+ }
+
+ private static ProjectMeasuresDoc newDoc(String uuid, String key, String name) {
+ return new ProjectMeasuresDoc()
+ .setId(uuid)
+ .setKey(key)
+ .setName(name);
+ }
+
+ private Map<String, Object> newMeasure(String key, Object value) {
+ return ImmutableMap.of("key", key, "value", value);
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import java.util.Date;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.junit.Rule;
+import org.junit.Test;
+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.SnapshotDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.measure.index.ProjectMeasuresDoc;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
+import org.sonar.server.permission.index.PermissionIndexerTester;
+
+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.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_AUTHORIZATION;
+import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexerTest {
+
+ private System2 system2 = System2.INSTANCE;
+
+ @Rule
+ public EsTester esTester = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
+
+ @Rule
+ public DbTester dbTester = DbTester.create(system2);
+
+ ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
+ PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(esTester);
+
+ ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(system2, dbTester.getDbClient(), esTester.client());
+
+ @Test
+ public void index_nothing() {
+ underTest.index();
+
+ assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isZero();
+ }
+
+ @Test
+ public void index_all_project() {
+ OrganizationDto organizationDto = dbTester.organizations().insert();
+ componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
+ componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
+ componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
+
+ underTest.index();
+
+ assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isEqualTo(3);
+ }
+
+ @Test
+ public void index_projects_even_when_no_analysis() {
+ ComponentDto project = componentDbTester.insertProject();
+
+ underTest.index();
+
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+ }
+
+ @Test
+ public void index_one_project() throws Exception {
+ OrganizationDto organizationDto = dbTester.organizations().insert();
+ ComponentDto project = newProjectDto(organizationDto);
+ componentDbTester.insertProjectAndSnapshot(project);
+ componentDbTester.insertProjectAndSnapshot(newProjectDto(organizationDto));
+
+ underTest.index(project.uuid());
+
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+ }
+
+ @Test
+ public void update_existing_document_when_indexing_one_project() throws Exception {
+ String uuid = "PROJECT-UUID";
+ esTester.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc()
+ .setId(uuid)
+ .setKey("Old Key")
+ .setName("Old Name")
+ .setAnalysedAt(new Date(1_000_000L)));
+ ComponentDto project = newProjectDto(dbTester.getDefaultOrganization(), uuid).setKey("New key").setName("New name");
+ SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
+
+ underTest.index(project.uuid());
+
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(uuid);
+ SearchRequestBuilder request = esTester.client()
+ .prepareSearch(INDEX_PROJECT_MEASURES)
+ .setTypes(TYPE_PROJECT_MEASURES)
+ .setQuery(boolQuery().must(matchAllQuery()).filter(
+ boolQuery()
+ .must(termQuery("_id", uuid))
+ .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_KEY, "New key"))
+ .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_NAME, "New name"))
+ .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, new Date(analysis.getCreatedAt())))));
+ assertThat(request.get().getHits()).hasSize(1);
+ }
+
+ @Test
+ public void delete_project() {
+ OrganizationDto organizationDto = dbTester.organizations().insert();
+ ComponentDto project1 = newProjectDto(organizationDto);
+ componentDbTester.insertProjectAndSnapshot(project1);
+ ComponentDto project2 = newProjectDto(organizationDto);
+ componentDbTester.insertProjectAndSnapshot(project2);
+ ComponentDto project3 = newProjectDto(organizationDto);
+ componentDbTester.insertProjectAndSnapshot(project3);
+ underTest.index();
+ authorizationIndexerTester.indexProjectPermission(project1.uuid(), emptyList(), emptyList());
+ authorizationIndexerTester.indexProjectPermission(project2.uuid(), emptyList(), emptyList());
+ authorizationIndexerTester.indexProjectPermission(project3.uuid(), emptyList(), emptyList());
+
+ underTest.deleteProject(project1.uuid());
+
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project2.uuid(), project3.uuid());
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION)).containsOnly(project2.uuid(), project3.uuid());
+ }
+
+ @Test
+ public void does_nothing_when_deleting_unknown_project() throws Exception {
+ ComponentDto project = newProjectDto(dbTester.organizations().insert());
+ componentDbTester.insertProjectAndSnapshot(project);
+ underTest.index();
+ authorizationIndexerTester.indexProjectPermission(project.uuid(), emptyList(), emptyList());
+
+ underTest.deleteProject("UNKNOWN");
+
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+ assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_AUTHORIZATION)).containsOnly(project.uuid());
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+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 static org.assertj.core.api.Java6Assertions.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 {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ ProjectMeasuresQuery underTest = new ProjectMeasuresQuery();
+
+ @Test
+ public void empty_query() throws Exception {
+ assertThat(underTest.getMetricCriteria()).isEmpty();
+ assertThat(underTest.hasQualityGateStatus()).isFalse();
+ }
+
+ @Test
+ public void add_metric_criterion() throws Exception {
+ underTest.addMetricCriterion(new MetricCriterion("coverage", EQ, 10d));
+
+ assertThat(underTest.getMetricCriteria())
+ .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
+ .containsOnly(tuple("coverage", EQ, 10d));
+ }
+
+ @Test
+ 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();
+ }
+
+ @Test
+ public void fail_to_create_operator_from_unknown_value() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ ProjectMeasuresQuery.Operator.valueOf("UNKNOWN");
+ }
+}
--- /dev/null
+/*
+ * 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.measure.index;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.measure.index.ProjectsEsModule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectsEsModuleTest {
+ @Test
+ public void verify_count_of_added_components() {
+ ComponentContainer container = new ComponentContainer();
+ new ProjectsEsModule().configure(container);
+ assertThat(container.size()).isEqualTo(3 + 2);
+ }
+}
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 org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
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 org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.index.IssueIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.permission.index.PermissionIndexer;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleTesting;
-import org.sonar.server.component.es.ProjectMeasuresDoc;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.IssueDocTesting;
import org.sonar.server.issue.index.IssueIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresDoc;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
import org.sonar.server.rule.index.RuleDoc;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.view.index.ViewDoc;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.component.ComponentCleanerService;
import org.sonar.server.component.ComponentFinder;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.issue.IssueDocTesting;
import org.sonar.server.issue.index.IssueAuthorizationDoc;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.test.index.TestDoc;
import org.sonar.server.test.index.TestIndexDefinition;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.component.ComponentCleanerService;
import org.sonar.server.component.ComponentFinder;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.issue.IssueDocTesting;
import org.sonar.server.issue.index.IssueAuthorizationDoc;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.test.index.TestDoc;
import org.sonar.server.test.index.TestIndexDefinition;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentService;
-import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.component.es.ProjectMeasuresIndexer;
import org.sonar.server.es.EsTester;
import org.sonar.server.language.LanguageTesting;
+import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
import org.sonar.server.qualityprofile.QProfileLookup;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.qualityprofile.QProfileProjectOperations;