]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8307 Filter by Quality Gate in WS api/components/search_projects 1318/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 19 Oct 2016 12:59:50 +0000 (14:59 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 20 Oct 2016 08:40:03 +0000 (10:40 +0200)
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresDoc.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexDefinition.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresQuery.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresResultSetIterator.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidator.java
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresQueryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresResultSetIteratorTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java

index 48dbe0e5203023233818d9a4edc38bea9ae014d8..030feef06e0e578f24f1c4c414cba172c1d51f61 100644 (file)
@@ -104,4 +104,12 @@ public class ProjectMeasuresDoc extends BaseDoc {
     return this;
   }
 
+  public String getQualityGate() {
+    return getField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE);
+  }
+
+  public ProjectMeasuresDoc setQualityGate(String s) {
+    setField(ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE, s);
+    return this;
+  }
 }
index dd24c4a167e48b5505029cd3e51a6ce5c15d8697..df2269ab79e54bec47daa3084fa7ad3e86425468 100644 (file)
@@ -23,14 +23,13 @@ import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+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 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;
@@ -38,6 +37,7 @@ import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD
 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_PROJECT_MEASURES;
 
@@ -51,13 +51,7 @@ public class ProjectMeasuresIndex extends BaseIndex {
   }
 
   public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
-    BoolQueryBuilder metricFilters = boolQuery();
-    query.getMetricCriteria().stream()
-      .map(criteria -> nestedQuery(FIELD_MEASURES, boolQuery()
-        .filter(termQuery(FIELD_KEY, criteria.getMetricKey()))
-        .filter(toValueQuery(criteria))))
-      .forEach(metricFilters::filter);
-    QueryBuilder esQuery = query.getMetricCriteria().isEmpty() ? matchAllQuery() : metricFilters;
+    QueryBuilder esQuery = createEsQuery(query);
 
     SearchRequestBuilder request = getClient()
       .prepareSearch(INDEX_PROJECT_MEASURES)
@@ -71,16 +65,31 @@ public class ProjectMeasuresIndex extends BaseIndex {
     return new SearchIdResult<>(request.get(), id -> id);
   }
 
-  private static QueryBuilder toValueQuery(MetricCriteria criteria) {
+  private static QueryBuilder createEsQuery(ProjectMeasuresQuery query) {
+    BoolQueryBuilder filters = boolQuery();
+    query.getMetricCriteria().stream()
+      .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery()
+        .filter(termQuery(FIELD_KEY, criterion.getMetricKey()))
+        .filter(toValueQuery(criterion))))
+      .forEach(filters::filter);
+    if (query.hasQualityGateStatus()) {
+      filters.filter(termQuery(FIELD_QUALITY_GATE, query.getQualityGateStatus().name()));
+    }
+    return filters;
+  }
+
+  private static QueryBuilder toValueQuery(MetricCriterion criterion) {
     String fieldName = FIELD_VALUE;
 
-    switch (criteria.getOperator()) {
+    switch (criterion.getOperator()) {
       case GT:
-        return rangeQuery(fieldName).gt(criteria.getValue());
+        return rangeQuery(fieldName).gt(criterion.getValue());
       case LTE:
-        return rangeQuery(fieldName).lte(criteria.getValue());
+        return rangeQuery(fieldName).lte(criterion.getValue());
+      case EQ:
+        return termQuery(fieldName, criterion.getValue());
       default:
-        throw new IllegalStateException("Metric criteria non supported: " + criteria.getOperator().name());
+        throw new IllegalStateException("Metric criteria non supported: " + criterion.getOperator().name());
     }
 
   }
index a8ba6675e5949a0ba4a816b37e9b0fdbb29a78de..3c454d7d0960a03e25847fb38bdbaf990454f22e 100644 (file)
@@ -30,6 +30,7 @@ public class ProjectMeasuresIndexDefinition implements IndexDefinition {
   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";
@@ -49,6 +50,7 @@ public class ProjectMeasuresIndexDefinition implements IndexDefinition {
     NewIndex.NewIndexType mapping = index.createType(TYPE_PROJECT_MEASURES);
     mapping.stringFieldBuilder(FIELD_KEY).disableNorms().build();
     mapping.stringFieldBuilder(FIELD_NAME).enableSorting().enableGramSearch().build();
+    mapping.stringFieldBuilder(FIELD_QUALITY_GATE).build();
     mapping.createDateTimeField(FIELD_ANALYSED_AT);
     mapping.nestedFieldBuilder(FIELD_MEASURES)
       .addStringFied(FIELD_MEASURES_KEY)
index b64d67070ca111d827c6219e4b3e50df7feb8637..6725b1cf60483aadb452b5529c9d376e58743c98 100644 (file)
@@ -22,23 +22,40 @@ package org.sonar.server.component.es;
 
 import java.util.ArrayList;
 import java.util.List;
+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<MetricCriteria> metricCriteria = new ArrayList<>();
+  private List<MetricCriterion> metricCriteria = new ArrayList<>();
+  private Metric.Level qualityGateStatus;
 
-  public ProjectMeasuresQuery addMetricCriterion(MetricCriteria metricCriteria) {
-    this.metricCriteria.add(metricCriteria);
+  public ProjectMeasuresQuery addMetricCriterion(MetricCriterion metricCriterion) {
+    this.metricCriteria.add(metricCriterion);
     return this;
   }
 
-  public List<MetricCriteria> getMetricCriteria() {
+  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 enum Operator {
     LTE("<="), GT(">"), EQ("=");
 
@@ -60,12 +77,12 @@ public class ProjectMeasuresQuery {
     }
   }
 
-  public static class MetricCriteria {
+  public static class MetricCriterion {
     private final String metricKey;
     private final Operator operator;
     private final double value;
 
-    public MetricCriteria(String metricKey, Operator operator, double value) {
+    public MetricCriterion(String metricKey, Operator operator, double value) {
       this.metricKey = requireNonNull(metricKey);
       this.operator = requireNonNull(operator);
       this.value = requireNonNull(value);
index 845a66a7c261beed8d50c50eb60d05942dbcdf5a..fe6798aa8f2f416a2024a665499b772a0509eadd 100644 (file)
@@ -27,6 +27,7 @@ import java.sql.SQLException;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.resources.Qualifiers;
@@ -35,6 +36,7 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.ResultSetIterator;
 
+import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
 import static org.sonar.api.measures.Metric.ValueType.DATA;
 import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
 import static org.sonar.db.DatabaseUtils.repeatCondition;
@@ -55,10 +57,10 @@ public class ProjectMeasuresResultSetIterator extends ResultSetIterator<ProjectM
     "WHERE m.val_type NOT IN ('" + METRICS_JOINER.join(DATA.name(), DISTRIB.name()) + "') " +
     "AND m.enabled=? AND m.hidden=?";
 
-  private static final String SQL_MEASURES = "SELECT pm.metric_id, pm.value, pm.variation_value_1 FROM project_measures pm " +
+  private static final String SQL_MEASURES = "SELECT pm.metric_id, pm.value, pm.variation_value_1, pm.text_value FROM project_measures pm " +
     "WHERE pm.component_uuid = ? AND pm.analysis_uuid = ? " +
     "AND pm.metric_id IN ({metricIds}) " +
-    "AND (pm.value IS NOT NULL OR pm.variation_value_1 IS NOT NULL) " +
+    "AND (pm.value IS NOT NULL OR pm.variation_value_1 IS NOT NULL OR pm.text_value IS NOT NULL) " +
     "AND pm.person_id IS NULL ";
 
   private final DbSession dbSession;
@@ -127,29 +129,45 @@ public class ProjectMeasuresResultSetIterator extends ResultSetIterator<ProjectM
   @Override
   protected ProjectMeasuresDoc read(ResultSet rs) throws SQLException {
     String projectUuid = rs.getString(1);
+    Measures measures = selectMeasures(projectUuid, rs.getString(4));
     ProjectMeasuresDoc doc = new ProjectMeasuresDoc()
       .setId(projectUuid)
       .setKey(rs.getString(2))
       .setName(rs.getString(3))
-      .setMeasuresFromMap(selectMeasures(projectUuid, rs.getString(4)));
+      .setQualityGate(measures.qualityGateStatus)
+      .setMeasuresFromMap(measures.numericMeasures);
     long analysisDate = rs.getLong(5);
     doc.setAnalysedAt(rs.wasNull() ? null : new Date(analysisDate));
     return doc;
   }
 
-  private Map<String, Object> selectMeasures(String projectUuid, String analysisUuid) {
-    Map<String, Object> measures = new HashMap<>();
+  private Measures selectMeasures(String projectUuid, String analysisUuid) {
+    Measures measures = new Measures();
     try (PreparedStatement stmt = createMeasuresStatement(projectUuid, analysisUuid);
       ResultSet rs = stmt.executeQuery()) {
       while (rs.next()) {
-        String metricKey = metrics.get(rs.getLong(1));
-        Double value = metricKey.startsWith("new_") ? getDouble(rs, 3) : getDouble(rs, 2);
-        measures.put(metricKey, value);
+        readMeasure(rs, measures);
       }
       return measures;
-    } catch (SQLException e) {
-      throw new IllegalStateException("Fail to execute request to select measures", e);
+    } catch (Exception e) {
+      throw new IllegalStateException(String.format("Fail to execute request to select measures of project %s, analysis %s", projectUuid, analysisUuid), e);
+    }
+  }
+
+  private void readMeasure(ResultSet rs, Measures measures) throws SQLException {
+    String metricKey = metrics.get(rs.getLong(1));
+    Optional<Double> value = metricKey.startsWith("new_") ? getDouble(rs, 3) : getDouble(rs, 2);
+    if (value.isPresent()) {
+      measures.addNumericMeasure(metricKey, value.get());
+      return;
+    } else if (ALERT_STATUS_KEY.equals(metricKey)) {
+      String textValue = rs.getString(4);
+      if (!rs.wasNull()) {
+        measures.setQualityGateStatus(textValue);
+        return;
+      }
     }
+    throw new IllegalArgumentException("Measure has no value");
   }
 
   private PreparedStatement createMeasuresStatement(String projectUuid, String analysisUuid) throws SQLException {
@@ -165,16 +183,31 @@ public class ProjectMeasuresResultSetIterator extends ResultSetIterator<ProjectM
     return stmt;
   }
 
-  private static Double getDouble(ResultSet rs, int index) {
+  private static Optional<Double> getDouble(ResultSet rs, int index) {
     try {
       Double value = rs.getDouble(index);
       if (!rs.wasNull()) {
-        return value;
+        return Optional.of(value);
       }
-      throw new IllegalStateException("No value");
+      return Optional.empty();
     } catch (SQLException e) {
       throw new IllegalStateException("Fail to get double value", e);
     }
   }
 
+  private static class Measures {
+    private Map<String, Object> numericMeasures = new HashMap<>();
+    private String qualityGateStatus;
+
+    Measures addNumericMeasure(String metricKey, double value) {
+      numericMeasures.put(metricKey, value);
+      return this;
+    }
+
+    Measures setQualityGateStatus(String qualityGateStatus) {
+      this.qualityGateStatus = qualityGateStatus;
+      return this;
+    }
+  }
+
 }
index 8fb948d41dd548d8517307bfb475a2dd7121db96..e3ddbac901ce2d01a3f6fdb11f3cc0ed8487450b 100644 (file)
@@ -24,11 +24,13 @@ import com.google.common.base.Splitter;
 import java.util.regex.Matcher;
 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 static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Locale.ENGLISH;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+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;
 
 class ProjectMeasuresQueryFactory {
@@ -58,10 +60,16 @@ class ProjectMeasuresQueryFactory {
       checkArgument(matcher.find() && matcher.groupCount() == 3, "Criterion should have a metric, an operator and a value");
       String metric = matcher.group(1).toLowerCase(ENGLISH);
       Operator operator = Operator.getByValue(matcher.group(2));
-      double value = Double.parseDouble(matcher.group(3));
-      query.addMetricCriterion(new MetricCriteria(metric, operator, value));
+      String value = matcher.group(3);
+      if (ALERT_STATUS_KEY.equals(metric)) {
+        checkArgument(operator.equals(Operator.EQ), "Only equals operator is available for quality gate criteria");
+        query.setQualityGateStatus(Level.valueOf(value));
+      } else {
+        double doubleValue = Double.parseDouble(matcher.group(3));
+        query.addMetricCriterion(new MetricCriterion(metric, operator, doubleValue));
+      }
     } catch (Exception e) {
-      throw new IllegalArgumentException(String.format("Invalid criterion '%s'", criterion), e);
+      throw new IllegalArgumentException(String.format("Invalid criterion '%s'", criterion.trim()), e);
     }
   }
 
index d6dc330aef65a9aefc36783fdf1f8cb1a5d0520a..3030431e5daf53855fc4d782210871c7758c9085 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.metric.MetricDto;
 import org.sonar.server.component.es.ProjectMeasuresQuery;
 
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
 
 public class ProjectMeasuresQueryValidator {
 
@@ -40,7 +40,7 @@ public class ProjectMeasuresQueryValidator {
   }
 
   public void validate(DbSession dbSession, ProjectMeasuresQuery query) {
-    List<String> metricKeys = new ArrayList<>(query.getMetricCriteria().stream().map(MetricCriteria::getMetricKey).collect(Collectors.toSet()));
+    List<String> metricKeys = new ArrayList<>(query.getMetricCriteria().stream().map(MetricCriterion::getMetricKey).collect(Collectors.toSet()));
     List<MetricDto> dbMetrics = dbClient.metricDao().selectByKeys(dbSession, metricKeys);
     if (dbMetrics.size() == metricKeys.size()) {
       return;
index 2306d6c18a844543af6eea540106de420cbbd895..eaa0344eb1faeb5a134b92047bf329ec12cd4f59 100644 (file)
@@ -27,7 +27,7 @@ import java.util.stream.IntStream;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.config.MapSettings;
-import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+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.SearchIdResult;
@@ -35,6 +35,7 @@ import org.sonar.server.es.SearchOptions;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.Metric.Level.OK;
 import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
 import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
 
@@ -84,7 +85,7 @@ public class ProjectMeasuresIndexTest {
       newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
 
     ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
-      .addMetricCriterion(new MetricCriteria(COVERAGE, Operator.LTE, 80d));
+      .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d));
     List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
 
     assertThat(result).containsExactly("P1", "P2");
@@ -97,12 +98,26 @@ public class ProjectMeasuresIndexTest {
       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 MetricCriteria(NCLOC, Operator.GT, 30_000d)),
+    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 MetricCriteria(NCLOC, Operator.GT, 100_000d)),
+    assertThat(underTest.search(new ProjectMeasuresQuery().addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 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(
@@ -111,13 +126,26 @@ public class ProjectMeasuresIndexTest {
       newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))));
 
     ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
-      .addMetricCriterion(new MetricCriteria(COVERAGE, Operator.LTE, 80d))
-      .addMetricCriterion(new MetricCriteria(NCLOC, Operator.GT, 10_000d));
+      .addMetricCriterion(new MetricCriterion(COVERAGE, Operator.LTE, 80d))
+      .addMetricCriterion(new MetricCriterion(NCLOC, Operator.GT, 10_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");
+  }
+
   private void addDocs(ProjectMeasuresDoc... docs) {
     try {
       es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
@@ -133,7 +161,7 @@ public class ProjectMeasuresIndexTest {
       .setName(name);
   }
 
-  private Map<String, Object> newMeasure(String key, double value) {
+  private Map<String, Object> newMeasure(String key, Object value) {
     return ImmutableMap.of("key", key, "value", value);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresQueryTest.java
new file mode 100644 (file)
index 0000000..d55f77e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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");
+  }
+}
index b70092e911643fcc935bb0ac8a08b12d7976bc62..09086ad2a3008758b7cb11d35fa18b3fea3e2d04 100644 (file)
@@ -45,10 +45,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.measures.Metric.ValueType.DATA;
 import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
 import static org.sonar.api.measures.Metric.ValueType.INT;
+import static org.sonar.api.measures.Metric.ValueType.LEVEL;
 import static org.sonar.db.component.ComponentTesting.newDeveloper;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
 import static org.sonar.db.component.ComponentTesting.newView;
 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
+import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.WARN;
 
 public class ProjectMeasuresResultSetIteratorTest {
 
@@ -101,6 +103,19 @@ public class ProjectMeasuresResultSetIteratorTest {
     assertThat(doc.getMeasures()).containsOnly(ImmutableMap.of("key", "new_lines", "value", 10d));
   }
 
+  @Test
+  public void return_quality_gate_status_measure() throws Exception {
+    MetricDto metric = insertMetric("alert_status", LEVEL);
+    ComponentDto project = newProjectDto();
+    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
+    insertMeasure(project, analysis, metric, WARN.name());
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById();
+
+    assertThat(docsById).hasSize(1);
+    assertThat(docsById.get(project.uuid()).getQualityGate()).isEqualTo("WARN");
+  }
+
   @Test
   public void does_not_return_none_numeric_metrics() throws Exception {
     MetricDto dataMetric = insertMetric("data", DATA);
@@ -268,8 +283,15 @@ public class ProjectMeasuresResultSetIteratorTest {
     return insertMeasure(project, analysis, metric, null, value);
   }
 
+  private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, String value) {
+    return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setData(value));
+  }
+
   private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, @Nullable Double value, @Nullable Double leakValue) {
-    MeasureDto measure = MeasureTesting.newMeasureDto(metric, project, analysis).setValue(value).setVariation(1, leakValue);
+    return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setValue(value).setVariation(1, leakValue));
+  }
+
+  private MeasureDto insertMeasure(MeasureDto measure) {
     dbClient.measureDao().insert(dbSession, measure);
     dbSession.commit();
     return measure;
index dbe87ed2398a82953aa60a7f24d2bbfdc8c607f1..1550e03a0713d4b71f309b9108a47dda25bf3782 100644 (file)
@@ -28,9 +28,10 @@ import org.sonar.test.TestUtils;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+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.test.ExceptionCauseMatcher.hasType;
 
 public class ProjectMeasuresQueryFactoryTest {
@@ -43,7 +44,7 @@ public class ProjectMeasuresQueryFactoryTest {
     ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10 and coverage <= 80");
 
     assertThat(query.getMetricCriteria())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(
         tuple("ncloc", Operator.GT, 10d),
         tuple("coverage", Operator.LTE, 80d));
@@ -54,10 +55,23 @@ public class ProjectMeasuresQueryFactoryTest {
     ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc = 10");
 
     assertThat(query.getMetricCriteria())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(tuple("ncloc", Operator.EQ, 10d));
   }
 
+  @Test
+  public void create_query_on_quality_gate() throws Exception {
+    ProjectMeasuresQuery query = newProjectMeasuresQuery("alert_status = OK");
+
+    assertThat(query.getQualityGateStatus().name()).isEqualTo(OK.name());
+  }
+
+  @Test
+  public void fail_to_create_query_on_quality_gate_when_operator_is_not_equal() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    newProjectMeasuresQuery("alert_status > OK");
+  }
+
   @Test
   public void search_is_case_insensitive() throws Exception {
     assertThat(newProjectMeasuresQuery("ncloc > 10 AnD coverage <= 80 AND debt = 10 AND issues = 20").getMetricCriteria()).hasSize(4);
@@ -66,7 +80,7 @@ public class ProjectMeasuresQueryFactoryTest {
   @Test
   public void convert_metric_to_lower_case() throws Exception {
     assertThat(newProjectMeasuresQuery("NCLOC > 10 AND coVERage <= 80").getMetricCriteria())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(
         tuple("ncloc", Operator.GT, 10d),
         tuple("coverage", Operator.LTE, 80d));
@@ -75,7 +89,7 @@ public class ProjectMeasuresQueryFactoryTest {
   @Test
   public void ignore_white_spaces() throws Exception {
     assertThat(newProjectMeasuresQuery("   ncloc    >    10   ").getMetricCriteria())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(tuple("ncloc", Operator.GT, 10d));
   }