]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6620 remove Dto and BatchReport object from MeasureRepository
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 4 Jun 2015 16:24:02 +0000 (18:24 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 11 Jun 2015 08:28:34 +0000 (10:28 +0200)
23 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepository.java
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepository.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/metric/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateEventsStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityGateEventsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityProfileEventsStepTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/measure/MeasureRepositoryImplTest/shared.xml [new file with mode: 0644]

index 160bdac97afedd9980698b8169fa4e432dd8bcef..f3386a42786acd557494ec6c7954acca6b37b8e4 100644 (file)
@@ -51,6 +51,7 @@ import org.sonar.server.computation.issue.SourceLinesCache;
 import org.sonar.server.computation.language.PlatformLanguageRepository;
 import org.sonar.server.computation.measure.MeasureRepositoryImpl;
 import org.sonar.server.computation.measure.MetricCache;
+import org.sonar.server.computation.metric.MetricRepositoryImpl;
 import org.sonar.server.computation.period.PeriodsHolderImpl;
 import org.sonar.server.computation.step.ComputationStep;
 import org.sonar.server.computation.step.ComputationSteps;
@@ -123,18 +124,19 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
     return Arrays.asList(
       ActivityManager.class,
 
+      // holders
+      BatchReportDirectoryHolderImpl.class,
       TreeRootHolderImpl.class,
+      PeriodsHolderImpl.class,
 
       BatchReportReaderImpl.class,
 
-      BatchReportDirectoryHolderImpl.class,
-
       // repositories
       PlatformLanguageRepository.class,
+      MetricRepositoryImpl.class,
       MeasureRepositoryImpl.class,
       EventRepositoryImpl.class,
       ProjectSettingsRepository.class,
-      PeriodsHolderImpl.class,
       DbIdsRepository.class,
 
       // issues
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java
new file mode 100644 (file)
index 0000000..35a6966
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Optional;
+import java.util.Objects;
+import javax.annotation.Nullable;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.metric.Metric;
+
+public class BatchMeasureToMeasure {
+
+  public Optional<Measure> toMeasure(@Nullable BatchReport.Measure batchMeasure, Metric metric) {
+    Objects.requireNonNull(metric);
+    if (batchMeasure == null) {
+      return Optional.absent();
+    }
+
+    String data = batchMeasure.hasStringValue() ? batchMeasure.getStringValue() : null;
+    switch (metric.getMetricType().getValueType()) {
+      case INT:
+        return toIntegerMeasure(batchMeasure, data);
+      case LONG:
+        return toLongMeasure(batchMeasure, data);
+      case DOUBLE:
+        return toDoubleMeasure(batchMeasure, data);
+      case BOOLEAN:
+        return toBooleanMeasure(batchMeasure, data);
+      case STRING:
+        return toStringMeasure(batchMeasure);
+      case LEVEL:
+        return toLevelMeasure(batchMeasure);
+      case NO_VALUE:
+        return toNoValueMeasure(batchMeasure);
+      default:
+        throw new IllegalArgumentException("Unsupported Measure.ValueType " + metric.getMetricType().getValueType());
+    }
+  }
+
+  private static Optional<Measure> toIntegerMeasure(BatchReport.Measure batchMeasure, @Nullable String data) {
+    if (!batchMeasure.hasIntValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(batchMeasure.getIntValue(), data), batchMeasure);
+  }
+
+  private static Optional<Measure> toLongMeasure(BatchReport.Measure batchMeasure, @Nullable String data) {
+    if (!batchMeasure.hasLongValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(batchMeasure.getLongValue(), data), batchMeasure);
+  }
+
+  private static Optional<Measure> toDoubleMeasure(BatchReport.Measure batchMeasure, @Nullable String data) {
+    if (!batchMeasure.hasDoubleValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(batchMeasure.getDoubleValue(), data), batchMeasure);
+  }
+
+  private static Optional<Measure> toBooleanMeasure(BatchReport.Measure batchMeasure, @Nullable String data) {
+    if (!batchMeasure.hasBooleanValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(batchMeasure.getBooleanValue(), data), batchMeasure);
+  }
+
+  private static Optional<Measure> toStringMeasure(BatchReport.Measure batchMeasure) {
+    if (!batchMeasure.hasStringValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(batchMeasure.getStringValue()), batchMeasure);
+  }
+  
+  private static Optional<Measure> toLevelMeasure(BatchReport.Measure batchMeasure) {
+    if (!batchMeasure.hasStringValue()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    Optional<Measure.Level> level = Measure.Level.toLevel(batchMeasure.getStringValue());
+    if (!level.isPresent()) {
+      return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+    }
+    return toMeasure(MeasureImpl.create(level.get()), batchMeasure);
+  }
+
+  private static Optional<Measure> toNoValueMeasure(BatchReport.Measure batchMeasure) {
+    return toMeasure(MeasureImpl.createNoValue(), batchMeasure);
+  }
+
+  private static Optional<Measure> toMeasure(MeasureImpl measure, BatchReport.Measure batchMeasure) {
+    if (batchMeasure.hasAlertStatus() && !measure.hasQualityGateStatus()) {
+      Optional<Measure.Level> qualityGateStatus = Measure.Level.toLevel(batchMeasure.getAlertStatus());
+      if (qualityGateStatus.isPresent()) {
+        String text = batchMeasure.hasAlertText() ? batchMeasure.getAlertText() : null;
+        measure.setQualityGateStatus(new Measure.QualityGateStatus(qualityGateStatus.get(), text));
+      }
+    }
+    return Optional.of((Measure) measure);
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java
new file mode 100644 (file)
index 0000000..7d420c8
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+public interface Measure {
+
+  enum ValueType {
+    NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL
+  }
+
+  enum Level {
+    OK("Green"),
+    WARN("Orange"),
+    ERROR("Red");
+
+    private final String colorName;
+
+    Level(String colorName) {
+      this.colorName = colorName;
+    }
+
+    public String getColorName() {
+      return colorName;
+    }
+
+    public static Optional<Level> toLevel(@Nullable String level) {
+      if (level == null) {
+        return Optional.absent();
+      }
+      try {
+        return Optional.of(Level.valueOf(level));
+      } catch (IllegalArgumentException e) {
+        return Optional.absent();
+      }
+    }
+  }
+
+  /**
+   * A QualityGate status has a level and an optional describing text.
+   */
+  @Immutable
+  final class QualityGateStatus {
+    private final Level status;
+    @CheckForNull
+    private final String text;
+
+    /**
+     * Creates a QualityGateStatus without a text.
+     */
+    public QualityGateStatus(Level status) {
+      this(status, null);
+    }
+
+    /**
+     * Creates a QualityGateStatus with a optional text.
+     */
+    public QualityGateStatus(Level status, @Nullable String text) {
+      this.status = requireNonNull(status);
+      this.text = text;
+    }
+
+    public Level getStatus() {
+      return status;
+    }
+
+    @CheckForNull
+    public String getText() {
+      return text;
+    }
+
+    @Override
+    public String toString() {
+      return Objects.toStringHelper(this)
+          .add("status", status)
+          .add("text", text)
+          .toString();
+    }
+  }
+
+  /**
+   * The type of value stored in the measure.
+   */
+  ValueType getValueType();
+
+  /**
+   * The value of this measure as a boolean if the type is {@link Measure.ValueType#BOOLEAN}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
+   */
+  boolean getBooleanValue();
+
+  /**
+   * The value of this measure as a int if the type is {@link Measure.ValueType#INT}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#INT}
+   */
+  int getIntValue();
+
+  /**
+   * The value of this measure as a long if the type is {@link Measure.ValueType#LONG}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LONG}
+   */
+  long getLongValue();
+
+  /**
+   * The value of this measure as a double if the type is {@link Measure.ValueType#DOUBLE}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#DOUBLE}
+   */
+  double getDoubleValue();
+
+  /**
+   * The value of this measure as a String if the type is {@link Measure.ValueType#STRING}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#STRING}
+   */
+  String getStringValue();
+
+  /**
+   * The value of this measure as a Level if the type is {@link Measure.ValueType#LEVEL}.
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LEVEL}
+   */
+  Level getLevelValue();
+
+  /**
+   * The data of this measure if it exists.
+   * <p>
+   * If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
+   * </p>
+   *
+   * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
+   */
+  @CheckForNull
+  String getData();
+
+  /**
+   * Any Measure, which ever is its value type, can have a QualityGate status.
+   */
+  boolean hasQualityGateStatus();
+
+  /**
+   * The QualityGate status for this measure.
+   * <strong>Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first</strong>
+   *
+   * @throws IllegalStateException if the measure has no QualityGate status
+   */
+  QualityGateStatus getQualityGateStatus();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java
new file mode 100644 (file)
index 0000000..c2dad3d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Optional;
+import java.util.Objects;
+import javax.annotation.Nullable;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.server.computation.metric.Metric;
+
+import static org.sonar.server.computation.measure.Measure.Level.toLevel;
+
+public class MeasureDtoToMeasure {
+
+  public Optional<Measure> toMeasure(@Nullable MeasureDto measureDto, Metric metric) {
+    Objects.requireNonNull(metric);
+    if (measureDto == null) {
+      return Optional.absent();
+    }
+
+    Double value = measureDto.getValue();
+    String data = measureDto.getData();
+    switch (metric.getMetricType().getValueType()) {
+      case INT:
+        return toIntegerMeasure(measureDto, value, data);
+      case LONG:
+        return toLongMeasure(measureDto, value, data);
+      case DOUBLE:
+        return toDoubleMeasure(measureDto, value, data);
+      case BOOLEAN:
+        return toBooleanMeasure(measureDto, value, data);
+      case STRING:
+        return toStringMeasure(measureDto, data);
+      case LEVEL:
+        return toLevelMeasure(measureDto, data);
+      case NO_VALUE:
+        return toNoValueMeasure(measureDto);
+      default:
+        throw new IllegalArgumentException("Unsupported Measure.ValueType " + metric.getMetricType().getValueType());
+    }
+  }
+
+  private static Optional<Measure> toIntegerMeasure(MeasureDto measureDto, @Nullable Double value, String data) {
+    if (value == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(value.intValue(), data), measureDto);
+  }
+
+  private static Optional<Measure> toLongMeasure(MeasureDto measureDto, @Nullable Double value, String data) {
+    if (value == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(value.longValue(), data), measureDto);
+  }
+
+  private static Optional<Measure> toDoubleMeasure(MeasureDto measureDto, @Nullable Double value, String data) {
+    if (value == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(value.doubleValue(), data), measureDto);
+  }
+
+  private static Optional<Measure> toBooleanMeasure(MeasureDto measureDto, @Nullable Double value, String data) {
+    if (value == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(value == 1.0d, data), measureDto);
+  }
+
+  private static Optional<Measure> toStringMeasure(MeasureDto measureDto, @Nullable String data) {
+    if (data == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(data), measureDto);
+  }
+
+  private static Optional<Measure> toLevelMeasure(MeasureDto measureDto, @Nullable String data) {
+    if (data == null) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    Optional<Measure.Level> level = toLevel(data);
+    if (!level.isPresent()) {
+      return toMeasure(MeasureImpl.createNoValue(), measureDto);
+    }
+    return toMeasure(MeasureImpl.create(level.get()), measureDto);
+  }
+
+  private static Optional<Measure> toNoValueMeasure(MeasureDto measureDto) {
+    return toMeasure(MeasureImpl.createNoValue(), measureDto);
+  }
+
+  private static Optional<Measure> toMeasure(MeasureImpl measure, MeasureDto measureDto) {
+    if (measureDto.getAlertStatus() != null && !measure.hasQualityGateStatus()) {
+      Optional<Measure.Level> qualityGateStatus = toLevel(measureDto.getAlertStatus());
+      if (qualityGateStatus.isPresent()) {
+        measure.setQualityGateStatus(new Measure.QualityGateStatus(qualityGateStatus.get(), measureDto.getAlertText()));
+      }
+    }
+
+    return Optional.of((Measure) measure);
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureImpl.java
new file mode 100644 (file)
index 0000000..b4471e9
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Preconditions;
+import java.util.Locale;
+import javax.annotation.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
+public final class MeasureImpl implements Measure {
+
+  private final ValueType valueType;
+  @Nullable
+  private final Double value;
+  @Nullable
+  private final String data;
+  @Nullable
+  private final Level dataLevel;
+  @Nullable
+  private QualityGateStatus qualityGateStatus;
+
+  protected MeasureImpl(ValueType valueType, @Nullable Double value, @Nullable String data, @Nullable Level dataLevel) {
+    this.valueType = valueType;
+    this.value = value;
+    this.data = data;
+    this.dataLevel = dataLevel;
+  }
+
+  public static MeasureImpl create(boolean value, @Nullable String data) {
+    return new MeasureImpl(ValueType.BOOLEAN, value ? 1.0d : 0.0d, data, null);
+  }
+
+  public static MeasureImpl create(int value, @Nullable String data) {
+    return new MeasureImpl(ValueType.INT, (double) value, data, null);
+  }
+
+  public static MeasureImpl create(long value, @Nullable String data) {
+    return new MeasureImpl(ValueType.LONG, (double) value, data, null);
+  }
+
+  public static MeasureImpl create(double value, @Nullable String data) {
+    return new MeasureImpl(ValueType.DOUBLE, value, data, null);
+  }
+
+  public static MeasureImpl create(String value) {
+    return new MeasureImpl(ValueType.STRING, null, requireNonNull(value), null);
+  }
+
+  public static MeasureImpl create(Level level) {
+    return new MeasureImpl(ValueType.LEVEL, null, null, requireNonNull(level));
+  }
+
+  public static MeasureImpl createNoValue() {
+    return new MeasureImpl(ValueType.NO_VALUE, null, null, null);
+  }
+
+  @Override
+  public ValueType getValueType() {
+    return valueType;
+  }
+
+  @Override
+  public boolean getBooleanValue() {
+    checkValueType(ValueType.BOOLEAN);
+    return value == 1.0d;
+  }
+
+  @Override
+  public int getIntValue() {
+    checkValueType(ValueType.INT);
+    return value.intValue();
+  }
+
+  @Override
+  public long getLongValue() {
+    checkValueType(ValueType.LONG);
+    return value.longValue();
+  }
+
+  @Override
+  public double getDoubleValue() {
+    checkValueType(ValueType.DOUBLE);
+    return value;
+  }
+
+  @Override
+  public String getStringValue() {
+    checkValueType(ValueType.STRING);
+    return data;
+  }
+
+  @Override
+  public Level getLevelValue() {
+    checkValueType(ValueType.LEVEL);
+    return dataLevel;
+  }
+
+  @Override
+  public String getData() {
+    return data;
+  }
+
+  private void checkValueType(ValueType expected) {
+    if (valueType != expected) {
+      throw new IllegalStateException(
+          String.format(
+              "value can not be converted to %s because current value type is a %s",
+              expected.toString().toLowerCase(Locale.US),
+              valueType
+          ));
+    }
+  }
+
+  public MeasureImpl setQualityGateStatus(QualityGateStatus qualityGateStatus) {
+    this.qualityGateStatus = requireNonNull(qualityGateStatus, "Can not set a null QualityGate status");
+    return this;
+  }
+
+  @Override
+  public boolean hasQualityGateStatus() {
+    return this.qualityGateStatus != null;
+  }
+
+  @Override
+  public QualityGateStatus getQualityGateStatus() {
+    Preconditions.checkState(qualityGateStatus != null, "Measure does not have an QualityGate status");
+    return this.qualityGateStatus;
+  }
+
+}
index 390e3ff62e61b7303b4ef2010db00df6abe87888..ff01e2c227129b544088313a3e0bffdfe93bde89 100644 (file)
  */
 package org.sonar.server.computation.measure;
 
-import org.sonar.api.measures.Metric;
-import org.sonar.batch.protocol.output.BatchReport;
-
 import com.google.common.base.Optional;
-import org.sonar.core.measure.db.MeasureDto;
+import java.util.Map;
 import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricImpl;
 
 public interface MeasureRepository {
-  // FIXME should not expose MeasureDto from DAO layer
-  Optional<MeasureDto> findPrevious(Component component, Metric<?> metric);
 
-  // FIXME should not expose Measure from BatchReport
-  Optional<BatchReport.Measure> findCurrent(Component component, Metric<?> metric);
+  /**
+   * Retrieves the base measure (ie. the one currently existing in DB) for the specified {@link Component} for
+   * the specified {@link MetricImpl} if it exists.
+   *
+   * @throws NullPointerException if either argument is {@code null}
+   */
+  Optional<Measure> getBaseMeasure(Component component, Metric metric);
+
+  /**
+   * Retrieves the measure created during the current analysis for the specified {@link Component} for the specified
+   * {@link MetricImpl} if it exists (ie. one created by the Compute Engine or the Batch).
+   */
+  Optional<Measure> getRawMeasure(Component component, Metric metric);
+
+  /**
+   * @return {@link Measure}s for the specified {@link Component} mapped by their metric key.
+   */
+  Map<String, Measure> getRawMeasures(Component component);
+
+  /**
+   * Adds the specified measure for the specified Component and Metric. There can be no more than one measure for a
+   * specific combination of Component and Metric.
+   *
+   * @throws NullPointerException if any of the argument is null
+   * @throws UnsupportedOperationException when trying to add a measure when one already exists for the specified Component/Metric paar
+   */
+  void add(Component component, Metric metric, Measure measure);
 }
index 8e7dd40b4ee3c2bf60b7925b8e00a0f18442822d..ca88815d23a69bded6b63f7146b4f1cf47b4e99b 100644 (file)
  */
 package org.sonar.server.computation.measure;
 
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import javax.annotation.Nonnull;
-import org.sonar.api.measures.Metric;
+import javax.annotation.Nullable;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.db.DbClient;
 
+import static com.google.common.collect.FluentIterable.from;
+import static java.util.Objects.requireNonNull;
+
 public class MeasureRepositoryImpl implements MeasureRepository {
   private final DbClient dbClient;
   private final BatchReportReader reportReader;
+  private final MeasureDtoToMeasure measureDtoToMeasure = new MeasureDtoToMeasure();
+  private final BatchMeasureToMeasure batchMeasureToMeasure = new BatchMeasureToMeasure();
+  private final Function<BatchReport.Measure, Measure> batchMeasureToMeasureFunction;
+  private final Map<Integer, Map<String, Measure>> measures = new HashMap<>();
 
-  public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader) {
+  public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader, final MetricRepository metricRepository) {
     this.dbClient = dbClient;
     this.reportReader = reportReader;
+
+    this.batchMeasureToMeasureFunction = new Function<BatchReport.Measure, Measure>() {
+      @Nullable
+      @Override
+      public Measure apply(@Nonnull BatchReport.Measure input) {
+        return batchMeasureToMeasure.toMeasure(input, metricRepository.getByKey(input.getMetricKey())).get();
+      }
+    };
   }
 
   @Override
-  public Optional<MeasureDto> findPrevious(Component component, Metric<?> metric) {
+  public Optional<Measure> getBaseMeasure(Component component, Metric metric) {
+    // fail fast
+    requireNonNull(component);
+    requireNonNull(metric);
+
     try (DbSession dbSession = dbClient.openSession(false)) {
-      return Optional.fromNullable(
-        dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey())
-        );
+      MeasureDto measureDto = dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey());
+      return measureDtoToMeasure.toMeasure(measureDto, metric);
     }
   }
 
   @Override
-  public Optional<BatchReport.Measure> findCurrent(Component component, final Metric<?> metric) {
-    return Optional.fromNullable(Iterables.find(
+  public Optional<Measure> getRawMeasure(final Component component, final Metric metric) {
+    // fail fast
+    requireNonNull(component);
+    requireNonNull(metric);
+
+    Optional<Measure> local = findLocal(component, metric);
+    if (local.isPresent()) {
+      return local;
+    }
+    return findInBatch(component, metric);
+  }
+
+  private Optional<Measure> findInBatch(Component component, final Metric metric) {
+    BatchReport.Measure batchMeasure = Iterables.find(
       reportReader.readComponentMeasures(component.getRef()),
       new Predicate<BatchReport.Measure>() {
         @Override
@@ -59,6 +97,74 @@ public class MeasureRepositoryImpl implements MeasureRepository {
           return input.getMetricKey().equals(metric.getKey());
         }
       }
-      , null));
+      , null);
+
+    return batchMeasureToMeasure.toMeasure(batchMeasure, metric);
+  }
+
+  @Override
+  public void add(Component component, Metric metric, Measure measure) {
+    requireNonNull(component);
+    requireNonNull(metric);
+    requireNonNull(measure);
+
+    Optional<Measure> existingMeasure = findLocal(component, metric);
+    if (existingMeasure.isPresent()) {
+      throw new UnsupportedOperationException(
+        String.format(
+          "a measure can be set only once for a specific Component (ref=%s) and Metric (key=%s)",
+          component.getRef(),
+          metric.getKey()
+          ));
+    }
+    addLocal(component, metric, measure);
+  }
+
+  @Override
+  public Map<String, Measure> getRawMeasures(Component component) {
+    Map<String, Measure> rawMeasures = measures.get(component.getRef());
+    ImmutableMap<String, BatchReport.Measure> batchMeasures = from(reportReader.readComponentMeasures(component.getRef()))
+      .uniqueIndex(BatchMeasureToMetricKey.INSTANCE);
+
+    if (rawMeasures == null && batchMeasures.isEmpty()) {
+      return Collections.emptyMap();
+    }
+
+    Map<String, Measure> rawMeasuresFromBatch = Maps.transformValues(batchMeasures, batchMeasureToMeasureFunction);
+    if (rawMeasures == null) {
+      return ImmutableMap.copyOf(rawMeasuresFromBatch);
+    }
+
+    ImmutableMap.Builder<String, Measure> builder = ImmutableMap.builder();
+    builder.putAll(rawMeasuresFromBatch);
+    builder.putAll(rawMeasures);
+    return builder.build();
+  }
+
+  private Optional<Measure> findLocal(Component component, Metric metric) {
+    Map<String, Measure> measuresPerMetric = measures.get(component.getRef());
+    if (measuresPerMetric == null) {
+      return Optional.absent();
+    }
+    return Optional.fromNullable(measuresPerMetric.get(metric.getKey()));
+  }
+
+  private void addLocal(Component component, Metric metric, Measure measure) {
+    Map<String, Measure> measuresPerMetric = measures.get(component.getRef());
+    if (measuresPerMetric == null) {
+      measuresPerMetric = new HashMap<>();
+      measures.put(component.getRef(), measuresPerMetric);
+    }
+    measuresPerMetric.put(metric.getKey(), measure);
+  }
+
+  private enum BatchMeasureToMetricKey implements Function<BatchReport.Measure, String> {
+    INSTANCE;
+
+    @Nullable
+    @Override
+    public String apply(@Nonnull BatchReport.Measure input) {
+      return input.getMetricKey();
+    }
   }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java
new file mode 100644 (file)
index 0000000..52035df
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+import org.sonar.server.computation.measure.Measure;
+
+public interface Metric {
+  /**
+   * The Metric's key is its domain identifier.
+   */
+  String getKey();
+
+  String getName();
+
+  MetricType getMetricType();
+
+  enum MetricType {
+    INT(Measure.ValueType.INT),
+    MILLISEC(Measure.ValueType.INT),
+    RATING(Measure.ValueType.INT),
+    WORK_DUR(Measure.ValueType.LONG),
+    FLOAT(Measure.ValueType.DOUBLE),
+    PERCENT(Measure.ValueType.DOUBLE),
+    BOOL(Measure.ValueType.BOOLEAN),
+    STRING(Measure.ValueType.STRING),
+    DISTRIB(Measure.ValueType.STRING),
+    DATA(Measure.ValueType.STRING),
+    LEVEL(Measure.ValueType.LEVEL);
+
+    private final Measure.ValueType valueType;
+
+    MetricType(Measure.ValueType valueType) {
+      this.valueType = valueType;
+    }
+
+    public Measure.ValueType getValueType() {
+      return valueType;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java
new file mode 100644 (file)
index 0000000..d28f64a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+import java.util.Objects;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public final class MetricImpl implements Metric {
+
+  private final String key;
+  private final String name;
+  private final MetricType metricType;
+
+  public MetricImpl(String key, String name, MetricType metricType) {
+    this.key = requireNonNull(key);
+    this.name = requireNonNull(name);
+    this.metricType = requireNonNull(metricType);
+  }
+
+  @Override
+  public String getKey() {
+    return key;
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public MetricType getMetricType() {
+    return metricType;
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    MetricImpl metric = (MetricImpl) o;
+    return Objects.equals(key, metric.key) &&
+        Objects.equals(metricType, metric.metricType);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(key, metricType);
+  }
+
+  @Override
+  public String toString() {
+    return com.google.common.base.Objects.toStringHelper(this)
+        .add("key", key)
+        .add("name", name)
+        .add("metricType", metricType)
+        .toString();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepository.java
new file mode 100644 (file)
index 0000000..9120ce8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+public interface MetricRepository {
+
+  /**
+   * Gets the {@link Metric} with the specific key.
+   * <p>Since it does not make sense to encounter a reference (ie. a key) to a Metric during processing of
+   * a new analysis and not finding it in DB (metrics are never deleted), this method will throw an
+   * IllegalStateException if the metric with the specified key can not be found.</p>
+   *
+   * @throws IllegalStateException if no Metric with the specified key is found
+   * @throws NullPointerException if the specified key is {@code null}
+   */
+  Metric getByKey(String key);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java
new file mode 100644 (file)
index 0000000..63766ad
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+
+import static java.util.Objects.requireNonNull;
+
+public class MetricRepositoryImpl implements MetricRepository {
+  private final DbClient dbClient;
+
+  public MetricRepositoryImpl(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public Metric getByKey(String key) {
+    requireNonNull(key);
+
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      MetricDto metricDto = dbClient.metricDao().selectNullableByKey(dbSession, key);
+      if (metricDto == null) {
+        throw new IllegalStateException(String.format("Metric with key '%s' does not exist", key));
+      }
+
+      return toMetric(metricDto);
+    }
+  }
+
+  private static Metric toMetric(MetricDto metricDto) {
+    return new MetricImpl(metricDto.getKey(), metricDto.getShortName(), Metric.MetricType.valueOf(metricDto.getValueType()));
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/package-info.java
new file mode 100644 (file)
index 0000000..1f06a93
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.metric;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 51966a692fb356b9ee5c3f5bbef76598e7bb7181..7eaad9ec0319c1d2de2e402aff2f9d47fa18d5ce 100644 (file)
@@ -25,28 +25,33 @@ import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
 import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.event.Event;
 import org.sonar.server.computation.event.EventRepository;
+import org.sonar.server.computation.measure.Measure;
 import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.notification.NotificationManager;
 
 public class QualityGateEventsStep implements ComputationStep {
-  public static final Logger LOGGER = Loggers.get(QualityGateEventsStep.class);
+  private static final Logger LOGGER = Loggers.get(QualityGateEventsStep.class);
+
   private final TreeRootHolder treeRootHolder;
-  private final EventRepository eventRepository;
+  private final MetricRepository metricRepository;
   private final MeasureRepository measureRepository;
+  private final EventRepository eventRepository;
   private final NotificationManager notificationManager;
 
-  public QualityGateEventsStep(TreeRootHolder treeRootHolder, EventRepository eventRepository,
-    MeasureRepository measureRepository, NotificationManager notificationManager) {
-    this.eventRepository = eventRepository;
-    this.measureRepository = measureRepository;
+  public QualityGateEventsStep(TreeRootHolder treeRootHolder,
+    MetricRepository metricRepository, MeasureRepository measureRepository, EventRepository eventRepository,
+    NotificationManager notificationManager) {
     this.treeRootHolder = treeRootHolder;
+    this.metricRepository = metricRepository;
+    this.measureRepository = measureRepository;
+    this.eventRepository = eventRepository;
     this.notificationManager = notificationManager;
   }
 
@@ -61,95 +66,64 @@ public class QualityGateEventsStep implements ComputationStep {
   }
 
   private void executeForProject(Component project) {
-    Optional<BatchReport.Measure> statusMeasure = measureRepository.findCurrent(project, CoreMetrics.ALERT_STATUS);
-    if (!statusMeasure.isPresent()) {
-      return;
-    }
-    Optional<GateStatus> status = parse(statusMeasure.get().getAlertStatus());
-    if (!status.isPresent()) {
+    Metric metric = metricRepository.getByKey(CoreMetrics.ALERT_STATUS_KEY);
+    Optional<Measure> rawStatus = measureRepository.getRawMeasure(project, metric);
+    if (!rawStatus.isPresent() || !rawStatus.get().hasQualityGateStatus()) {
       return;
     }
 
-    checkStatusChange(project, status.get(), statusMeasure.get().getAlertText());
+    checkQualityGateStatusChange(project, metric, rawStatus.get().getQualityGateStatus());
   }
 
-  private void checkStatusChange(Component project, GateStatus status, String description) {
-    Optional<MeasureDto> baseMeasure = measureRepository.findPrevious(project, CoreMetrics.ALERT_STATUS);
+  private void checkQualityGateStatusChange(Component project, Metric metric, Measure.QualityGateStatus rawStatus) {
+    Optional<Measure> baseMeasure = measureRepository.getBaseMeasure(project, metric);
     if (!baseMeasure.isPresent()) {
-      checkStatus(project, status, description);
+      checkNewQualityGate(project, rawStatus);
       return;
     }
 
-    Optional<GateStatus> baseStatus = parse(baseMeasure.get().getAlertStatus());
-    if (!baseStatus.isPresent()) {
-      LOGGER.warn(String.format("Base status for project %s is not a supported value. Can not compute Quality Gate event", project.getKey()));
-      checkStatus(project, status, description);
+    if (!baseMeasure.get().hasQualityGateStatus()) {
+      LOGGER.warn(String.format("Previous alterStatus for project %s is not a supported value. Can not compute Quality Gate event", project.getKey()));
+      checkNewQualityGate(project, rawStatus);
       return;
     }
-
-    if (baseStatus.get() != status) {
-      // The status has changed
-      String label = String.format("%s (was %s)", status.getColorName(), baseStatus.get().getColorName());
-      createEvent(project, label, description);
-      boolean isNewKo = (baseStatus.get() == GateStatus.OK);
-      notifyUsers(project, label, description, status, isNewKo);
+    Measure.QualityGateStatus baseStatus = baseMeasure.get().getQualityGateStatus();
+
+    if (baseStatus.getStatus() != rawStatus.getStatus()) {
+      // The QualityGate status has changed
+      String label = String.format("%s (was %s)", rawStatus.getStatus().getColorName(), baseStatus.getStatus().getColorName());
+      createEvent(project, label, rawStatus.getText());
+      boolean isNewKo = (rawStatus.getStatus() == Measure.Level.OK);
+      notifyUsers(project, label, rawStatus, isNewKo);
     }
   }
 
-  private void checkStatus(Component project, GateStatus status, String description) {
-    if (status != GateStatus.OK) {
+  private void checkNewQualityGate(Component project, Measure.QualityGateStatus rawStatus) {
+    if (rawStatus.getStatus() != Measure.Level.OK) {
       // There were no defined alerts before, so this one is a new one
-      createEvent(project, status.getColorName(), description);
-      notifyUsers(project, status.getColorName(), description, status, true);
-    }
-  }
-
-  private static Optional<GateStatus> parse(@Nullable String alertStatus) {
-    if (alertStatus == null) {
-      return Optional.absent();
-    }
-
-    try {
-      return Optional.of(GateStatus.valueOf(alertStatus));
-    } catch (IllegalArgumentException e) {
-      LOGGER.error(String.format("Unsupported alertStatus value '%s' can not be parsed to AlertStatus", alertStatus));
-      return Optional.absent();
-    }
-  }
-
-  private enum GateStatus {
-    OK("Green"), WARN("Orange"), ERROR("Red");
-
-    private String colorName;
-
-    GateStatus(String colorName) {
-      this.colorName = colorName;
-    }
-
-    public String getColorName() {
-      return colorName;
+      createEvent(project, rawStatus.getStatus().getColorName(), rawStatus.getText());
+      // notifyUsers(project, alertName, alertText, alertLevel, true);
     }
   }
 
   /**
    * @param label "Red (was Orange)"
-   * @param description text detail, for example "Coverage < 80%"
-   * @param status OK, WARN or ERROR
+   * @param rawStatus OK, WARN or ERROR + optional text
    */
-  private void notifyUsers(Component project, String label, String description, GateStatus status, boolean isNewAlert) {
+  private void notifyUsers(Component project, String label, Measure.QualityGateStatus rawStatus, boolean isNewAlert) {
     Notification notification = new Notification("alerts")
       .setDefaultMessage(String.format("Alert on %s: %s", project.getName(), label))
       .setFieldValue("projectName", project.getName())
       .setFieldValue("projectKey", project.getKey())
       .setFieldValue("projectUuid", project.getUuid())
       .setFieldValue("alertName", label)
-      .setFieldValue("alertText", description)
-      .setFieldValue("alertLevel", status.toString())
+      .setFieldValue("alertText", rawStatus.getText())
+      .setFieldValue("alertLevel", rawStatus.getStatus().toString())
       .setFieldValue("isNewAlert", Boolean.toString(isNewAlert));
     notificationManager.scheduleForSending(notification);
   }
 
-  private void createEvent(Component project, String name, String description) {
+  private void createEvent(Component project, String name, @Nullable String description) {
     eventRepository.add(project, Event.createAlert(name, null, description));
   }
 
index 8c223e442efb420faf65ba100588a0f9c36b8fc7..d02909069d3e8b13d35eb2729bfdc299c767a7be 100644 (file)
@@ -29,16 +29,16 @@ import org.apache.commons.lang.time.DateUtils;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.resources.Language;
 import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.UtcDateUtils;
-import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
 import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.event.Event;
 import org.sonar.server.computation.event.EventRepository;
 import org.sonar.server.computation.language.LanguageRepository;
+import org.sonar.server.computation.measure.Measure;
 import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.computation.qualityprofile.QPMeasureData;
 import org.sonar.server.computation.qualityprofile.QualityProfile;
 
@@ -46,18 +46,22 @@ import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisi
 
 public class QualityProfileEventsStep implements ComputationStep {
   private final TreeRootHolder treeRootHolder;
+  private final MetricRepository metricRepository;
   private final MeasureRepository measureRepository;
   private final EventRepository eventRepository;
   private final LanguageRepository languageRepository;
 
   public QualityProfileEventsStep(TreeRootHolder treeRootHolder,
-    MeasureRepository measureRepository, EventRepository eventRepository, LanguageRepository languageRepository) {
+    MetricRepository metricRepository, MeasureRepository measureRepository, LanguageRepository languageRepository,
+    EventRepository eventRepository) {
     this.treeRootHolder = treeRootHolder;
+    this.metricRepository = metricRepository;
     this.measureRepository = measureRepository;
     this.eventRepository = eventRepository;
     this.languageRepository = languageRepository;
   }
 
+
   @Override
   public void execute() {
     new DepthTraversalTypeAwareVisitor(Component.Type.PROJECT, POST_ORDER) {
@@ -69,53 +73,53 @@ public class QualityProfileEventsStep implements ComputationStep {
   }
 
   private void executeForProject(Component projectComponent) {
-    Optional<MeasureDto> previousMeasure = measureRepository.findPrevious(projectComponent, CoreMetrics.QUALITY_PROFILES);
-    if (!previousMeasure.isPresent()) {
+    Optional<Measure> baseMeasure = measureRepository.getBaseMeasure(projectComponent, metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY));
+    if (!baseMeasure.isPresent()) {
       // first analysis -> do not generate events
       return;
     }
 
-    // Load current profiles
-    Optional<BatchReport.Measure> currentMeasure = measureRepository.findCurrent(projectComponent, CoreMetrics.QUALITY_PROFILES);
-    if (!currentMeasure.isPresent()) {
+    // Load base profiles
+    Optional<Measure> rawMeasure = measureRepository.getRawMeasure(projectComponent, metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY));
+    if (!rawMeasure.isPresent()) {
       throw new IllegalStateException("Missing measure " + CoreMetrics.QUALITY_PROFILES + " for component " + projectComponent.getRef());
     }
-    Map<String, QualityProfile> currentProfiles = QPMeasureData.fromJson(currentMeasure.get().getStringValue()).getProfilesByKey();
+    Map<String, QualityProfile> rawProfiles = QPMeasureData.fromJson(rawMeasure.get().getStringValue()).getProfilesByKey();
 
-    Map<String, QualityProfile> previousProfiles = parseJsonData(previousMeasure);
-    detectNewOrUpdatedProfiles(projectComponent, previousProfiles, currentProfiles);
-    detectNoMoreUsedProfiles(projectComponent, previousProfiles, currentProfiles);
+    Map<String, QualityProfile> baseProfiles = parseJsonData(baseMeasure);
+    detectNewOrUpdatedProfiles(projectComponent, baseProfiles, rawProfiles);
+    detectNoMoreUsedProfiles(projectComponent, baseProfiles, rawProfiles);
   }
 
-  private static Map<String, QualityProfile> parseJsonData(Optional<MeasureDto> previousMeasure) {
-    String data = previousMeasure.get().getData();
+  private static Map<String, QualityProfile> parseJsonData(Optional<Measure> measure) {
+    String data = measure.get().getStringValue();
     if (data == null) {
       return Collections.emptyMap();
     }
     return QPMeasureData.fromJson(data).getProfilesByKey();
   }
 
-  private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> previousProfiles, Map<String, QualityProfile> currentProfiles) {
-    for (QualityProfile previousProfile : previousProfiles.values()) {
-      if (!currentProfiles.containsKey(previousProfile.getQpKey())) {
-        markAsRemoved(context, previousProfile);
+  private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
+    for (QualityProfile baseProfile : baseProfiles.values()) {
+      if (!rawProfiles.containsKey(baseProfile.getQpKey())) {
+        markAsRemoved(context, baseProfile);
       }
     }
   }
 
-  private void detectNewOrUpdatedProfiles(Component component, Map<String, QualityProfile> previousProfiles, Map<String, QualityProfile> currentProfiles) {
-    for (QualityProfile profile : currentProfiles.values()) {
-      QualityProfile previousProfile = previousProfiles.get(profile.getQpKey());
-      if (previousProfile == null) {
+  private void detectNewOrUpdatedProfiles(Component component, Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
+    for (QualityProfile profile : rawProfiles.values()) {
+      QualityProfile baseProfile = baseProfiles.get(profile.getQpKey());
+      if (baseProfile == null) {
         markAsAdded(component, profile);
-      } else if (profile.getRulesUpdatedAt().after(previousProfile.getRulesUpdatedAt())) {
-        markAsChanged(component, previousProfile, profile);
+      } else if (profile.getRulesUpdatedAt().after(baseProfile.getRulesUpdatedAt())) {
+        markAsChanged(component, baseProfile, profile);
       }
     }
   }
 
-  private void markAsChanged(Component component, QualityProfile previousProfile, QualityProfile profile) {
-    Date from = previousProfile.getRulesUpdatedAt();
+  private void markAsChanged(Component component, QualityProfile baseProfile, QualityProfile profile) {
+    Date from = baseProfile.getRulesUpdatedAt();
 
     String data = KeyValueFormat.format(ImmutableSortedMap.of(
       "key", profile.getQpKey(),
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java
new file mode 100644 (file)
index 0000000..7105525
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricImpl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+
+public class BatchMeasureToMeasureTest {
+  private static final Metric SOME_INT_METRIC = new MetricImpl("key", "name", Metric.MetricType.INT);
+  private static final Metric SOME_LONG_METRIC = new MetricImpl("key", "name", Metric.MetricType.WORK_DUR);
+  private static final Metric SOME_DOUBLE_METRIC = new MetricImpl("key", "name", Metric.MetricType.FLOAT);
+  private static final Metric SOME_STRING_METRIC = new MetricImpl("key", "name", Metric.MetricType.STRING);
+  private static final Metric SOME_BOOLEAN_METRIC = new MetricImpl("key", "name", Metric.MetricType.BOOL);
+  private static final Metric SOME_LEVEL_METRIC = new MetricImpl("key", "name", Metric.MetricType.LEVEL);
+
+  private static final String SOME_DATA = "some_data man!";
+  private static final String SOME_ALERT_TEXT = "some alert text_be_careFul!";
+  private static final BatchReport.Measure EMPTY_BATCH_MEASURE = BatchReport.Measure.newBuilder().build();
+
+  private BatchMeasureToMeasure underTest = new BatchMeasureToMeasure();
+
+  @Test
+  public void toMeasure_returns_absent_for_null_argument() {
+    assertThat(underTest.toMeasure(null, SOME_INT_METRIC)).isAbsent();
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void toMeasure_throws_NPE_if_metric_argument_is_null() {
+    underTest.toMeasure(EMPTY_BATCH_MEASURE, null);
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void toMeasure_throws_NPE_if_both_arguments_are_null() {
+    underTest.toMeasure(null, null);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_string_value_for_LEVEL_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_invalid_string_value_for_LEVEL_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(BatchReport.Measure.newBuilder().setStringValue("trololo").build(), SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_value_in_wrong_case_for_LEVEL_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(BatchReport.Measure.newBuilder().setStringValue("waRn").build(), SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_value_for_LEVEL_Metric() {
+    for (Measure.Level alertStatus : Measure.Level.values()) {
+      verify_toMeasure_returns_value_for_LEVEL_Metric(alertStatus);
+    }
+  }
+
+  private void verify_toMeasure_returns_value_for_LEVEL_Metric(Measure.Level expectedQualityGateStatus) {
+    Optional<Measure> measure = underTest.toMeasure(BatchReport.Measure.newBuilder().setStringValue(expectedQualityGateStatus.name()).build(), SOME_LEVEL_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LEVEL);
+    assertThat(measure.get().getLevelValue()).isEqualTo(expectedQualityGateStatus);
+  }
+
+  @Test
+  public void toMeasure_for_LEVEL_Metric_maps_QualityGateStatus() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setStringValue(Measure.Level.OK.name())
+      .setAlertStatus(Measure.Level.ERROR.name())
+      .setAlertText(SOME_ALERT_TEXT)
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LEVEL);
+    assertThat(measure.get().getLevelValue()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.ERROR);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_for_LEVEL_Metric_parses_level_from_data() {
+    for (Measure.Level level : Measure.Level.values()) {
+      verify_toMeasure_for_LEVEL_Metric_parses_level_from_data(level);
+    }
+  }
+
+  private void verify_toMeasure_for_LEVEL_Metric_parses_level_from_data(Measure.Level expectedLevel) {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setStringValue(expectedLevel.name())
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getLevelValue()).isEqualTo(expectedLevel);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Int_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_INT_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Int_Metric() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setIntValue(10)
+      .setStringValue(SOME_DATA)
+      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_INT_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.INT);
+    assertThat(measure.get().getIntValue()).isEqualTo(10);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Long_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_long_part_of_value_in_dto_for_Long_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(BatchReport.Measure.newBuilder().setLongValue(15l).build(), SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LONG);
+    assertThat(measure.get().getLongValue()).isEqualTo(15);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Long_Metric() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setLongValue(10l)
+      .setStringValue(SOME_DATA)
+      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LONG);
+    assertThat(measure.get().getLongValue()).isEqualTo(10);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Double_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_DOUBLE_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Double_Metric() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setDoubleValue(10.6395d)
+      .setStringValue(SOME_DATA)
+      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_DOUBLE_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.DOUBLE);
+    assertThat(measure.get().getDoubleValue()).isEqualTo(10.6395d);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Boolean_metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_false_value_if_dto_has_invalid_value_for_Boolean_metric() {
+    verify_toMeasure_returns_false_value_if_dto_has_invalid_value_for_Boolean_metric(true);
+    verify_toMeasure_returns_false_value_if_dto_has_invalid_value_for_Boolean_metric(false);
+  }
+
+  private void verify_toMeasure_returns_false_value_if_dto_has_invalid_value_for_Boolean_metric(boolean expected) {
+    Optional<Measure> measure = underTest.toMeasure(BatchReport.Measure.newBuilder().setBooleanValue(expected).build(), SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.BOOLEAN);
+    assertThat(measure.get().getBooleanValue()).isEqualTo(expected);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Boolean_metric() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setBooleanValue(true).setStringValue(SOME_DATA).setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT).build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.BOOLEAN);
+    assertThat(measure.get().getBooleanValue()).isTrue();
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_String_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_STRING_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_maps_alert_properties_in_dto_for_String_Metric() {
+    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
+      .setStringValue(SOME_DATA)
+      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
+      .build();
+
+    Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_STRING_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.STRING);
+    assertThat(measure.get().getStringValue()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java
new file mode 100644 (file)
index 0000000..ddf953b
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.server.computation.measure.Measure.Level;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricImpl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+
+public class MeasureDtoToMeasureTest {
+  private static final Metric SOME_INT_METRIC = new MetricImpl("key", "name", Metric.MetricType.INT);
+  private static final Metric SOME_LONG_METRIC = new MetricImpl("key", "name", Metric.MetricType.WORK_DUR);
+  private static final Metric SOME_DOUBLE_METRIC = new MetricImpl("key", "name", Metric.MetricType.FLOAT);
+  private static final Metric SOME_STRING_METRIC = new MetricImpl("key", "name", Metric.MetricType.STRING);
+  private static final Metric SOME_BOOLEAN_METRIC = new MetricImpl("key", "name", Metric.MetricType.BOOL);
+  private static final Metric SOME_LEVEL_METRIC = new MetricImpl("key", "name", Metric.MetricType.LEVEL);
+
+  private static final String SOME_DATA = "some_data man!";
+  private static final String SOME_ALERT_TEXT = "some alert text_be_careFul!";
+  private static final MeasureDto EMPTY_MEASURE_DTO = new MeasureDto();
+
+  private MeasureDtoToMeasure underTest = new MeasureDtoToMeasure();
+
+  @Test
+  public void toMeasure_returns_absent_for_null_argument() {
+    assertThat(underTest.toMeasure(null, SOME_INT_METRIC)).isAbsent();
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void toMeasure_throws_NPE_if_metric_argument_is_null() {
+    underTest.toMeasure(EMPTY_MEASURE_DTO, null);
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void toMeasure_throws_NPE_if_both_arguments_are_null() {
+    underTest.toMeasure(null, null);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_data_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_LEVEL_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_invalid_data_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setData("trololo"), SOME_LEVEL_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dta_has_data_in_wrong_case_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setData("waRn"), SOME_LEVEL_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_no_QualityGateStatus_if_dto_has_no_alertStatus_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_STRING_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().hasQualityGateStatus()).isFalse();
+  }
+
+  @Test
+  public void toMeasure_returns_no_QualityGateStatus_if_alertStatus_has_invalid_data_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setData("trololo"), SOME_STRING_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().hasQualityGateStatus()).isFalse();
+  }
+
+  @Test
+  public void toMeasure_returns_no_QualityGateStatus_if_alertStatus_has_data_in_wrong_case_for_Level_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setData("waRn"), SOME_STRING_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().hasQualityGateStatus()).isFalse();
+  }
+
+  @Test
+  public void toMeasure_returns_value_for_LEVEL_Metric() {
+    for (Level level : Level.values()) {
+      verify_toMeasure_returns_value_for_LEVEL_Metric(level);
+    }
+  }
+
+  private void verify_toMeasure_returns_value_for_LEVEL_Metric(Level expectedLevel) {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setData(expectedLevel.name()), SOME_LEVEL_METRIC);
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LEVEL);
+    assertThat(measure.get().getLevelValue()).isEqualTo(expectedLevel);
+  }
+
+  @Test
+  public void toMeasure_for_LEVEL_Metric_can_have_an_qualityGateStatus() {
+    MeasureDto measureDto = new MeasureDto().setData(Level.OK.name()).setAlertStatus(Level.ERROR.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LEVEL);
+    assertThat(measure.get().getLevelValue()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.ERROR);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void toMeasure_for_LEVEL_Metric_ignores_data() {
+    MeasureDto measureDto = new MeasureDto().setAlertStatus(Level.ERROR.name()).setData(SOME_DATA);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_LEVEL_METRIC);
+
+    assertThat(measure).isPresent();
+    measure.get().getStringValue();
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Int_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_INT_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_int_part_of_value_in_dto_for_Int_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setValue(1.5d), SOME_INT_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.INT);
+    assertThat(measure.get().getIntValue()).isEqualTo(1);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Int_Metric() {
+    MeasureDto measureDto = new MeasureDto().setValue(10d).setData(SOME_DATA).setAlertStatus(Level.OK.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_INT_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.INT);
+    assertThat(measure.get().getIntValue()).isEqualTo(10);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Long_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_long_part_of_value_in_dto_for_Long_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setValue(1.5d), SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LONG);
+    assertThat(measure.get().getLongValue()).isEqualTo(1);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Long_Metric() {
+    MeasureDto measureDto = new MeasureDto().setValue(10d).setData(SOME_DATA).setAlertStatus(Level.OK.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_LONG_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LONG);
+    assertThat(measure.get().getLongValue()).isEqualTo(10);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Double_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_DOUBLE_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Double_Metric() {
+    MeasureDto measureDto = new MeasureDto().setValue(10.6395d).setData(SOME_DATA).setAlertStatus(Level.OK.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_DOUBLE_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.DOUBLE);
+    assertThat(measure.get().getDoubleValue()).isEqualTo(10.6395d);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_Boolean_metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_returns_false_value_if_dto_has_invalid_value_for_Boolean_metric() {
+    Optional<Measure> measure = underTest.toMeasure(new MeasureDto().setValue(1.987d), SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.BOOLEAN);
+    assertThat(measure.get().getBooleanValue()).isFalse();
+  }
+
+  @Test
+  public void toMeasure_maps_data_and_alert_properties_in_dto_for_Boolean_metric() {
+    MeasureDto measureDto = new MeasureDto().setValue(1d).setData(SOME_DATA).setAlertStatus(Level.OK.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_BOOLEAN_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.BOOLEAN);
+    assertThat(measure.get().getBooleanValue()).isTrue();
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+
+  @Test
+  public void toMeasure_returns_no_value_if_dto_has_no_value_for_String_Metric() {
+    Optional<Measure> measure = underTest.toMeasure(EMPTY_MEASURE_DTO, SOME_STRING_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
+  }
+
+  @Test
+  public void toMeasure_maps_alert_properties_in_dto_for_String_Metric() {
+    MeasureDto measureDto = new MeasureDto().setData(SOME_DATA).setAlertStatus(Level.OK.name()).setAlertText(SOME_ALERT_TEXT);
+
+    Optional<Measure> measure = underTest.toMeasure(measureDto, SOME_STRING_METRIC);
+
+    assertThat(measure.isPresent());
+    assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.STRING);
+    assertThat(measure.get().getStringValue()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
+    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK);
+    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureImplTest.java
new file mode 100644 (file)
index 0000000..c9ddf85
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.server.computation.measure.Measure.ValueType;
+
+import static com.google.common.collect.FluentIterable.from;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(DataProviderRunner.class)
+public class MeasureImplTest {
+
+  private static final MeasureImpl INT_MEASURE = MeasureImpl.create((int) 1, null);
+  private static final MeasureImpl LONG_MEASURE = MeasureImpl.create(1l, null);
+  private static final MeasureImpl DOUBLE_MEASURE = MeasureImpl.create(1d, null);
+  private static final MeasureImpl STRING_MEASURE = MeasureImpl.create("some_sT ring");
+  private static final MeasureImpl TRUE_MEASURE = MeasureImpl.create(true, null);
+  private static final MeasureImpl FALSE_MEASURE = MeasureImpl.create(false, null);
+  private static final MeasureImpl LEVEL_MEASURE = MeasureImpl.create(Measure.Level.OK);
+  private static final MeasureImpl NO_VALUE_MEASURE = MeasureImpl.createNoValue();
+
+  private static final List<MeasureImpl> MEASURES = ImmutableList.of(
+    INT_MEASURE, LONG_MEASURE, DOUBLE_MEASURE, STRING_MEASURE, TRUE_MEASURE, FALSE_MEASURE, NO_VALUE_MEASURE, LEVEL_MEASURE
+    );
+
+  @Test(expected = NullPointerException.class)
+  public void create_from_String_throws_NPE_if_arg_is_null() {
+    MeasureImpl.create((String) null);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_INT_MEASURE() {
+    return getMeasuresExcept(ValueType.INT);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_LONG_MEASURE() {
+    return getMeasuresExcept(ValueType.LONG);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_DOUBLE_MEASURE() {
+    return getMeasuresExcept(ValueType.DOUBLE);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_BOOLEAN_MEASURE() {
+    return getMeasuresExcept(ValueType.BOOLEAN);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_STRING_MEASURE() {
+    return getMeasuresExcept(ValueType.STRING);
+  }
+
+  @DataProvider
+  public static Object[][] all_but_LEVEL_MEASURE() {
+    return getMeasuresExcept(ValueType.LEVEL);
+  }
+
+  @DataProvider
+  public static Object[][] all() {
+    return from(MEASURES).transform(WrapInArray.INSTANCE).toArray(MeasureImpl[].class);
+  }
+
+  private static MeasureImpl[][] getMeasuresExcept(final ValueType valueType) {
+    return from(MEASURES)
+      .filter(new Predicate<MeasureImpl>() {
+        @Override
+        public boolean apply(@Nonnull MeasureImpl input) {
+            return input.getValueType() != valueType;
+        }
+      }).transform(WrapInArray.INSTANCE)
+        .toArray(MeasureImpl[].class);
+  }
+
+  @Test
+  public void create_from_int_has_INT_value_type() {
+    assertThat(INT_MEASURE.getValueType()).isEqualTo(ValueType.INT);
+  }
+
+  @Test
+  public void create_from_long_has_LONG_value_type() {
+    assertThat(LONG_MEASURE.getValueType()).isEqualTo(ValueType.LONG);
+  }
+
+  @Test
+  public void create_from_double_has_DOUBLE_value_type() {
+    assertThat(DOUBLE_MEASURE.getValueType()).isEqualTo(ValueType.DOUBLE);
+  }
+
+  @Test
+  public void create_from_boolean_has_BOOLEAN_value_type() {
+    assertThat(TRUE_MEASURE.getValueType()).isEqualTo(ValueType.BOOLEAN);
+    assertThat(FALSE_MEASURE.getValueType()).isEqualTo(ValueType.BOOLEAN);
+  }
+
+  @Test
+  public void create_from_String_has_STRING_value_type() {
+    assertThat(STRING_MEASURE.getValueType()).isEqualTo(ValueType.STRING);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_INT_MEASURE")
+  public void getIntValue_throws_ISE_for_all_value_types_except_INT(Measure measure) {
+    measure.getIntValue();
+  }
+
+  @Test
+  public void getIntValue_returns_value_for_INT_value_type() {
+    assertThat(INT_MEASURE.getIntValue()).isEqualTo(1);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_LONG_MEASURE")
+  public void getLongValue_throws_ISE_for_all_value_types_except_LONG(Measure measure) {
+    measure.getLongValue();
+  }
+
+  @Test
+  public void getLongValue_returns_value_for_LONG_value_type() {
+    assertThat(LONG_MEASURE.getLongValue()).isEqualTo(1);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_DOUBLE_MEASURE")
+  public void getDoubleValue_throws_ISE_for_all_value_types_except_DOUBLE(Measure measure) {
+    measure.getDoubleValue();
+  }
+
+  @Test
+  public void getDoubleValue_returns_value_for_DOUBLE_value_type() {
+    assertThat(DOUBLE_MEASURE.getDoubleValue()).isEqualTo(1d);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_BOOLEAN_MEASURE")
+  public void getBooleanValue_throws_ISE_for_all_value_types_except_BOOLEAN(Measure measure) {
+    measure.getBooleanValue();
+  }
+
+  @Test
+  public void getBooleanValue_returns_value_for_BOOLEAN_value_type() {
+    assertThat(TRUE_MEASURE.getBooleanValue()).isTrue();
+    assertThat(FALSE_MEASURE.getBooleanValue()).isFalse();
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_STRING_MEASURE")
+  public void getStringValue_throws_ISE_for_all_value_types_except_STRING(Measure measure) {
+    measure.getStringValue();
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all_but_LEVEL_MEASURE")
+  public void getLevelValue_throws_ISE_for_all_value_types_except_LEVEL(Measure measure) {
+    measure.getLevelValue();
+  }
+
+  @Test
+  public void getData_returns_null_for_NO_VALUE_value_type() {
+    assertThat(NO_VALUE_MEASURE.getData()).isNull();
+  }
+
+  @Test
+  @UseDataProvider("all_but_STRING_MEASURE")
+  public void getData_returns_null_for_all_value_types_but_STRING_when_not_set(Measure measure) {
+    assertThat(measure.getData()).isNull();
+  }
+
+  @Test
+  public void getData_returns_value_for_STRING_value_type() {
+    assertThat(STRING_MEASURE.getData()).isEqualTo(STRING_MEASURE.getStringValue());
+  }
+
+  @Test
+  @UseDataProvider("all")
+  public void hasAlertStatus_returns_false_for_all_value_types_when_not_set(Measure measure) {
+    assertThat(measure.hasQualityGateStatus()).isFalse();
+  }
+
+  @Test(expected = IllegalStateException.class)
+  @UseDataProvider("all")
+  public void getAlertStatus_throws_ISE_for_all_value_types_when_not_set(Measure measure) {
+    measure.getQualityGateStatus();
+  }
+
+  @Test
+  public void getAlertStatus_returns_argument_from_setAlertStatus() {
+    Measure.QualityGateStatus someStatus = new Measure.QualityGateStatus(Measure.Level.OK);
+
+    assertThat(MeasureImpl.create(true, null).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create(false, null).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create((int) 1, null).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create((long) 1, null).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create((double) 1, null).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create("str").setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+    assertThat(MeasureImpl.create(Measure.Level.OK).setQualityGateStatus(someStatus).getQualityGateStatus()).isEqualTo(someStatus);
+  }
+
+  @Test(expected = NullPointerException.class)
+  @UseDataProvider("all")
+  public void setAlertStatus_throws_NPE_if_arg_is_null(MeasureImpl measure) {
+    measure.setQualityGateStatus(null);
+  }
+
+  @Test
+  public void getData_returns_argument_from_factory_method() {
+    String someData = "lololool";
+
+    assertThat(MeasureImpl.create(true, someData).getData()).isEqualTo(someData);
+    assertThat(MeasureImpl.create(false, someData).getData()).isEqualTo(someData);
+    assertThat(MeasureImpl.create((int) 1, someData).getData()).isEqualTo(someData);
+    assertThat(MeasureImpl.create((long) 1, someData).getData()).isEqualTo(someData);
+    assertThat(MeasureImpl.create((double) 1, someData).getData()).isEqualTo(someData);
+  }
+
+  @Test
+  public void measure_of_value_type_LEVEL_has_no_data() {
+    assertThat(LEVEL_MEASURE.getData()).isNull();
+  }
+
+  private enum WrapInArray implements Function<MeasureImpl, MeasureImpl[]> {
+    INSTANCE;
+
+    @Nullable
+    @Override
+    public MeasureImpl[] apply(@Nonnull MeasureImpl input) {
+      return new MeasureImpl[] {input};
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java
new file mode 100644 (file)
index 0000000..4a3d0f1
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.measure;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import javax.annotation.CheckForNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
+import org.sonar.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.batch.BatchReportReaderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.measure.persistence.MeasureDao;
+import org.sonar.server.metric.persistence.MetricDao;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class MeasureRepositoryImplTest {
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+  public static final String SOME_DATA = "some data";
+  @Rule
+  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+  private static final String FILE_COMPONENT_KEY = "file cpt key";
+  private static final DumbComponent FILE_COMPONENT = DumbComponent.builder(Component.Type.FILE, 1).setKey(FILE_COMPONENT_KEY).build();
+  private static final DumbComponent OTHER_COMPONENT = DumbComponent.builder(Component.Type.FILE, 2).setKey("some other key").build();
+  private static final String METRIC_KEY_1 = "metric 1";
+  private static final int METRIC_ID_1 = 1;
+  private static final String METRIC_KEY_2 = "metric 2";
+  private static final int METRIC_ID_2 = 2;
+  private final Metric metric1 = mock(Metric.class);
+  private final Metric metric2 = mock(Metric.class);
+  private static final long LAST_SNAPSHOT_ID = 123;
+  private static final long OTHER_SNAPSHOT_ID = 369;
+  private static final long COMPONENT_ID = 567;
+  private static final Measure SOME_MEASURE = mock(Measure.class);
+
+  private DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new SnapshotDao(), new MetricDao(), new ComponentDao());
+  private MetricRepository metricRepository = mock(MetricRepository.class);
+  private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository);
+
+  private DbClient mockedDbClient = mock(DbClient.class);
+  private BatchReportReader mockBatchReportReader = mock(BatchReportReader.class);
+  private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository);
+
+  @CheckForNull
+  private DbSession dbSession;
+
+  @Before
+  public void setUp() throws Exception {
+    when(metric1.getKey()).thenReturn(METRIC_KEY_1);
+    when(metric1.getMetricType()).thenReturn(Metric.MetricType.STRING);
+    when(metric2.getKey()).thenReturn(METRIC_KEY_2);
+    when(metric2.getMetricType()).thenReturn(Metric.MetricType.STRING);
+
+    // references to metrics are consistent with DB by design
+    when(metricRepository.getByKey(METRIC_KEY_1)).thenReturn(metric1);
+    when(metricRepository.getByKey(METRIC_KEY_2)).thenReturn(metric2);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (dbSession != null) {
+      dbSession.close();
+    }
+  }
+
+  @Test
+  public void getBaseMeasure_throws_NPE_and_does_not_open_session_if_component_is_null() {
+    try {
+      underTestWithMock.getBaseMeasure(null, metric1);
+      fail("an NPE should have been raised");
+    } catch (NullPointerException e) {
+      verifyZeroInteractions(mockedDbClient);
+    }
+  }
+
+  @Test
+  public void getBaseMeasure_throws_NPE_and_does_not_open_session_if_metric_is_null() {
+    try {
+      underTestWithMock.getBaseMeasure(FILE_COMPONENT, null);
+      fail("an NPE should have been raised");
+    } catch (NullPointerException e) {
+      verifyZeroInteractions(mockedDbClient);
+    }
+  }
+
+  @Test
+  public void getBaseMeasure_returns_absent_if_measure_does_not_exist_in_DB() {
+    Optional<Measure> res = underTest.getBaseMeasure(FILE_COMPONENT, metric1);
+
+    assertThat(res).isAbsent();
+  }
+
+  @Test
+  public void getBaseMeasure_returns_Measure_if_measure_of_last_snapshot_only_in_DB() {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+    dbSession = dbClient.openSession(false);
+    dbClient.measureDao().insert(dbSession, createMeasureDto(METRIC_ID_1, LAST_SNAPSHOT_ID));
+    dbClient.measureDao().insert(dbSession, createMeasureDto(METRIC_ID_2, OTHER_SNAPSHOT_ID));
+    dbSession.commit();
+
+    // metric 1 is associated to snapshot with "last=true"
+    Optional<Measure> res = underTest.getBaseMeasure(FILE_COMPONENT, metric1);
+
+    assertThat(res).isPresent();
+    assertThat(res.get().getStringValue()).isEqualTo(SOME_DATA);
+
+    // metric 2 is associated to snapshot with "last=false" => not retrieved
+    res = underTest.getBaseMeasure(FILE_COMPONENT, metric2);
+
+    assertThat(res).isAbsent();
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void add_throws_NPE_if_Component_argument_is_null() {
+    underTest.add(null, metric1, mock(Measure.class));
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void add_throws_NPE_if_Component_metric_is_null() {
+    underTest.add(FILE_COMPONENT, null, mock(Measure.class));
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void add_throws_NPE_if_Component_measure_is_null() {
+    underTest.add(FILE_COMPONENT, metric1, null);
+  }
+
+  @Test(expected = UnsupportedOperationException.class)
+  public void add_throws_UOE_if_measure_already_exists() {
+    underTest.add(FILE_COMPONENT, metric1, mock(Measure.class));
+    underTest.add(FILE_COMPONENT, metric1, mock(Measure.class));
+  }
+
+  @Test
+  public void getRawMeasure_throws_NPE_without_reading_batch_report_if_component_arg_is_null() {
+    try {
+      underTestWithMock.getRawMeasure(null, metric1);
+      fail("an NPE should have been raised");
+    } catch (NullPointerException e) {
+      verifyNoMoreInteractions(mockBatchReportReader);
+    }
+  }
+
+  @Test
+  public void getRawMeasure_throws_NPE_without_reading_batch_report_if_metric_arg_is_null() {
+    try {
+      underTestWithMock.getRawMeasure(FILE_COMPONENT, null);
+      fail("an NPE should have been raised");
+    } catch (NullPointerException e) {
+      verifyNoMoreInteractions(mockBatchReportReader);
+    }
+  }
+
+  @Test
+  public void getRawMeasure_returns_measure_added_through_add_method() {
+    underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
+
+    Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
+
+    assertThat(res).isPresent();
+    assertThat(res.get()).isSameAs(SOME_MEASURE);
+
+    // make sure we really match on the specified component and metric
+    assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isAbsent();
+    assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isAbsent();
+  }
+
+  @Test
+  public void getRawMeasure_returns_measure_from_batch_if_not_added_through_add_method() {
+    String value = "trololo";
+
+    reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of(
+        BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(value).build()
+    ));
+
+    Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
+
+    assertThat(res).isPresent();
+    assertThat(res.get().getStringValue()).isEqualTo(value);
+
+    // make sure we really match on the specified component and metric
+    assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isAbsent();
+    assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isAbsent();
+  }
+
+  @Test
+  public void getRawMeasure_retrieves_added_measure_over_batch_measure() {
+    reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of(
+        BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build()
+    ));
+
+    Measure addedMeasure = mock(Measure.class);
+    underTest.add(FILE_COMPONENT, metric1, addedMeasure);
+
+    Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
+
+    assertThat(res).isPresent();
+    assertThat(res.get()).isSameAs(addedMeasure);
+  }
+
+  private static MeasureDto createMeasureDto(int metricId, long snapshotId) {
+    return new MeasureDto()
+        .setComponentId(COMPONENT_ID)
+        .setSnapshotId(snapshotId)
+        .setData(SOME_DATA)
+        .setMetricId(metricId);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java
new file mode 100644 (file)
index 0000000..9ff5e51
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MetricImplTest {
+
+  private static final String SOME_KEY = "key";
+  private static final String SOME_NAME = "name";
+
+  @Test(expected = NullPointerException.class)
+  public void constructor_throws_NPE_if_key_arg_is_null() {
+    new MetricImpl(null, SOME_NAME, Metric.MetricType.BOOL);
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void constructor_throws_NPE_if_name_arg_is_null() {
+    new MetricImpl(SOME_KEY, null, Metric.MetricType.BOOL);
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void constructor_throws_NPE_if_valueType_arg_is_null() {
+    new MetricImpl(SOME_KEY, SOME_NAME, null);
+  }
+
+  @Test
+  public void verify_getters() {
+    MetricImpl metric = new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT);
+
+    assertThat(metric.getKey()).isEqualTo(SOME_KEY);
+    assertThat(metric.getName()).isEqualTo(SOME_NAME);
+    assertThat(metric.getMetricType()).isEqualTo(Metric.MetricType.FLOAT);
+  }
+
+  @Test
+  public void equals_uses_key_and_name() {
+    MetricImpl expected = new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT);
+
+    assertThat(new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT)).isEqualTo(expected);
+    assertThat(new MetricImpl("some other key", SOME_NAME, Metric.MetricType.FLOAT)).isNotEqualTo(expected);
+    assertThat(new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.STRING)).isNotEqualTo(expected);
+  }
+
+  @Test
+  public void equals_ignores_valueType() {
+    assertThat(new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT)).isEqualTo(new MetricImpl(SOME_KEY, "some other name", Metric.MetricType.FLOAT));
+  }
+
+  @Test
+  public void hashcode_uses_only_key_and_valueType() {
+    int expected = new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT).hashCode();
+
+    assertThat(new MetricImpl(SOME_KEY, "some other name", Metric.MetricType.FLOAT).hashCode()).isEqualTo(expected);
+  }
+
+  @Test
+  public void all_fields_are_displayed_in_toString() {
+    assertThat(new MetricImpl(SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT).toString())
+      .isEqualTo("MetricImpl{key=key, name=name, metricType=FLOAT}");
+
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java
new file mode 100644 (file)
index 0000000..fa1e114
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.computation.metric;
+
+import javax.annotation.CheckForNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.metric.persistence.MetricDao;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class MetricRepositoryImplTest {
+  private static final String SOME_KEY = "some key";
+  private static final String SOME_NAME = "the short name";
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+
+  private DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MetricDao());
+  private MetricRepository underTest = new MetricRepositoryImpl(dbClient);
+
+  @CheckForNull
+  private DbSession dbSession;
+
+  @Before
+  public void setUp() throws Exception {
+    dbTester.truncateTables();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (dbSession != null) {
+      dbSession.close();
+    }
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void findByKey_throws_NPE_if_arg_is_null() {
+    underTest.getByKey(null);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void findByKey_throws_ISE_of_Metric_does_not_exist() {
+    underTest.getByKey(SOME_KEY);
+  }
+
+  @Test
+  public void verify_mapping_and_valueType_conversion_from_DB() {
+    dbSession = dbClient.openSession(false);
+
+    for (Metric.MetricType metricType : Metric.MetricType.values()) {
+      verify_mapping_and_valueType_conversion_from_DB_impl(metricType.name(), metricType);
+    }
+  }
+
+  private void verify_mapping_and_valueType_conversion_from_DB_impl(String valueType, Metric.MetricType expected) {
+    MetricDto metricDto = new MetricDto().setKey(SOME_KEY + valueType).setShortName(SOME_NAME).setValueType(valueType);
+
+    dbClient.metricDao().insert(dbSession, metricDto);
+    dbSession.commit();
+
+    Metric metric = underTest.getByKey(metricDto.getKey());
+
+    assertThat(metric.getKey()).isEqualTo(metricDto.getKey());
+    assertThat(metric.getName()).isEqualTo(metricDto.getShortName());
+    assertThat(metric.getMetricType()).isEqualTo(expected);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void findByKey_throws_IAE_if_valueType_can_not_be_parsed() {
+    MetricDto metricDto = new MetricDto().setKey(SOME_KEY).setShortName(SOME_NAME).setValueType("trololo");
+
+    dbSession = dbClient.openSession(false);
+    dbClient.metricDao().insert(dbSession, metricDto);
+    dbSession.commit();
+
+    underTest.getByKey(SOME_KEY);
+  }
+}
index cf6df3a9bd10016670f8f7f81b78d0323c1246d7..efecd5049b161efe2ba3bb3670d870b10651e19b 100644 (file)
 package org.sonar.server.computation.step;
 
 import com.google.common.base.Optional;
-import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.sonar.api.notifications.Notification;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.computation.event.Event;
 import org.sonar.server.computation.event.EventRepository;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureImpl;
 import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.notification.NotificationManager;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -41,189 +44,190 @@ import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
-import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS;
-import static org.sonar.server.computation.component.DumbComponent.DUMB_PROJECT;
+import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
+import static org.sonar.server.computation.measure.Measure.Level.ERROR;
+import static org.sonar.server.computation.measure.Measure.Level.OK;
+import static org.sonar.server.computation.measure.Measure.Level.WARN;
 
 public class QualityGateEventsStepTest {
-
-  static final String INVALID_STATUS = "trololo";
-  static final String DESCRIPTION = "gate errors";
+  private static final DumbComponent PROJECT_COMPONENT = DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("uuid 1").setKey("key 1")
+    .addChildren(DumbComponent.builder(Component.Type.MODULE, 2).build())
+    .build();
+  private static final String INVALID_ALERT_STATUS = "trololo";
+  private static final String ALERT_TEXT = "alert text";
+  private static final Measure.QualityGateStatus OK_QUALITY_GATE_STATUS = new Measure.QualityGateStatus(OK, ALERT_TEXT);
+  private static final Measure.QualityGateStatus WARN_QUALITY_GATE_STATUS = new Measure.QualityGateStatus(WARN, ALERT_TEXT);
+  private static final Measure.QualityGateStatus ERROR_QUALITY_GATE_STATUS = new Measure.QualityGateStatus(ERROR, ALERT_TEXT);
 
   @Rule
   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
 
-  ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
-  ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
+  private ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
+  private ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
+
+  private Metric alertStatusMetric = mock(Metric.class);
 
-  EventRepository eventRepository = mock(EventRepository.class);
-  MeasureRepository measureRepository = mock(MeasureRepository.class);
-  NotificationManager notificationManager = mock(NotificationManager.class);
-  QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, eventRepository, measureRepository, notificationManager);
+  private MetricRepository metricRepository = mock(MetricRepository.class);
+  private MeasureRepository measureRepository = mock(MeasureRepository.class);
+  private EventRepository eventRepository = mock(EventRepository.class);
+  private NotificationManager notificationManager = mock(NotificationManager.class);
+  private QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationManager);
 
   @Before
   public void setUp() throws Exception {
-    treeRootHolder.setRoot(DUMB_PROJECT);
+    when(metricRepository.getByKey(ALERT_STATUS_KEY)).thenReturn(alertStatusMetric);
+    treeRootHolder.setRoot(PROJECT_COMPONENT);
   }
 
   @Test
-  public void no_event_if_no_status_measure() {
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.<BatchReport.Measure>absent());
+  public void no_event_if_no_raw_ALERT_STATUS_measure() {
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(Optional.<Measure>absent());
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verifyNoMoreInteractions(measureRepository, eventRepository, notificationManager);
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verifyNoMoreInteractions(measureRepository, eventRepository);
   }
 
   @Test
-  public void no_event_created_if_status_measure_is_null() {
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.of(BatchReport.Measure.newBuilder().build()));
+  public void no_event_created_if_raw_ALERT_STATUS_measure_is_null() {
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue()));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verifyNoMoreInteractions(measureRepository, eventRepository, notificationManager);
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verifyNoMoreInteractions(measureRepository, eventRepository);
+  }
+
+  private static Optional<Measure> of(MeasureImpl measure) {
+    return Optional.of((Measure) measure);
   }
 
   @Test
-  public void no_event_created_if_status_measure_has_unsupported_value() {
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.of(BatchReport.Measure.newBuilder().setAlertStatus(INVALID_STATUS).build()));
+  public void no_event_created_if_raw_ALERT_STATUS_measure_is_unsupported_value() {
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.create(INVALID_ALERT_STATUS)));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verifyNoMoreInteractions(measureRepository, eventRepository, notificationManager);
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verifyNoMoreInteractions(measureRepository, eventRepository);
   }
 
   @Test
-  public void no_event_created_if_OK_and_no_base_status() {
-    String alertStatus = "OK";
+  public void no_event_created_if_no_base_ALERT_STATUS_and_raw_is_OK() {
+    Measure.QualityGateStatus someQGStatus = new Measure.QualityGateStatus(Measure.Level.OK);
 
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(createBatchReportMeasure(alertStatus, null));
-    when(measureRepository.findPrevious(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.<MeasureDto>absent());
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue().setQualityGateStatus(someQGStatus)));
+    when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue()));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verify(measureRepository).findPrevious(DUMB_PROJECT, ALERT_STATUS);
-    verifyNoMoreInteractions(measureRepository, eventRepository, notificationManager);
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verifyNoMoreInteractions(measureRepository, eventRepository);
   }
 
   @Test
-  public void event_created_if_WARN_and_no_base_status() {
-    verify_event_created_if_no_base_status("WARN", "Orange", null);
+  public void event_created_if_no_base_ALERT_STATUS_and_raw_is_WARN() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(WARN, "Orange");
   }
 
   @Test
-  public void event_created_if_ERROR_and_no_base_status() {
-    verify_event_created_if_no_base_status("ERROR", "Red", null);
+  public void event_created_if_base_ALERT_STATUS_and_raw_is_ERROR() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(ERROR, "Red");
   }
 
   @Test
-  public void event_created_if_ERROR_and_base_measure_has_no_status() {
-    verify_event_created_if_no_base_status("ERROR", "Red", new MeasureDto());
+  public void event_created_if_base_ALERT_STATUS_has_no_alertStatus_and_raw_is_ERROR() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(ERROR, "Red");
   }
 
   @Test
-  public void event_created_if_WARN_and_base_measure_has_no_status() {
-    verify_event_created_if_no_base_status("WARN", "Orange", new MeasureDto());
+  public void event_created_if_base_ALERT_STATUS_has_no_alertStatus_and_raw_is_WARN() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(WARN, "Orange");
   }
 
   @Test
-  public void event_created_if_ERROR_and_base_status_has_invalid_value() {
-    verify_event_created_if_no_base_status("ERROR", "Red", new MeasureDto().setAlertStatus(INVALID_STATUS));
+  public void event_created_if_base_ALERT_STATUS_has_invalid_alertStatus_and_raw_is_ERROR() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(ERROR, "Red");
   }
 
   @Test
-  public void event_created_if_WARN_and_base_status_has_invalid_value() {
-    verify_event_created_if_no_base_status("WARN", "Orange", new MeasureDto().setAlertStatus(INVALID_STATUS));
+  public void event_created_if_base_ALERT_STATUS_has_invalid_alertStatus_and_raw_is_WARN() {
+    verify_event_created_if_no_base_ALERT_STATUS_measure(WARN, "Orange");
   }
 
-  private void verify_event_created_if_no_base_status(String status, String expectedLabel, @Nullable MeasureDto measureDto) {
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(createBatchReportMeasure(status, DESCRIPTION));
-    when(measureRepository.findPrevious(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.fromNullable(measureDto));
+  private void verify_event_created_if_no_base_ALERT_STATUS_measure(Measure.Level rawAlterStatus, String expectedEventName) {
+    Measure.QualityGateStatus someQGStatus = new Measure.QualityGateStatus(rawAlterStatus, ALERT_TEXT);
+
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue().setQualityGateStatus(someQGStatus)));
+    when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue()));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verify(measureRepository).findPrevious(DUMB_PROJECT, ALERT_STATUS);
-    verify(eventRepository).add(eq(DUMB_PROJECT), eventArgumentCaptor.capture());
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
     verifyNoMoreInteractions(measureRepository, eventRepository);
 
     Event event = eventArgumentCaptor.getValue();
     assertThat(event.getCategory()).isEqualTo(Event.Category.ALERT);
-    assertThat(event.getName()).isEqualTo(expectedLabel);
-    assertThat(event.getDescription()).isEqualTo(DESCRIPTION);
+    assertThat(event.getName()).isEqualTo(expectedEventName);
+    assertThat(event.getDescription()).isEqualTo(ALERT_TEXT);
     assertThat(event.getData()).isNull();
-
-    verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
-    Notification notification = notificationArgumentCaptor.getValue();
-    assertThat(notification.getType()).isEqualTo("alerts");
-    assertThat(notification.getFieldValue("projectKey")).isEqualTo(DUMB_PROJECT.getKey());
-    assertThat(notification.getFieldValue("projectUuid")).isEqualTo(DUMB_PROJECT.getUuid());
-    assertThat(notification.getFieldValue("projectName")).isEqualTo(DUMB_PROJECT.getName());
-    assertThat(notification.getFieldValue("alertLevel")).isEqualTo(status);
-    assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel);
   }
 
   @Test
-  public void no_event_created_if_status_same_as_base() {
-    String alertStatus = "OK";
-
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(createBatchReportMeasure(alertStatus, DESCRIPTION));
-    when(measureRepository.findPrevious(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.of(new MeasureDto().setAlertStatus(alertStatus)));
+  public void no_event_created_if_base_ALERT_STATUS_measure_but_status_is_the_same() {
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue().setQualityGateStatus(OK_QUALITY_GATE_STATUS)));
+    when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue().setQualityGateStatus(OK_QUALITY_GATE_STATUS)));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verify(measureRepository).findPrevious(DUMB_PROJECT, ALERT_STATUS);
-    verifyNoMoreInteractions(measureRepository, eventRepository, notificationManager);
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verifyNoMoreInteractions(measureRepository, eventRepository);
   }
 
   @Test
-  public void event_created_if_status_changed() {
-    verify_event_created_if_status_changed("OK", "WARN", "Orange (was Green)");
-    verify_event_created_if_status_changed("OK", "ERROR", "Red (was Green)");
-    verify_event_created_if_status_changed("WARN", "OK", "Green (was Orange)");
-    verify_event_created_if_status_changed("WARN", "ERROR", "Red (was Orange)");
-    verify_event_created_if_status_changed("ERROR", "OK", "Green (was Red)");
-    verify_event_created_if_status_changed("ERROR", "WARN", "Orange (was Red)");
+  public void event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed() {
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(OK, WARN_QUALITY_GATE_STATUS, "Orange (was Green)");
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(OK, ERROR_QUALITY_GATE_STATUS, "Red (was Green)");
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(WARN, OK_QUALITY_GATE_STATUS, "Green (was Orange)");
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(WARN, ERROR_QUALITY_GATE_STATUS, "Red (was Orange)");
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(ERROR, OK_QUALITY_GATE_STATUS, "Green (was Red)");
+    verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(ERROR, WARN_QUALITY_GATE_STATUS, "Orange (was Red)");
   }
 
-  private void verify_event_created_if_status_changed(String baseStatus, String status, String expectedLabel) {
-    when(measureRepository.findCurrent(DUMB_PROJECT, ALERT_STATUS)).thenReturn(createBatchReportMeasure(status, DESCRIPTION));
-    when(measureRepository.findPrevious(DUMB_PROJECT, ALERT_STATUS)).thenReturn(Optional.of(new MeasureDto().setAlertStatus(baseStatus)));
+  private void verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(Measure.Level previousAlertStatus,
+    Measure.QualityGateStatus newQualityGateStatus, String expectedLabel) {
+    when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(MeasureImpl.createNoValue().setQualityGateStatus(newQualityGateStatus)));
+    when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(
+      of(MeasureImpl.createNoValue().setQualityGateStatus(new Measure.QualityGateStatus(previousAlertStatus))));
 
     underTest.execute();
 
-    verify(measureRepository).findCurrent(DUMB_PROJECT, ALERT_STATUS);
-    verify(measureRepository).findPrevious(DUMB_PROJECT, ALERT_STATUS);
-    verify(eventRepository).add(eq(DUMB_PROJECT), eventArgumentCaptor.capture());
+    verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
+    verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
     verifyNoMoreInteractions(measureRepository, eventRepository);
 
     Event event = eventArgumentCaptor.getValue();
     assertThat(event.getCategory()).isEqualTo(Event.Category.ALERT);
     assertThat(event.getName()).isEqualTo(expectedLabel);
-    assertThat(event.getDescription()).isEqualTo(DESCRIPTION);
+    assertThat(event.getDescription()).isEqualTo(ALERT_TEXT);
     assertThat(event.getData()).isNull();
 
     verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
     Notification notification = notificationArgumentCaptor.getValue();
     assertThat(notification.getType()).isEqualTo("alerts");
-    assertThat(notification.getFieldValue("projectKey")).isEqualTo(DUMB_PROJECT.getKey());
-    assertThat(notification.getFieldValue("projectUuid")).isEqualTo(DUMB_PROJECT.getUuid());
-    assertThat(notification.getFieldValue("projectName")).isEqualTo(DUMB_PROJECT.getName());
-    assertThat(notification.getFieldValue("alertLevel")).isEqualTo(status);
+    assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey());
+    assertThat(notification.getFieldValue("projectUuid")).isEqualTo(PROJECT_COMPONENT.getUuid());
+    assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName());
+    assertThat(notification.getFieldValue("alertLevel")).isEqualTo(newQualityGateStatus.getStatus().name());
     assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel);
 
     reset(measureRepository, eventRepository, notificationManager);
   }
 
-  private static Optional<BatchReport.Measure> createBatchReportMeasure(String status, @Nullable String description) {
-    BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder().setAlertStatus(status);
-    if (description != null) {
-      builder.setAlertText(description);
-    }
-    return Optional.of(builder.build());
-  }
 }
index d491d4a581f97d6e96c78f61fbb79f4bd71c134b..2876c95c2f606d98be2963b727815466604ad63a 100644 (file)
@@ -36,16 +36,18 @@ import org.mockito.stubbing.Answer;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.resources.AbstractLanguage;
 import org.sonar.api.resources.Language;
-import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.UtcDateUtils;
-import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.server.computation.batch.TreeRootHolderRule;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.computation.event.Event;
 import org.sonar.server.computation.event.EventRepository;
 import org.sonar.server.computation.language.LanguageRepository;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureImpl;
 import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.computation.qualityprofile.QPMeasureData;
 import org.sonar.server.computation.qualityprofile.QualityProfile;
 
@@ -71,21 +73,25 @@ public class QualityProfileEventsStepTest {
   private static final String LANGUAGE_KEY_2 = "language_key_2";
   private static final String LANGUAGE_KEY_3 = "languageKey3";
 
+  private MetricRepository metricRepository = mock(MetricRepository.class);
   private MeasureRepository measureRepository = mock(MeasureRepository.class);
   private LanguageRepository languageRepository = mock(LanguageRepository.class);
   private EventRepository eventRepository = mock(EventRepository.class);
   private ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
 
-  private QualityProfileEventsStep underTest = new QualityProfileEventsStep(treeRootHolder, measureRepository, eventRepository, languageRepository);
+  private Metric qualityProfileMetric = mock(Metric.class);
+
+  private QualityProfileEventsStep underTest = new QualityProfileEventsStep(treeRootHolder, metricRepository, measureRepository, languageRepository, eventRepository);
 
   @Before
   public void setUp() throws Exception {
+    when(metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY)).thenReturn(qualityProfileMetric);
     treeRootHolder.setRoot(DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("uuid").setKey("key").build());
   }
 
   @Test
-  public void no_effect_if_no_previous_measure() {
-    when(measureRepository.findPrevious(treeRootHolder.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<MeasureDto>absent());
+  public void no_effect_if_no_base_measure() {
+    when(measureRepository.getBaseMeasure(treeRootHolder.getRoot(), qualityProfileMetric)).thenReturn(Optional.<Measure>absent());
 
     underTest.execute();
 
@@ -93,15 +99,15 @@ public class QualityProfileEventsStepTest {
   }
 
   @Test(expected = IllegalStateException.class)
-  public void ISE_if_no_current_measure() {
-    when(measureRepository.findPrevious(treeRootHolder.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto()));
-    when(measureRepository.findCurrent(treeRootHolder.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<BatchReport.Measure>absent());
+  public void ISE_if_no_raw_measure() {
+    when(measureRepository.getBaseMeasure(treeRootHolder.getRoot(), qualityProfileMetric)).thenReturn(Optional.of(newMeasure()));
+    when(measureRepository.getRawMeasure(treeRootHolder.getRoot(), qualityProfileMetric)).thenReturn(Optional.<Measure>absent());
 
     underTest.execute();
   }
 
   @Test
-  public void no_event_if_no_qp_now_nor_before() {
+  public void no_event_if_no_base_nor_row_QualityProfile_measure() {
     mockMeasures(treeRootHolder.getRoot(), null, null);
 
     underTest.execute();
@@ -248,8 +254,8 @@ public class QualityProfileEventsStepTest {
   }
 
   private void mockMeasures(Component component, @Nullable QualityProfile[] previous, @Nullable QualityProfile[] current) {
-    when(measureRepository.findPrevious(component, CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto(previous)));
-    when(measureRepository.findCurrent(component, CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newQPBatchMeasure(current)));
+    when(measureRepository.getBaseMeasure(component, qualityProfileMetric)).thenReturn(Optional.of(newMeasure(previous)));
+    when(measureRepository.getRawMeasure(component, qualityProfileMetric)).thenReturn(Optional.of(newMeasure(current)));
   }
 
   private static void verifyEvent(Event event, String expectedName, @Nullable String expectedData) {
@@ -274,12 +280,8 @@ public class QualityProfileEventsStepTest {
     return qps;
   }
 
-  private static MeasureDto newMeasureDto(@Nullable QualityProfile... qps) {
-    return new MeasureDto().setData(toJson(qps));
-  }
-
-  private static BatchReport.Measure newQPBatchMeasure(@Nullable QualityProfile... qps) {
-    return BatchReport.Measure.newBuilder().setStringValue(toJson(qps)).build();
+  private static Measure newMeasure(@Nullable QualityProfile... qps) {
+    return MeasureImpl.create(toJson(qps));
   }
 
   private static String toJson(@Nullable QualityProfile... qps) {
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/measure/MeasureRepositoryImplTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/measure/MeasureRepositoryImplTest/shared.xml
new file mode 100644 (file)
index 0000000..19ce315
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+    <projects id="567" kee="file cpt key" enabled="[true]"/>
+    <snapshots id="123" project_id="567" islast="[true]"/>
+    <snapshots id="369" project_id="567" islast="[false]"/>
+    <metrics id="1" name="metric 1"  />
+    <metrics id="2" name="metric 2" />
+</dataset>