]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7562 WS api/measures/component_tree sort alert_status and level metrics
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 6 May 2016 16:40:40 +0000 (18:40 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 10 May 2016 13:06:04 +0000 (15:06 +0200)
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeSort.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeSortTest.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java

index 1f7141e72e5c56873a433054b9b07bb1a9999d4b..8b2d4c831fe6ccd10e68f2086ec8ce9bf3e3baac 100644 (file)
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.Metric.ValueType;
 import org.sonar.db.component.ComponentDtoWithSnapshotId;
 import org.sonar.db.measure.MeasureDto;
@@ -45,7 +46,6 @@ 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.FLOAT;
 import static org.sonar.api.measures.Metric.ValueType.INT;
-import static org.sonar.api.measures.Metric.ValueType.LEVEL;
 import static org.sonar.api.measures.Metric.ValueType.MILLISEC;
 import static org.sonar.api.measures.Metric.ValueType.PERCENT;
 import static org.sonar.api.measures.Metric.ValueType.RATING;
@@ -60,7 +60,7 @@ import static org.sonar.server.measure.ws.ComponentTreeAction.QUALIFIER_SORT;
 class ComponentTreeSort {
 
   private static final Set<ValueType> NUMERIC_VALUE_TYPES = EnumSet.of(BOOL, FLOAT, INT, MILLISEC, WORK_DUR, PERCENT, RATING);
-  private static final Set<ValueType> TEXTUAL_VALUE_TYPES = EnumSet.of(DATA, DISTRIB, LEVEL, STRING);
+  private static final Set<ValueType> TEXTUAL_VALUE_TYPES = EnumSet.of(DATA, DISTRIB, STRING);
 
   private ComponentTreeSort() {
     // static method only
@@ -129,6 +129,8 @@ class ComponentTreeSort {
       return numericalMetricOrdering(isAscending, metric, measuresByComponentUuidAndMetric);
     } else if (TEXTUAL_VALUE_TYPES.contains(metricValueType)) {
       return stringOrdering(isAscending, new ComponentDtoWithSnapshotIdToTextualMeasureValue(metric, measuresByComponentUuidAndMetric));
+    } else if (ValueType.LEVEL.equals(ValueType.valueOf(metric.getValueType()))) {
+      return levelMetricOrdering(isAscending, metric, measuresByComponentUuidAndMetric);
     }
 
     throw new IllegalStateException("Unrecognized metric value type: " + metric.getValueType());
@@ -172,6 +174,18 @@ class ComponentTreeSort {
     return ordering.nullsLast().onResultOf(new ComponentDtoWithSnapshotIdToMeasureVariationValue(metric, measuresByComponentUuidAndMetric, request.getMetricPeriodSort()));
   }
 
+  private static Ordering<ComponentDtoWithSnapshotId> levelMetricOrdering(boolean isAscending, @Nullable MetricDto metric,
+    Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric) {
+    Ordering<Integer> ordering = Ordering.natural();
+
+    // inverse the order of org.sonar.api.measures.Metric.Level
+    if (isAscending) {
+      ordering = ordering.reverse();
+    }
+
+    return ordering.nullsLast().onResultOf(new ComponentDtoWithSnapshotIdToLevelIndex(metric, measuresByComponentUuidAndMetric));
+  }
+
   private static class ComponentDtoWithSnapshotIdToNumericalMeasureValue implements Function<ComponentDtoWithSnapshotId, Double> {
     private final MetricDto metric;
     private final Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric;
@@ -193,6 +207,27 @@ class ComponentTreeSort {
     }
   }
 
+  private static class ComponentDtoWithSnapshotIdToLevelIndex implements Function<ComponentDtoWithSnapshotId, Integer> {
+    private final MetricDto metric;
+    private final Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric;
+
+    private ComponentDtoWithSnapshotIdToLevelIndex(@Nullable MetricDto metric,
+      Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric) {
+      this.metric = metric;
+      this.measuresByComponentUuidAndMetric = measuresByComponentUuidAndMetric;
+    }
+
+    @Override
+    public Integer apply(@Nonnull ComponentDtoWithSnapshotId input) {
+      MeasureDto measure = measuresByComponentUuidAndMetric.get(input.uuid(), metric);
+      if (measure == null || measure.getData() == null) {
+        return null;
+      }
+
+      return Metric.Level.names().indexOf(measure.getData());
+    }
+  }
+
   private static class ComponentDtoWithSnapshotIdToMeasureVariationValue implements Function<ComponentDtoWithSnapshotId, Double> {
     private final MetricDto metric;
     private final Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric;
index f57686501eb8a7da24f36c41263cbe7ce8de3b7f..af5da0663698a54de5088f45624d3acf78b8fab7 100644 (file)
@@ -25,7 +25,9 @@ import java.util.List;
 import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric.ValueType;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.component.ComponentDtoWithSnapshotId;
 import org.sonar.db.measure.MeasureDto;
@@ -72,7 +74,7 @@ public class ComponentTreeSortTest {
 
     metrics = newArrayList(violationsMetric, sqaleIndexMetric);
 
-    measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(), 1);
+    measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(), 2);
     // same number than path field
     double currentValue = 9;
     for (ComponentDtoWithSnapshotId component : components) {
@@ -135,6 +137,35 @@ public class ComponentTreeSortTest {
       .containsExactly("path-9", "path-8", "path-7", "path-6", "path-5", "path-4", "path-3", "path-2", "path-1", "path-without-measure");
   }
 
+  @Test
+  public void sort_by_alert_status_ascending() {
+    components = newArrayList(
+      newComponentWithoutSnapshotId("PROJECT OK 1", Qualifiers.PROJECT, "PROJECT_OK_PATH_1"),
+      newComponentWithoutSnapshotId("PROJECT WARN 1", Qualifiers.PROJECT, "PROJECT_WARN_PATH_1"),
+      newComponentWithoutSnapshotId("PROJECT ERROR 1", Qualifiers.PROJECT, "PROJECT_ERROR_PATH_1"),
+      newComponentWithoutSnapshotId("PROJECT OK 2", Qualifiers.PROJECT, "PROJECT_OK_PATH_2"),
+      newComponentWithoutSnapshotId("PROJECT WARN 2", Qualifiers.PROJECT, "PROJECT_WARN_PATH_2"),
+      newComponentWithoutSnapshotId("PROJECT ERROR 2", Qualifiers.PROJECT, "PROJECT_ERROR_PATH_2"));
+    metrics = singletonList(newMetricDto()
+      .setKey(CoreMetrics.ALERT_STATUS_KEY)
+      .setValueType(ValueType.LEVEL.name()));
+    measuresByComponentUuidAndMetric = HashBasedTable.create();
+    List<String> statuses = newArrayList("OK", "WARN", "ERROR");
+    for (int i = 0; i < components.size(); i++) {
+      ComponentDtoWithSnapshotId component = components.get(i);
+      String alertStatus = statuses.get(i % 3);
+      measuresByComponentUuidAndMetric.put(component.uuid(), metrics.get(0), new MeasureDto().setData(alertStatus));
+    }
+    ComponentTreeWsRequest wsRequest = newRequest(newArrayList(METRIC_SORT, NAME_SORT), true, CoreMetrics.ALERT_STATUS_KEY);
+
+    List<ComponentDtoWithSnapshotId> result = sortComponents(wsRequest);
+
+    assertThat(result).extracting("name").containsExactly(
+      "PROJECT ERROR 1", "PROJECT ERROR 2",
+      "PROJECT WARN 1", "PROJECT WARN 2",
+      "PROJECT OK 1", "PROJECT OK 2");
+  }
+
   @Test
   public void sort_by_numerical_metric_period_1_key_ascending() {
     components.add(newComponentWithoutSnapshotId("name-without-measure", "qualifier-without-measure", "path-without-measure"));
index cf139075a5bef46ac070a5cffc66e9723870a320..d27e62e34ae6dfb1ba8930b7e2f5d65bfc1b2ee6 100644 (file)
@@ -105,6 +105,14 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
   public enum Level {
     OK("Green"), WARN("Orange"), ERROR("Red");
 
+    private static final List<String> NAMES = Lists.transform(Arrays.asList(values()), new Function<Level, String>() {
+      @Nonnull
+      @Override
+      public String apply(@Nonnull Level level) {
+        return level.name();
+      }
+    });
+
     private String colorName;
 
     Level(String colorName) {
@@ -116,13 +124,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
     }
 
     public static List<String> names() {
-      return Lists.transform(Arrays.asList(values()), new Function<Level, String>() {
-        @Nonnull
-        @Override
-        public String apply(@Nonnull Level level) {
-          return level.name();
-        }
-      });
+      return NAMES;
     }
   }