*/
package org.sonar.server.component.es;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.stream.IntStream;
import java.util.Set;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.aggregations.bucket.range.RangeBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
import org.sonar.server.es.BaseIndex;
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.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_MEASURES;
import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY;
import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE;
public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
QueryBuilder esQuery = createEsQuery(query);
- AggregationBuilder locAggregation = AggregationBuilders.nested("nested_" + NCLOC_KEY)
- .path("measures")
- .subAggregation(
- AggregationBuilders.filter("filter_" + NCLOC_KEY)
- .filter(termsQuery("measures.key", NCLOC_KEY))
- .subAggregation(AggregationBuilders.range(NCLOC_KEY)
- .field("measures.value")
- .addUnboundedTo(1_000d)
- .addRange(1_000d, 10_000d)
- .addRange(10_000d, 100_000d)
- .addRange(100_000d, 500_000d)
- .addUnboundedFrom(500_000)));
-
SearchRequestBuilder request = getClient()
.prepareSearch(INDEX_PROJECT_MEASURES)
.setTypes(TYPE_PROJECT_MEASURES)
.setQuery(esQuery)
.setFrom(searchOptions.getOffset())
.setSize(searchOptions.getLimit())
- .addAggregation(locAggregation)
+ .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)))
+ .addAggregation(createRatingFacet(SQALE_RATING_KEY))
+ .addAggregation(createRatingFacet(RELIABILITY_RATING_KEY))
+ .addAggregation(createRatingFacet(SECURITY_RATING_KEY))
.addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
return new SearchIdResult<>(request.get(), id -> id);
}
+ 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 QueryBuilder createEsQuery(ProjectMeasuresQuery query) {
BoolQueryBuilder filters = boolQuery()
.must(createAuthorizationFilter());
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
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)))
- );
+ newDoc("P55", "K3", "N3").setMeasures(newArrayList(newMeasure(NCLOC, 100_000_000_000d))));
Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getFacets();
entry("1000.0-10000.0", 2L),
entry("10000.0-100000.0", 4L),
entry("100000.0-500000.0", 2L),
- entry("500000.0-*", 5L)
- );
+ entry("500000.0-*", 5L));
+ }
+
+ @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()).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_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()).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_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()).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_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()).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()).getFacets();
+
+ assertThat(facets.get(SECURITY_RATING)).containsExactly(
+ entry("1", 3L),
+ entry("2", 2L),
+ entry("3", 4L),
+ entry("4", 2L),
+ entry("5", 5L));
}
private void addDocs(ProjectMeasuresDoc... docs) {