aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>2017-05-23 11:56:52 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-06-09 08:26:48 +0200
commitc72da32c69c14f71b68c81f46adfe219ecc40c9e (patch)
treedebc362aa44c8fa7ada206661984684a0e66fac3
parent7a9dd7414a10abcec0c3f8e4297ba5d7ff72bcc5 (diff)
downloadsonarqube-c72da32c69c14f71b68c81f46adfe219ecc40c9e.tar.gz
sonarqube-c72da32c69c14f71b68c81f46adfe219ecc40c9e.zip
SONAR-9260 allow to filter on NO_DATA in project search
-rw-r--r--it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java30
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java31
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java26
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java34
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java80
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTextSearchTest.java10
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java36
11 files changed, 237 insertions, 51 deletions
diff --git a/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java b/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java
index 5070fd3c5c9..4d4b50369a3 100644
--- a/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java
+++ b/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java
@@ -86,7 +86,7 @@ public class SearchProjectsTest {
@Test
public void filter_projects_by_measure_values() throws Exception {
String projectKey = newProjectKey();
- analyzeProject(projectKey, "shared/xoo-sample");
+ analyzeProject(projectKey,"shared/xoo-sample");
verifyFilterMatches(projectKey, "ncloc > 1");
verifyFilterMatches(projectKey, "ncloc > 1 and comment_lines < 10000");
@@ -94,6 +94,15 @@ public class SearchProjectsTest {
}
@Test
+ public void find_projects_with_no_data() throws Exception {
+ String projectKey = newProjectKey();
+ analyzeProject(projectKey,"shared/xoo-sample");
+
+ verifyFilterMatches(projectKey, "coverage = NO_DATA");
+ verifyFilterDoesNotMatch("ncloc = NO_DATA");
+ }
+
+ @Test
public void filter_by_text_query() throws IOException {
orchestrator.executeBuild(create(projectDir("shared/xoo-sample"), "sonar.projectKey", "project1", "sonar.projectName", "apachee"));
orchestrator.executeBuild(create(projectDir("shared/xoo-sample"), "sonar.projectKey", "project2", "sonar.projectName", "Apache"));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
index 08d8e55e3dc..87c54c55c84 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
@@ -48,6 +48,7 @@ class ProjectMeasuresQueryFactory {
public static final String IS_FAVORITE_CRITERION = "isFavorite";
public static final String QUERY_KEY = "query";
+ private static final String NO_DATA = "NO_DATA";
private static final Map<String, BiConsumer<Criterion, ProjectMeasuresQuery>> CRITERION_PROCESSORS = ImmutableMap.<String, BiConsumer<Criterion, ProjectMeasuresQuery>>builder()
.put(IS_FAVORITE_CRITERION.toLowerCase(ENGLISH), (criterion, query) -> processIsFavorite(criterion))
@@ -132,7 +133,15 @@ class ProjectMeasuresQueryFactory {
private static void processMetricCriterion(Criterion criterion, ProjectMeasuresQuery query) {
checkOperator(criterion);
checkValue(criterion);
- query.addMetricCriterion(new MetricCriterion(criterion.getKey().toLowerCase(ENGLISH), criterion.getOperator(), parseValue(criterion.getValue())));
+ query.addMetricCriterion(createMetricCriterion(criterion, criterion.getKey().toLowerCase(ENGLISH), criterion.getOperator()));
+ }
+
+ private static MetricCriterion createMetricCriterion(Criterion criterion, String metricKey, Operator operator) {
+ if (NO_DATA.equalsIgnoreCase(criterion.getValue())) {
+ checkArgument(EQ.equals(operator), "%s can only be used with equals operator", NO_DATA);
+ return MetricCriterion.createNoData(metricKey);
+ }
+ return MetricCriterion.create(metricKey, operator, parseValue(criterion.getValue()));
}
private static double parseValue(String value) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java
index e8cb88abc4f..fb51e78a818 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java
@@ -109,7 +109,9 @@ public class SearchProjectsAction implements ComponentsWsAction {
.setResponseExample(getClass().getResource("search_projects-example.json"))
.setChangelog(
new Change("6.4", format("The '%s' parameter accepts '%s' to filter by language", FILTER_LANGUAGES, PARAM_FILTER)),
- new Change("6.4", "The 'visibility' field is added"))
+ new Change("6.4", "The 'visibility' field is added"),
+ new Change("6.5", "The 'filter' parameter now allows 'NO_DATA' as value for numeric metrics")
+ )
.setHandler(this);
action.createFieldsParam(POSSIBLE_FIELDS)
@@ -133,6 +135,8 @@ public class SearchProjectsAction implements ComponentsWsAction {
" <code>filter=\"alert_status = ERROR and isFavorite and coverage >= 60 and coverage < 80\"</code></li>" +
" <li>to filter projects with a reliability, security and maintainability rating equals or worse than B:<br>" +
" <code>filter=\"reliability_rating>=2 and security_rating>=2 and sqale_rating>=2\"</code></li>" +
+ " <li>to filter projects without duplication data:<br>" +
+ " <code>filter=\"duplicated_lines_density = NO_DATA\"</code></li>" +
"</ul>" +
"To filter on project name or key, use the 'query' keyword, for instance : <code>filter='query = \"Sonar\"'</code>.<br>" +
"<br>" +
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java
index 596323a4187..8fb31c3ee65 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java
@@ -284,9 +284,7 @@ public class ProjectMeasuresIndex {
BoolQueryBuilder metricFilters = boolQuery();
entry.getValue()
.stream()
- .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery()
- .filter(termQuery(FIELD_MEASURES_KEY, criterion.getMetricKey()))
- .filter(toValueQuery(criterion))))
+ .map(criterion -> toQuery(criterion))
.forEach(metricFilters::must);
filters.put(entry.getKey(), metricFilters);
});
@@ -318,6 +316,15 @@ public class ProjectMeasuresIndex {
return Optional.of(ProjectsTextSearchQueryFactory.createQuery(queryText.get()));
}
+ private static QueryBuilder toQuery(MetricCriterion criterion) {
+ if (criterion.isNoData()) {
+ return boolQuery().mustNot(nestedQuery(FIELD_MEASURES, termQuery(FIELD_MEASURES_KEY, criterion.getMetricKey())));
+ }
+ return nestedQuery(FIELD_MEASURES, boolQuery()
+ .filter(termQuery(FIELD_MEASURES_KEY, criterion.getMetricKey()))
+ .filter(toValueQuery(criterion)));
+ }
+
private static QueryBuilder toValueQuery(MetricCriterion criterion) {
String fieldName = FIELD_MEASURES_VALUE;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java
index f0847e8d061..ba07efe7d75 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java
@@ -26,6 +26,7 @@ import java.util.Set;
import javax.annotation.Nullable;
import org.sonar.api.measures.Metric;
+import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.server.component.ws.FilterParser.Operator;
@@ -127,12 +128,13 @@ public class ProjectMeasuresQuery {
public static class MetricCriterion {
private final String metricKey;
private final Operator operator;
- private final double value;
+ @Nullable
+ private final Double value;
- public MetricCriterion(String metricKey, Operator operator, double value) {
- this.metricKey = requireNonNull(metricKey);
- this.operator = requireNonNull(operator);
- this.value = requireNonNull(value);
+ private MetricCriterion(String metricKey, @Nullable Operator operator, @Nullable Double value) {
+ this.metricKey = metricKey;
+ this.operator = operator;
+ this.value = value;
}
public String getMetricKey() {
@@ -140,12 +142,30 @@ public class ProjectMeasuresQuery {
}
public Operator getOperator() {
+ checkDataAvailable();
return operator;
}
public double getValue() {
+ checkDataAvailable();
return value;
}
+
+ public boolean isNoData() {
+ return value == null;
+ }
+
+ public static MetricCriterion createNoData(String metricKey) {
+ return new MetricCriterion(requireNonNull(metricKey), null, null);
+ }
+
+ public static MetricCriterion create(String metricKey, Operator operator, double value) {
+ return new MetricCriterion(requireNonNull(metricKey), requireNonNull(operator), value);
+ }
+
+ private void checkDataAvailable() {
+ checkState(!isNoData(), "The criterion for metric %s has no data", metricKey);
+ }
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java
index 023d39899f2..a6a25b6691d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java
@@ -274,6 +274,37 @@ public class ProjectMeasuresQueryFactoryTest {
}
@Test
+ public void filter_no_data() throws Exception {
+ List<Criterion> criteria = singletonList(Criterion.builder().setKey("duplicated_lines_density").setOperator(EQ).setValue("NO_DATA").build());
+
+ ProjectMeasuresQuery underTest = newProjectMeasuresQuery(criteria, emptySet());
+
+ assertThat(underTest.getMetricCriteria())
+ .extracting(MetricCriterion::getMetricKey, MetricCriterion::isNoData)
+ .containsOnly(tuple("duplicated_lines_density", true));
+ }
+
+ @Test
+ public void fail_to_use_no_data_with_operator_lower_than() throws Exception {
+ List<Criterion> criteria = singletonList(Criterion.builder().setKey("duplicated_lines_density").setOperator(LT).setValue("NO_DATA").build());
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("NO_DATA can only be used with equals operator");
+
+ newProjectMeasuresQuery(criteria, emptySet());
+ }
+
+ @Test
+ public void filter_no_data_with_other_case() throws Exception {
+ List<Criterion> criteria = singletonList(Criterion.builder().setKey("duplicated_lines_density").setOperator(EQ).setValue("nO_DaTa").build());
+
+ ProjectMeasuresQuery underTest = newProjectMeasuresQuery(criteria, emptySet());
+
+ assertThat(underTest.getMetricCriteria())
+ .extracting(MetricCriterion::getMetricKey, MetricCriterion::isNoData)
+ .containsOnly(tuple("duplicated_lines_density", true));
+ }
+
+ @Test
public void accept_empty_query() throws Exception {
ProjectMeasuresQuery result = newProjectMeasuresQuery(emptyList(), emptySet());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java
index c6e0e6fef9e..9220c27e19a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java
@@ -62,7 +62,7 @@ public class ProjectMeasuresQueryValidatorTest {
@Test
public void does_not_fail_when_metric_criteria_contains_an_existing_metric() throws Exception {
insertValidMetric("ncloc");
- ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion("ncloc", GT, 10d));
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.create("ncloc", GT, 10d));
underTest.validate(dbSession, query);
}
@@ -71,7 +71,7 @@ public class ProjectMeasuresQueryValidatorTest {
public void does_not_fail_when_sort_is_by_name() throws Exception {
insertValidMetric("ncloc");
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("ncloc", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("ncloc", GT, 10d))
.setSort("name");
underTest.validate(dbSession, query);
@@ -82,7 +82,7 @@ public class ProjectMeasuresQueryValidatorTest {
insertValidMetric("ncloc");
insertValidMetric("debt");
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("ncloc", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("ncloc", GT, 10d))
.setSort("debt");
underTest.validate(dbSession, query);
@@ -96,11 +96,11 @@ public class ProjectMeasuresQueryValidatorTest {
insertMetric(createValidMetric("distrib").setValueType(DISTRIB.name()));
insertMetric(createValidMetric("string").setValueType(STRING.name()));
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("data", GT, 10d))
- .addMetricCriterion(new MetricCriterion("distrib", EQ, 11d))
- .addMetricCriterion(new MetricCriterion("ncloc", LTE, 20d))
- .addMetricCriterion(new MetricCriterion("debt", LT, 20d))
- .addMetricCriterion(new MetricCriterion("string", EQ, 40d));
+ .addMetricCriterion(MetricCriterion.create("data", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("distrib", EQ, 11d))
+ .addMetricCriterion(MetricCriterion.create("ncloc", LTE, 20d))
+ .addMetricCriterion(MetricCriterion.create("debt", LT, 20d))
+ .addMetricCriterion(MetricCriterion.create("string", EQ, 40d));
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Following metrics are not numeric : [data, distrib, string]");
@@ -112,7 +112,7 @@ public class ProjectMeasuresQueryValidatorTest {
insertMetric(createValidMetric("ncloc").setEnabled(false));
insertMetric(createValidMetric("debt").setEnabled(false));
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("ncloc", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("ncloc", GT, 10d))
.setSort("debt");
expectedException.expect(IllegalArgumentException.class);
@@ -124,7 +124,7 @@ public class ProjectMeasuresQueryValidatorTest {
public void fail_when_metric_does_not_exists() throws Exception {
insertValidMetric("ncloc");
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("unknown", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("unknown", GT, 10d))
.setSort("debt");
expectedException.expect(IllegalArgumentException.class);
@@ -136,9 +136,9 @@ public class ProjectMeasuresQueryValidatorTest {
public void return_all_unknown_metrics() throws Exception {
insertValidMetric("ncloc");
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion("debt", GT, 10d))
- .addMetricCriterion(new MetricCriterion("ncloc", LTE, 20d))
- .addMetricCriterion(new MetricCriterion("coverage", GT, 30d))
+ .addMetricCriterion(MetricCriterion.create("debt", GT, 10d))
+ .addMetricCriterion(MetricCriterion.create("ncloc", LTE, 20d))
+ .addMetricCriterion(MetricCriterion.create("coverage", GT, 30d))
.setSort("duplications");
expectedException.expect(IllegalArgumentException.class);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
index 02fb375157d..f54ef4b2e94 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
@@ -149,7 +149,9 @@ public class SearchProjectsActionTest {
assertThat(def.params().stream().map(Param::key).collect(toList())).containsOnly("organization", "filter", "facets", "s", "asc", "ps", "p", "f");
assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactlyInAnyOrder(
tuple("6.4", "The 'languages' parameter accepts 'filter' to filter by language"),
- tuple("6.4", "The 'visibility' field is added"));
+ tuple("6.4", "The 'visibility' field is added"),
+ tuple("6.5", "The 'filter' parameter now allows 'NO_DATA' as value for numeric metrics")
+ );
Param organization = def.param("organization");
assertThat(organization.isRequired()).isFalse();
@@ -268,7 +270,7 @@ public class SearchProjectsActionTest {
userSession.logIn();
OrganizationDto organization1 = db.organizations().insert();
OrganizationDto organization2 = db.organizations().insert();
- MetricDto coverage = db.measureDbTester().insertMetric(c -> c.setKey(COVERAGE).setValueType(INT.name()));
+ MetricDto coverage = db.measureDbTester().insertMetric(c -> c.setKey(COVERAGE).setValueType(PERCENT.name()));
MetricDto ncloc = db.measureDbTester().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
ComponentDto project1 = insertProject(organization1, new Measure(coverage, c -> c.setValue(81d)), new Measure(ncloc, c -> c.setValue(10_000d)));
ComponentDto project2 = insertProject(organization1, new Measure(coverage, c -> c.setValue(80d)), new Measure(ncloc, c -> c.setValue(10_000d)));
@@ -402,6 +404,34 @@ public class SearchProjectsActionTest {
}
@Test
+ public void filter_projects_by_no_duplication() {
+ userSession.logIn();
+ OrganizationDto organizationDto = db.organizations().insert();
+ MetricDto coverage = db.measureDbTester().insertMetric(c -> c.setKey(COVERAGE).setValueType(PERCENT.name()));
+ MetricDto duplications = db.measureDbTester().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()));
+ ComponentDto project1 = insertProject(organizationDto, new Measure(coverage, c -> c.setValue(10d)));
+ ComponentDto project2 = insertProject(organizationDto, new Measure(duplications, c -> c.setValue(0d)));
+ ComponentDto project3 = insertProject(organizationDto, new Measure(duplications, c -> c.setValue(79d)));
+
+ SearchProjectsWsResponse result = call(request.setFilter("duplicated_lines_density = NO_DATA"));
+
+ assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey());
+ }
+
+ @Test
+ public void filter_projects_by_no_duplication_should_not_return_projects_with_duplication() {
+ userSession.logIn();
+ OrganizationDto organizationDto = db.organizations().insert();
+ MetricDto coverage = db.measureDbTester().insertMetric(c -> c.setKey(COVERAGE).setValueType(PERCENT.name()));
+ MetricDto duplications = db.measureDbTester().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()));
+ insertProject(organizationDto, new Measure(duplications, c -> c.setValue(10d)), new Measure(coverage, c -> c.setValue(50d)));
+
+ SearchProjectsWsResponse result = call(request.setFilter("duplicated_lines_density = NO_DATA"));
+
+ assertThat(result.getComponentsList()).extracting(Component::getKey).isEmpty();
+ }
+
+ @Test
public void filter_projects_by_new_duplications() {
userSession.logIn();
OrganizationDto organizationDto = db.organizations().insert();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java
index 6802c072051..3affb0a44be 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java
@@ -215,7 +215,7 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT3, COVERAGE, 81d, NCLOC, 10_000d));
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 80d));
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LT, 80d));
assertResults(query, PROJECT1);
}
@@ -228,7 +228,7 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT3, COVERAGE, 81d, NCLOC, 10_000d));
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d));
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LTE, 80d));
assertResults(query, PROJECT1, PROJECT2);
}
@@ -240,10 +240,10 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT2, COVERAGE, 80d, NCLOC, 30_001d),
newDoc(PROJECT3, COVERAGE, 80d, NCLOC, 30_001d));
- ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 30_000d));
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.create(NCLOC, Operator.GT, 30_000d));
assertResults(query, PROJECT2, PROJECT3);
- query = new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 100_000d));
+ query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.create(NCLOC, Operator.GT, 100_000d));
assertNoResults(query);
}
@@ -254,10 +254,10 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT2, COVERAGE, 80d, NCLOC, 30_001d),
newDoc(PROJECT3, COVERAGE, 80d, NCLOC, 30_001d));
- ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 30_001d));
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.create(NCLOC, Operator.GTE, 30_001d));
assertResults(query, PROJECT2, PROJECT3);
- query = new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GTE, 100_000d));
+ query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.create(NCLOC, Operator.GTE, 100_000d));
assertNoResults(query);
}
@@ -269,12 +269,54 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT3, COVERAGE, 81d, NCLOC, 10_000d));
ProjectMeasuresQuery query = new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.EQ, 80d));
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.EQ, 80d));
assertResults(query, PROJECT2);
}
@Test
+ public void filter_on_no_data_with_several_projects() {
+ index(
+ newDoc(PROJECT1, NCLOC, 1d),
+ newDoc(PROJECT2, DUPLICATION, 80d));
+
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery()
+ .addMetricCriterion(MetricCriterion.createNoData(DUPLICATION));
+
+ assertResults(query, PROJECT1);
+ }
+
+ @Test
+ public void filter_on_no_data_should_not_return_projects_with_data_and_other_measures() {
+ ComponentDto project = ComponentTesting.newPrivateProjectDto(ORG);
+ index(newDoc(project, DUPLICATION, 80d, NCLOC, 1d));
+
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.createNoData(DUPLICATION));
+
+ assertNoResults(query);
+ }
+
+ @Test
+ public void filter_on_no_data_should_not_return_projects_with_data() {
+ ComponentDto project = ComponentTesting.newPrivateProjectDto(ORG);
+ index(newDoc(project, DUPLICATION, 80d));
+
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.createNoData(DUPLICATION));
+
+ assertNoResults(query);
+ }
+
+ @Test
+ public void filter_on_no_data_should_return_projects_with_no_data() {
+ ComponentDto project = ComponentTesting.newPrivateProjectDto(ORG);
+ index(newDoc(project, NCLOC, 1d));
+
+ ProjectMeasuresQuery query = new ProjectMeasuresQuery().addMetricCriterion(MetricCriterion.createNoData(DUPLICATION));
+
+ assertResults(query, project);
+ }
+
+ @Test
public void filter_on_several_metrics() {
index(
newDoc(PROJECT1, COVERAGE, 81d, NCLOC, 10_001d),
@@ -282,9 +324,9 @@ public class ProjectMeasuresIndexTest {
newDoc(PROJECT3, COVERAGE, 79d, 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));
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LTE, 80d))
+ .addMetricCriterion(MetricCriterion.create(NCLOC, Operator.GT, 10_000d))
+ .addMetricCriterion(MetricCriterion.create(NCLOC, Operator.LT, 11_000d));
assertResults(esQuery, PROJECT2);
}
@@ -479,8 +521,8 @@ public class ProjectMeasuresIndexTest {
newDoc(NCLOC, 501_000d, COVERAGE, 81d, DUPLICATION, 20d));
Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(NCLOC, Operator.LT, 10_000d))
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
+ .addMetricCriterion(MetricCriterion.create(NCLOC, Operator.LT, 10_000d))
+ .addMetricCriterion(MetricCriterion.create(DUPLICATION, Operator.LT, 10d)),
new SearchOptions().addFacets(NCLOC, COVERAGE)).getFacets();
// Sticky facet on ncloc does not take into account ncloc filter
@@ -620,8 +662,8 @@ public class ProjectMeasuresIndexTest {
newDoc(NCLOC, 501_000d, COVERAGE, 810d, DUPLICATION, 20d));
Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d))
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d)),
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LT, 30d))
+ .addMetricCriterion(MetricCriterion.create(DUPLICATION, Operator.LT, 10d)),
new SearchOptions().addFacets(COVERAGE, NCLOC)).getFacets();
// Sticky facet on coverage does not take into account coverage filter
@@ -764,8 +806,8 @@ public class ProjectMeasuresIndexTest {
newDoc(DUPLICATION, 20d, NCLOC, 1000000d, COVERAGE, 40d));
Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(DUPLICATION, Operator.LT, 10d))
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
+ .addMetricCriterion(MetricCriterion.create(DUPLICATION, Operator.LT, 10d))
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LT, 30d)),
new SearchOptions().addFacets(DUPLICATION, NCLOC)).getFacets();
// Sticky facet on duplication does not take into account duplication filter
@@ -922,8 +964,8 @@ public class ProjectMeasuresIndexTest {
newDoc(metricKey, 5d, NCLOC, 800000d, COVERAGE, 60d));
Facets facets = underTest.search(new ProjectMeasuresQuery()
- .addMetricCriterion(new MetricCriterion(metricKey, Operator.LT, 3d))
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 30d)),
+ .addMetricCriterion(MetricCriterion.create(metricKey, Operator.LT, 3d))
+ .addMetricCriterion(MetricCriterion.create(COVERAGE, Operator.LT, 30d)),
new SearchOptions().addFacets(metricKey, NCLOC)).getFacets();
// Sticky facet on maintainability rating does not take into account maintainability rating filter
@@ -1017,7 +1059,7 @@ public class ProjectMeasuresIndexTest {
Facets facets = underTest.search(new ProjectMeasuresQuery()
.setQualityGateStatus(ERROR)
- .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LT, 55d)),
+ .addMetricCriterion(MetricCriterion.create(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
diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTextSearchTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTextSearchTest.java
index b34c381afed..c7f2f9bbbf7 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTextSearchTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTextSearchTest.java
@@ -280,11 +280,11 @@ public class ProjectMeasuresIndexTextSearchTest {
newDoc(newPrivateProjectDto(ORG).setUuid("project3").setName("Apache").setKey("project3"), NCLOC, 50_000d),
newDoc(newPrivateProjectDto(ORG).setUuid("project4").setName("Apache").setKey("project4"), NCLOC, 60_000d));
- assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(new MetricCriterion(NCLOC, GT, 20_000d)), "project3", "project4", "project2");
- assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(new MetricCriterion(NCLOC, LT, 55_000d)), "project3", "project2");
- assertResults(new ProjectMeasuresQuery().setQueryText("PAC").addMetricCriterion(new MetricCriterion(NCLOC, LT, 55_000d)), "project3", "project2");
- assertResults(new ProjectMeasuresQuery().setQueryText("apachee").addMetricCriterion(new MetricCriterion(NCLOC, GT, 30_000d)), "project2");
- assertResults(new ProjectMeasuresQuery().setQueryText("unknown").addMetricCriterion(new MetricCriterion(NCLOC, GT, 20_000d)));
+ assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 20_000d)), "project3", "project4", "project2");
+ assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(MetricCriterion.create(NCLOC, LT, 55_000d)), "project3", "project2");
+ assertResults(new ProjectMeasuresQuery().setQueryText("PAC").addMetricCriterion(MetricCriterion.create(NCLOC, LT, 55_000d)), "project3", "project2");
+ assertResults(new ProjectMeasuresQuery().setQueryText("apachee").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 30_000d)), "project2");
+ assertResults(new ProjectMeasuresQuery().setQueryText("unknown").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 20_000d)));
}
private void index(ProjectMeasuresDoc... docs) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java
index 27529639601..d72676cf991 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java
@@ -46,7 +46,7 @@ public class ProjectMeasuresQueryTest {
@Test
public void add_metric_criterion() throws Exception {
- underTest.addMetricCriterion(new MetricCriterion("coverage", EQ, 10d));
+ underTest.addMetricCriterion(MetricCriterion.create("coverage", EQ, 10d));
assertThat(underTest.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -54,6 +54,24 @@ public class ProjectMeasuresQueryTest {
}
@Test
+ public void isNoData_returns_true_when_no_data() throws Exception {
+ underTest.addMetricCriterion(MetricCriterion.createNoData("coverage"));
+
+ assertThat(underTest.getMetricCriteria())
+ .extracting(MetricCriterion::getMetricKey, MetricCriterion::isNoData)
+ .containsOnly(tuple("coverage", true));
+ }
+
+ @Test
+ public void isNoData_returns_false_when_data_exists() throws Exception {
+ underTest.addMetricCriterion(MetricCriterion.create("coverage", EQ, 10d));
+
+ assertThat(underTest.getMetricCriteria())
+ .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::isNoData)
+ .containsOnly(tuple("coverage", EQ, false));
+ }
+
+ @Test
public void set_quality_gate_status() throws Exception {
underTest.setQualityGateStatus(OK);
@@ -72,4 +90,20 @@ public class ProjectMeasuresQueryTest {
underTest.setSort(null);
}
+
+ @Test
+ public void fail_to_get_value_when_no_data() throws Exception {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("The criterion for metric coverage has no data");
+
+ MetricCriterion.createNoData("coverage").getValue();
+ }
+
+ @Test
+ public void fail_to_get_operator_when_no_data() throws Exception {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("The criterion for metric coverage has no data");
+
+ MetricCriterion.createNoData("coverage").getOperator();
+ }
}