aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-10-24 15:39:26 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-10-24 15:39:26 +0200
commit7fbdae0b91dd971fe4f5f5991987369319faf3de (patch)
tree804aab8bdfc75df7366d623e6e4dc9a512448481 /server/sonar-server
parentbe7fe2686f3c4cb62c5351e81f6a51d3983e8547 (diff)
downloadsonarqube-7fbdae0b91dd971fe4f5f5991987369319faf3de.tar.gz
sonarqube-7fbdae0b91dd971fe4f5f5991987369319faf3de.zip
SONAR-8323 api/components/search_projects should return "sticky" facets
Diffstat (limited to 'server/sonar-server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java85
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java388
2 files changed, 434 insertions, 39 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
index f6767705457..00368bc78a1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
@@ -19,8 +19,12 @@
*/
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;
@@ -37,6 +41,7 @@ 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;
@@ -45,6 +50,7 @@ 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;
@@ -76,29 +82,54 @@ public class ProjectMeasuresIndex extends BaseIndex {
}
public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
- QueryBuilder esQuery = createEsQuery(query);
-
- SearchRequestBuilder request = getClient()
+ SearchRequestBuilder requestBuilder = getClient()
.prepareSearch(INDEX_PROJECT_MEASURES)
.setTypes(TYPE_PROJECT_MEASURES)
.setFetchSource(false)
- .setQuery(esQuery)
.setFrom(searchOptions.getOffset())
.setSize(searchOptions.getLimit())
- .addAggregation(createQualityGateFacet())
- .addAggregation(createRatingFacet(SQALE_RATING_KEY))
- .addAggregation(createRatingFacet(RELIABILITY_RATING_KEY))
- .addAggregation(createRatingFacet(SECURITY_RATING_KEY))
- .addAggregation(createRangeFacet(DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d)))
- .addAggregation(createRangeFacet(COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d)))
- .addAggregation(createRangeFacet(NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d)))
.addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
- return new SearchIdResult<>(request.get(), id -> id);
+ BoolQueryBuilder esFilter = boolQuery();
+ Map<String, QueryBuilder> filters = createFilters(query);
+ filters.values().forEach(esFilter::must);
+ requestBuilder.setQuery(esFilter);
+
+ addFacets(requestBuilder, filters);
+ return new SearchIdResult<>(requestBuilder.get(), id -> id);
+ }
+
+ private static void addFacets(SearchRequestBuilder esSearch, Map<String, QueryBuilder> filters) {
+ addRangeFacet(esSearch, NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d), filters);
+ addRangeFacet(esSearch, DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d), filters);
+ addRangeFacet(esSearch, COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d), filters);
+ addRatingFacet(esSearch, SQALE_RATING_KEY, filters);
+ addRatingFacet(esSearch, RELIABILITY_RATING_KEY, filters);
+ addRatingFacet(esSearch, SECURITY_RATING_KEY, filters);
+ 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);
+ RangeBuilder rangeAgg = AggregationBuilders.range(metricKey)
+ .field(FIELD_VALUE);
final int lastIndex = thresholds.size() - 1;
IntStream.range(0, thresholds.size())
.forEach(i -> {
@@ -126,7 +157,7 @@ public class ProjectMeasuresIndex extends BaseIndex {
.subAggregation(
AggregationBuilders.filter("filter_" + metricKey)
.filter(termsQuery(FIELD_KEY, metricKey))
- .subAggregation(AggregationBuilders.filters(metricKey)
+ .subAggregation(filters(metricKey)
.filter("1", termQuery(FIELD_VALUE, 1d))
.filter("2", termQuery(FIELD_VALUE, 2d))
.filter("3", termQuery(FIELD_VALUE, 3d))
@@ -141,16 +172,24 @@ public class ProjectMeasuresIndex extends BaseIndex {
.filter(Metric.Level.OK.name(), termQuery(FIELD_QUALITY_GATE, Metric.Level.OK.name()));
}
- private QueryBuilder createEsQuery(ProjectMeasuresQuery query) {
- BoolQueryBuilder filters = boolQuery()
- .must(createAuthorizationFilter());
- query.getMetricCriteria().stream()
- .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery()
- .filter(termQuery(FIELD_KEY, criterion.getMetricKey()))
- .filter(toValueQuery(criterion))))
- .forEach(filters::filter);
+ 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.filter(termQuery(FIELD_QUALITY_GATE, query.getQualityGateStatus().name()));
+ filters.put(ALERT_STATUS_KEY, termQuery(FIELD_QUALITY_GATE, query.getQualityGateStatus().name()));
}
return filters;
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
index b5c07e0d4bc..2ea96edc3cd 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
@@ -30,7 +30,6 @@ import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.MapSettings;
-import org.sonar.api.measures.Metric.Level;
import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
import org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
import org.sonar.server.es.EsTester;
@@ -45,7 +44,9 @@ 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.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;
@@ -175,7 +176,8 @@ public class ProjectMeasuresIndexTest {
ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
.addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d))
- .addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 10_000d));
+ .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");
@@ -250,7 +252,7 @@ public class ProjectMeasuresIndexTest {
public void facet_ncloc() {
addDocs(
// 3 docs with ncloc<1K
- newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d))),
+ newDoc("P11", "K1", "N1").setMeasures(newArrayList(newMeasure(NCLOC, 0d), newMeasure(COVERAGE, 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
@@ -282,6 +284,78 @@ public class ProjectMeasuresIndexTest {
}
@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()).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()).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%
@@ -317,6 +391,78 @@ public class ProjectMeasuresIndexTest {
}
@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()).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()).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%
@@ -352,6 +498,76 @@ public class ProjectMeasuresIndexTest {
}
@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()).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()).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
@@ -387,6 +603,82 @@ public class ProjectMeasuresIndexTest {
}
@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()).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()).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
@@ -460,25 +752,89 @@ public class ProjectMeasuresIndexTest {
public void facet_quality_gate() {
addDocs(
// 2 docs with QG OK
- newDoc("P11", "K1", "N1").setQualityGate(Level.OK.name()),
- newDoc("P12", "K1", "N1").setQualityGate(Level.OK.name()),
+ 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()).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(Level.WARN.name()),
- newDoc("P22", "K1", "N1").setQualityGate(Level.WARN.name()),
- newDoc("P23", "K1", "N1").setQualityGate(Level.WARN.name()),
+ 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()).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(Level.ERROR.name()),
- newDoc("P32", "K1", "N1").setQualityGate(Level.ERROR.name()),
- newDoc("P33", "K1", "N1").setQualityGate(Level.ERROR.name()),
- newDoc("P34", "K1", "N1").setQualityGate(Level.ERROR.name()));
+ 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()).getFacets().get(ALERT_STATUS_KEY);
assertThat(result).containsExactly(
- entry(Level.ERROR.name(), 4L),
- entry(Level.WARN.name(), 3L),
- entry(Level.OK.name(), 2L)
- );
+ entry(ERROR.name(), 0L),
+ entry(WARN.name(), 3L),
+ entry(OK.name(), 2L));
}
private void addDocs(ProjectMeasuresDoc... docs) {