Browse Source

SONAR-7488 support PostProjectAnalysisTask in report CE task

tags/5.5-RC1
Sébastien Lesaint 8 years ago
parent
commit
a1418d7865
29 changed files with 2168 additions and 34 deletions
  1. 4
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
  2. 54
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/CeTaskImpl.java
  3. 183
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ConditionImpl.java
  4. 94
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ConditionToCondition.java
  5. 192
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/PostProjectAnalysisTasksExecutor.java
  6. 62
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ProjectImpl.java
  7. 72
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/QualityGateImpl.java
  8. 23
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/posttask/package-info.java
  9. 73
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/ConditionStatus.java
  10. 33
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/MutableQualityGateStatusHolder.java
  11. 7
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGate.java
  12. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateServiceImpl.java
  13. 24
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatus.java
  14. 41
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolder.java
  15. 62
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolderImpl.java
  16. 78
    3
      server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java
  17. 63
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/CeTaskImplTest.java
  18. 168
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ConditionImplTest.java
  19. 163
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ConditionToConditionTest.java
  20. 197
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/PostProjectAnalysisTasksExecutorTest.java
  21. 75
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ProjectImplTest.java
  22. 96
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/posttask/QualityGateImplTest.java
  23. 99
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionStatusTest.java
  24. 51
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/MutableQualityGateStatusHolderRule.java
  25. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateHolderImplTest.java
  26. 2
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateServiceImplTest.java
  27. 117
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolderImplTest.java
  28. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityGateLoadingStepTest.java
  29. 132
    27
      server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityGateMeasuresStepTest.java

+ 4
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java View File

@@ -77,9 +77,11 @@ import org.sonar.server.computation.measure.MeasureRepositoryImpl;
import org.sonar.server.computation.measure.MeasureToMeasureDto;
import org.sonar.server.computation.metric.MetricModule;
import org.sonar.server.computation.period.PeriodsHolderImpl;
import org.sonar.server.computation.posttask.PostProjectAnalysisTasksExecutor;
import org.sonar.server.computation.qualitygate.EvaluationResultTextConverterImpl;
import org.sonar.server.computation.qualitygate.QualityGateHolderImpl;
import org.sonar.server.computation.qualitygate.QualityGateServiceImpl;
import org.sonar.server.computation.qualitygate.QualityGateStatusHolderImpl;
import org.sonar.server.computation.qualitymodel.NewQualityModelMeasuresVisitor;
import org.sonar.server.computation.qualitymodel.QualityModelMeasuresVisitor;
import org.sonar.server.computation.qualitymodel.RatingSettings;
@@ -124,6 +126,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
*/
private static List componentClasses() {
return Arrays.asList(
PostProjectAnalysisTasksExecutor.class,
ComputationStepExecutor.class,

// File System
@@ -138,6 +141,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
TreeRootHolderImpl.class,
PeriodsHolderImpl.class,
QualityGateHolderImpl.class,
QualityGateStatusHolderImpl.class,
RatingSettings.class,
ActiveRulesHolderImpl.class,
MeasureComputersHolderImpl.class,

+ 54
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/CeTaskImpl.java View File

@@ -0,0 +1,54 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.posttask.CeTask;

import static java.util.Objects.requireNonNull;

@Immutable
class CeTaskImpl implements CeTask {
private final String id;
private final Status status;

CeTaskImpl(String id, Status status) {
this.id = requireNonNull(id, "uuid can not be null");
this.status = requireNonNull(status, "status can not be null");
}

@Override
public String getId() {
return id;
}

@Override
public Status getStatus() {
return status;
}

@Override
public String toString() {
return "CeTaskImpl{" +
"id='" + id + '\'' +
", status=" + status +
'}';
}
}

+ 183
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ConditionImpl.java View File

@@ -0,0 +1,183 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.posttask.QualityGate;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.ce.posttask.QualityGate.EvaluationStatus.NO_VALUE;

@Immutable
class ConditionImpl implements QualityGate.Condition {
private final QualityGate.EvaluationStatus status;
private final String metricKey;
private final QualityGate.Operator operator;
@CheckForNull
private final String errorThreshold;
@CheckForNull
private final String warningThreshold;
private final boolean onLeakPeriod;
@CheckForNull
private final String value;

private ConditionImpl(Builder builder) {
requireNonNull(builder.status, "status can not be null");
requireNonNull(builder.metricKey, "metricKey can not be null");
requireNonNull(builder.operator, "operator can not be null");
verifyThresholds(builder);
verifyValue(builder);

this.status = builder.status;
this.metricKey = builder.metricKey;
this.operator = builder.operator;
this.errorThreshold = builder.errorThreshold;
this.warningThreshold = builder.warningThreshold;
this.onLeakPeriod = builder.onLeakPeriod;
this.value = builder.value;
}

private static void verifyThresholds(Builder builder) {
checkArgument(
builder.errorThreshold != null || builder.warningThreshold != null,
"At least one of errorThreshold and warningThreshold must be non null");
}

private static void verifyValue(Builder builder) {
if (builder.status == NO_VALUE) {
checkArgument(builder.value == null, "value must be null when status is %s", NO_VALUE);
} else {
checkArgument(builder.value != null, "value can not be null when status is not %s", NO_VALUE);
}
}

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {
private String metricKey;
private QualityGate.Operator operator;
@CheckForNull
private String errorThreshold;
@CheckForNull
private String warningThreshold;
private boolean onLeakPeriod;
@CheckForNull
private String value;
private QualityGate.EvaluationStatus status;

private Builder() {
// enforce use of static method
}

public Builder setMetricKey(String metricKey) {
this.metricKey = metricKey;
return this;
}

public Builder setOperator(QualityGate.Operator operator) {
this.operator = operator;
return this;
}

public Builder setErrorThreshold(String errorThreshold) {
this.errorThreshold = errorThreshold;
return this;
}

public Builder setWarningThreshold(String warningThreshold) {
this.warningThreshold = warningThreshold;
return this;
}

public Builder setOnLeakPeriod(boolean onLeakPeriod) {
this.onLeakPeriod = onLeakPeriod;
return this;
}

public Builder setValue(String value) {
this.value = value;
return this;
}

public Builder setStatus(QualityGate.EvaluationStatus status) {
this.status = status;
return this;
}

public ConditionImpl build() {
return new ConditionImpl(this);
}
}

@Override
public QualityGate.EvaluationStatus getStatus() {
return status;
}

@Override
public String getMetricKey() {
return metricKey;
}

@Override
public QualityGate.Operator getOperator() {
return operator;
}

@Override
public String getErrorThreshold() {
return errorThreshold;
}

@Override
public String getWarningThreshold() {
return warningThreshold;
}

@Override
public boolean isOnLeakPeriod() {
return onLeakPeriod;
}

@Override
public String getValue() {
checkState(status != NO_VALUE, "There is no value when status is " + NO_VALUE);

return value;
}

@Override
public String toString() {
return "ConditionImpl{" +
"status=" + status +
", metricKey='" + metricKey + '\'' +
", operator=" + operator +
", errorThreshold='" + errorThreshold + '\'' +
", warningThreshold='" + warningThreshold + '\'' +
", onLeakPeriod=" + onLeakPeriod +
", value='" + value + '\'' +
'}';
}
}

+ 94
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ConditionToCondition.java View File

@@ -0,0 +1,94 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.google.common.base.Function;
import java.util.Map;
import javax.annotation.Nonnull;
import org.sonar.api.ce.posttask.QualityGate;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionStatus;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;

/**
* Converts a {@link Condition} from the Compute Engine internal API to a {@link org.sonar.api.ce.posttask.QualityGate.Condition}
* of the public API.
*/
class ConditionToCondition implements Function<Condition, QualityGate.Condition> {
private final ConditionImpl.Builder builder = ConditionImpl.newBuilder();
private final Map<Condition, ConditionStatus> statusPerConditions;

public ConditionToCondition(Map<Condition, ConditionStatus> statusPerConditions) {
this.statusPerConditions = statusPerConditions;
}

@Override
@Nonnull
public QualityGate.Condition apply(@Nonnull Condition input) {
String metricKey = input.getMetric().getKey();
ConditionStatus conditionStatus = statusPerConditions.get(input);
checkState(conditionStatus != null, "Missing ConditionStatus for condition on metric key %s", metricKey);
return builder
.setStatus(convert(conditionStatus.getStatus()))
.setMetricKey(metricKey)
.setOperator(convert(input.getOperator()))
.setErrorThreshold(input.getErrorThreshold())
.setWarningThreshold(input.getWarningThreshold())
.setOnLeakPeriod(input.getPeriod() != null)
.setValue(conditionStatus.getValue())
.build();
}

private static QualityGate.EvaluationStatus convert(ConditionStatus.EvaluationStatus status) {
switch (status) {
case NO_VALUE:
return QualityGate.EvaluationStatus.NO_VALUE;
case OK:
return QualityGate.EvaluationStatus.OK;
case WARN:
return QualityGate.EvaluationStatus.WARN;
case ERROR:
return QualityGate.EvaluationStatus.ERROR;
default:
throw new IllegalArgumentException(format(
"Unsupported value '%s' of ConditionStatus.EvaluationStatus can not be converted to QualityGate.EvaluationStatus",
status));
}
}

private static QualityGate.Operator convert(Condition.Operator operator) {
switch (operator) {
case EQUALS:
return QualityGate.Operator.EQUALS;
case NOT_EQUALS:
return QualityGate.Operator.NOT_EQUALS;
case GREATER_THAN:
return QualityGate.Operator.GREATER_THAN;
case LESS_THAN:
return QualityGate.Operator.LESS_THAN;
default:
throw new IllegalArgumentException(format(
"Unsupported value '%s' of Condition.Operation can not be converted to QualityGate.Operator",
operator));
}
}
}

+ 192
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/PostProjectAnalysisTasksExecutor.java View File

@@ -0,0 +1,192 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.google.common.base.Optional;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.ce.posttask.CeTask;
import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
import org.sonar.api.ce.posttask.Project;
import org.sonar.api.ce.posttask.QualityGate;
import org.sonar.server.computation.analysis.AnalysisMetadataHolder;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionStatus;
import org.sonar.server.computation.qualitygate.QualityGateHolder;
import org.sonar.server.computation.qualitygate.QualityGateStatus;
import org.sonar.server.computation.qualitygate.QualityGateStatusHolder;
import org.sonar.server.computation.step.ComputationStepExecutor;

import static com.google.common.collect.FluentIterable.from;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.ce.posttask.CeTask.Status.FAILED;
import static org.sonar.api.ce.posttask.CeTask.Status.SUCCESS;

/**
* Responsible for calling {@link PostProjectAnalysisTask} implementations (if any).
*/
public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor.Listener {
private static final PostProjectAnalysisTask[] NO_POST_PROJECT_ANALYSIS_TASKS = new PostProjectAnalysisTask[0];

private final org.sonar.ce.queue.CeTask ceTask;
private final AnalysisMetadataHolder analysisMetadataHolder;
private final QualityGateHolder qualityGateHolder;
private final QualityGateStatusHolder qualityGateStatusHolder;
private final PostProjectAnalysisTask[] postProjectAnalysisTasks;

/**
* Constructor used by Pico when there is no {@link PostProjectAnalysisTask} in the container.
*/
public PostProjectAnalysisTasksExecutor(org.sonar.ce.queue.CeTask ceTask,
AnalysisMetadataHolder analysisMetadataHolder,
QualityGateHolder qualityGateHolder, QualityGateStatusHolder qualityGateStatusHolder) {
this(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, null);
}

public PostProjectAnalysisTasksExecutor(org.sonar.ce.queue.CeTask ceTask,
AnalysisMetadataHolder analysisMetadataHolder,
QualityGateHolder qualityGateHolder, QualityGateStatusHolder qualityGateStatusHolder,
@Nullable PostProjectAnalysisTask[] postProjectAnalysisTasks) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.qualityGateHolder = qualityGateHolder;
this.qualityGateStatusHolder = qualityGateStatusHolder;
this.ceTask = ceTask;
this.postProjectAnalysisTasks = postProjectAnalysisTasks == null ? NO_POST_PROJECT_ANALYSIS_TASKS : postProjectAnalysisTasks;
}

@Override
public void finished(boolean allStepsExecuted) {
if (postProjectAnalysisTasks.length == 0) {
return;
}

ProjectAnalysis projectAnalysis = createProjectAnalysis(allStepsExecuted ? SUCCESS : FAILED);
for (PostProjectAnalysisTask postProjectAnalysisTask : postProjectAnalysisTasks) {
postProjectAnalysisTask.finished(projectAnalysis);
}
}

private ProjectAnalysis createProjectAnalysis(CeTask.Status status) {
return new ProjectAnalysis(
new CeTaskImpl(this.ceTask.getUuid(), status),
createProject(this.ceTask),
getAnalysisDate(),
status == SUCCESS ? createQualityGate(this.qualityGateHolder) : null);
}

private static Project createProject(org.sonar.ce.queue.CeTask ceTask) {
return new ProjectImpl(
ceTask.getComponentUuid(),
ceTask.getComponentKey(),
ceTask.getComponentName());
}

private Date getAnalysisDate() {
return new Date(this.analysisMetadataHolder.getAnalysisDate());
}

@CheckForNull
private QualityGateImpl createQualityGate(QualityGateHolder qualityGateHolder) {
Optional<org.sonar.server.computation.qualitygate.QualityGate> qualityGateOptional = qualityGateHolder.getQualityGate();
if (qualityGateOptional.isPresent()) {
org.sonar.server.computation.qualitygate.QualityGate qualityGate = qualityGateOptional.get();

return new QualityGateImpl(
String.valueOf(qualityGate.getId()),
qualityGate.getName(),
convert(qualityGateStatusHolder.getStatus()),
convert(qualityGate.getConditions(), qualityGateStatusHolder.getStatusPerConditions()));
}
return null;
}

private static QualityGate.Status convert(QualityGateStatus status) {
switch (status) {
case OK:
return QualityGate.Status.OK;
case WARN:
return QualityGate.Status.WARN;
case ERROR:
return QualityGate.Status.ERROR;
default:
throw new IllegalArgumentException(format(
"Unsupported value '%s' of QualityGateStatus can not be converted to QualityGate.Status",
status));
}
}

private static Collection<QualityGate.Condition> convert(Set<Condition> conditions, Map<Condition, ConditionStatus> statusPerConditions) {
return from(conditions)
.transform(new ConditionToCondition(statusPerConditions))
.toList();
}

private static class ProjectAnalysis implements PostProjectAnalysisTask.ProjectAnalysis {
private final CeTask ceTask;
private final Project project;
private final Date date;
@CheckForNull
private final QualityGate qualityGate;

private ProjectAnalysis(CeTask ceTask, Project project, Date date, @Nullable QualityGate qualityGate) {
this.ceTask = requireNonNull(ceTask, "ceTask can not be null");
this.project = requireNonNull(project, "project can not be null");
this.date = requireNonNull(date, "date can not be null");
this.qualityGate = qualityGate;
}

@Override
public CeTask getCeTask() {
return ceTask;
}

@Override
public Project getProject() {
return project;
}

@Override
@CheckForNull
public QualityGate getQualityGate() {
return qualityGate;
}

@Override
public Date getDate() {
return date;
}

@Override
public String toString() {
return "ProjectAnalysis{" +
"ceTask=" + ceTask +
", project=" + project +
", date=" + date +
", qualityGate=" + qualityGate +
'}';
}
}

}

+ 62
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/ProjectImpl.java View File

@@ -0,0 +1,62 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.posttask.Project;

import static java.util.Objects.requireNonNull;

@Immutable
class ProjectImpl implements Project {
private final String uuid;
private final String key;
private final String name;

ProjectImpl(String uuid, String key, String name) {
this.uuid = requireNonNull(uuid, "uuid can not be null");
this.key = requireNonNull(key, "key can not be null");
this.name = requireNonNull(name, "name can not be null");
}

@Override
public String getUuid() {
return uuid;
}

@Override
public String getKey() {
return key;
}

@Override
public String getName() {
return name;
}

@Override
public String toString() {
return "ProjectImpl{" +
"uuid='" + uuid + '\'' +
", key='" + key + '\'' +
", name='" + name + '\'' +
'}';
}
}

+ 72
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/QualityGateImpl.java View File

@@ -0,0 +1,72 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.google.common.collect.ImmutableList;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.posttask.QualityGate;

import static java.util.Objects.requireNonNull;

@Immutable
class QualityGateImpl implements QualityGate {
private final String id;
private final String name;
private final Status status;
private final Collection<Condition> conditions;

public QualityGateImpl(String id, String name, Status status, Collection<Condition> conditions) {
this.id = requireNonNull(id, "id can not be null");
this.name = requireNonNull(name, "name can not be null");
this.status = requireNonNull(status, "status can not be null");
this.conditions = ImmutableList.copyOf(requireNonNull(conditions, "conditions can not be null"));
}

@Override
public String getId() {
return id;
}

@Override
public String getName() {
return name;
}

@Override
public Status getStatus() {
return status;
}

@Override
public Collection<Condition> getConditions() {
return conditions;
}

@Override
public String toString() {
return "QualityGateImpl{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", status=" + status +
", conditions=" + conditions +
'}';
}
}

+ 23
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/posttask/package-info.java View File

@@ -0,0 +1,23 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
package org.sonar.server.computation.posttask;

import javax.annotation.ParametersAreNonnullByDefault;

+ 73
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/ConditionStatus.java View File

@@ -0,0 +1,73 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

@Immutable
public class ConditionStatus {
public static final ConditionStatus NO_VALUE_STATUS = new ConditionStatus(EvaluationStatus.NO_VALUE, null);

private final EvaluationStatus status;
@CheckForNull
private final String value;

private ConditionStatus(EvaluationStatus status, @Nullable String value) {
this.status = requireNonNull(status, "status can not be null");
this.value = value;
}

public static ConditionStatus create(EvaluationStatus status, String value) {
requireNonNull(status, "status can not be null");
checkArgument(status != EvaluationStatus.NO_VALUE, "EvaluationStatus 'NO_VALUE' can not be used with this method, use constant ConditionStatus.NO_VALUE_STATUS instead.");
requireNonNull(value, "value can not be null");
return new ConditionStatus(status, value);
}

public EvaluationStatus getStatus() {
return status;
}

/**
* @return {@code null} when {@link #getStatus()} is {@link EvaluationStatus#NO_VALUE}, otherwise non {@code null}
*/
@CheckForNull
public String getValue() {
return value;
}

@Override
public String toString() {
return "ConditionStatus{" +
"status=" + status +
", value='" + value + '\'' +
'}';
}

public enum EvaluationStatus {
NO_VALUE, OK, WARN, ERROR
}

}

+ 33
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/MutableQualityGateStatusHolder.java View File

@@ -0,0 +1,33 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import java.util.Map;

public interface MutableQualityGateStatusHolder extends QualityGateStatusHolder {
/**
* Sets the status of the quality gate and its conditions in the holder.
*
* @throws NullPointerException if either {@code globalStatus} or {@code statusPerCondition} is {@code null}
* @throws IllegalArgumentException if {@code statusPerCondition} is empty
* @throws IllegalStateException if the status has already been set in the holder
*/
void setStatus(QualityGateStatus globalStatus, Map<Condition, ConditionStatus> statusPerCondition);
}

+ 7
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGate.java View File

@@ -28,14 +28,20 @@ import static com.google.common.collect.FluentIterable.from;

@Immutable
public class QualityGate {
private final long id;
private final String name;
private final Set<Condition> conditions;

public QualityGate(String name, Iterable<Condition> conditions) {
public QualityGate(long id, String name, Iterable<Condition> conditions) {
this.id = id;
this.name = Objects.requireNonNull(name);
this.conditions = from(conditions).filter(notNull()).toSet();
}

public long getId() {
return id;
}

public String getName() {
return name;
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateServiceImpl.java View File

@@ -61,7 +61,7 @@ public class QualityGateServiceImpl implements QualityGateService {
private QualityGate toQualityGate(QualityGateDto qualityGateDto) {
Iterable<Condition> conditions = from(conditionDao.selectForQualityGate(qualityGateDto.getId())).transform(conditionDtoToBean);

return new QualityGate(qualityGateDto.getName(), conditions);
return new QualityGate(qualityGateDto.getId(), qualityGateDto.getName(), conditions);
}

}

+ 24
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatus.java View File

@@ -0,0 +1,24 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

public enum QualityGateStatus {
OK, WARN, ERROR
}

+ 41
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolder.java View File

@@ -0,0 +1,41 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import java.util.Map;

public interface QualityGateStatusHolder {

/**
* The global status of the quality gate (if there is a quality gate on the project).
*
* @throws IllegalStateException if status has not yet been set in the holder
* @see QualityGateHolder#getQualityGate()
*/
QualityGateStatus getStatus();

/**
* The status per condition of the quality gate (if there is a quality gate on the project).
*
* @throws IllegalStateException if status has not yet been set in the holder
* @see QualityGateHolder#getQualityGate()
*/
Map<Condition, ConditionStatus> getStatusPerConditions();
}

+ 62
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolderImpl.java View File

@@ -0,0 +1,62 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.CheckForNull;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

public class QualityGateStatusHolderImpl implements MutableQualityGateStatusHolder {
@CheckForNull
private QualityGateStatus status;
@CheckForNull
private Map<Condition, ConditionStatus> statusPerCondition;

@Override
public QualityGateStatus getStatus() {
checkInitialized();

return status;
}

@Override
public Map<Condition, ConditionStatus> getStatusPerConditions() {
checkInitialized();

return statusPerCondition;
}

private void checkInitialized() {
checkState(status != null, "Quality gate status has not been set yet");
}

@Override
public void setStatus(QualityGateStatus globalStatus, Map<Condition, ConditionStatus> statusPerCondition) {
checkState(status == null, "Quality gate status has already been set in the holder");
requireNonNull(globalStatus, "global status can not be null");
requireNonNull(statusPerCondition, "status per condition can not be null");

this.status = globalStatus;
this.statusPerCondition = ImmutableMap.copyOf(statusPerCondition);
}
}

+ 78
- 3
server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java View File

@@ -19,10 +19,14 @@
*/
package org.sonar.server.computation.step;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.measures.CoreMetrics;
@@ -40,12 +44,18 @@ import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.metric.MetricRepository;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionEvaluator;
import org.sonar.server.computation.qualitygate.ConditionStatus;
import org.sonar.server.computation.qualitygate.EvaluationResult;
import org.sonar.server.computation.qualitygate.EvaluationResultTextConverter;
import org.sonar.server.computation.qualitygate.MutableQualityGateStatusHolder;
import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateHolder;

import static com.google.common.collect.FluentIterable.from;
import static java.lang.String.format;
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
import static org.sonar.server.computation.qualitygate.ConditionStatus.NO_VALUE_STATUS;
import static org.sonar.server.computation.qualitygate.ConditionStatus.create;

/**
* This step:
@@ -62,15 +72,18 @@ public class QualityGateMeasuresStep implements ComputationStep {

private final TreeRootHolder treeRootHolder;
private final QualityGateHolder qualityGateHolder;
private final MutableQualityGateStatusHolder qualityGateStatusHolder;
private final MeasureRepository measureRepository;
private final MetricRepository metricRepository;
private final EvaluationResultTextConverter evaluationResultTextConverter;

public QualityGateMeasuresStep(TreeRootHolder treeRootHolder, QualityGateHolder qualityGateHolder,
public QualityGateMeasuresStep(TreeRootHolder treeRootHolder,
QualityGateHolder qualityGateHolder, MutableQualityGateStatusHolder qualityGateStatusHolder,
MeasureRepository measureRepository, MetricRepository metricRepository,
EvaluationResultTextConverter evaluationResultTextConverter) {
this.treeRootHolder = treeRootHolder;
this.qualityGateHolder = qualityGateHolder;
this.qualityGateStatusHolder = qualityGateStatusHolder;
this.evaluationResultTextConverter = evaluationResultTextConverter;
this.measureRepository = measureRepository;
this.metricRepository = metricRepository;
@@ -88,16 +101,68 @@ public class QualityGateMeasuresStep implements ComputationStep {
}

private void executeForProject(Component project) {
QualityGateDetailsDataBuilder builder = new QualityGateDetailsDataBuilder();

Optional<QualityGate> qualityGate = qualityGateHolder.getQualityGate();
if (qualityGate.isPresent()) {
QualityGateDetailsDataBuilder builder = new QualityGateDetailsDataBuilder();
updateMeasures(project, qualityGate.get().getConditions(), builder);

addProjectMeasure(project, builder);

updateQualityGateStatusHolder(qualityGate.get(), builder);
}
}

private void updateQualityGateStatusHolder(QualityGate qualityGate, QualityGateDetailsDataBuilder builder) {
qualityGateStatusHolder.setStatus(convert(builder.getGlobalLevel()), createStatusPerCondition(qualityGate.getConditions(), builder.getEvaluatedConditions()));
}

private static ConditionStatus.EvaluationStatus toEvaluationStatus(Measure.Level globalLevel) {
switch (globalLevel) {
case OK:
return ConditionStatus.EvaluationStatus.OK;
case WARN:
return ConditionStatus.EvaluationStatus.WARN;
case ERROR:
return ConditionStatus.EvaluationStatus.ERROR;
default:
throw new IllegalArgumentException(format(
"Unsupported value '%s' of Measure.Level can not be converted to EvaluationStatus",
globalLevel));
}
}

private static org.sonar.server.computation.qualitygate.QualityGateStatus convert(Measure.Level globalLevel) {
switch (globalLevel) {
case OK:
return org.sonar.server.computation.qualitygate.QualityGateStatus.OK;
case WARN:
return org.sonar.server.computation.qualitygate.QualityGateStatus.WARN;
case ERROR:
return org.sonar.server.computation.qualitygate.QualityGateStatus.ERROR;
default:
throw new IllegalArgumentException(format(
"Unsupported value '%s' of Measure.Level can not be converted to QualityGateStatus",
globalLevel));
}
}

private static Map<Condition, ConditionStatus> createStatusPerCondition(Iterable<Condition> conditions, Iterable<EvaluatedCondition> evaluatedConditions) {
Map<Condition, EvaluatedCondition> evaluatedConditionPerCondition = from(evaluatedConditions)
.uniqueIndex(EvaluatedConditionToCondition.INSTANCE);

ImmutableMap.Builder<Condition, ConditionStatus> builder = ImmutableMap.builder();
for (Condition condition : conditions) {
EvaluatedCondition evaluatedCondition = evaluatedConditionPerCondition.get(condition);

if (evaluatedCondition == null) {
builder.put(condition, NO_VALUE_STATUS);
} else {
builder.put(condition, create(toEvaluationStatus(evaluatedCondition.getLevel()), evaluatedCondition.getActualValue()));
}
}
return builder.build();
}

private void updateMeasures(Component project, Set<Condition> conditions, QualityGateDetailsDataBuilder builder) {
for (Condition condition : conditions) {
Optional<Measure> measure = measureRepository.getRawMeasure(project, condition.getMetric());
@@ -170,4 +235,14 @@ public class QualityGateMeasuresStep implements ComputationStep {
return evaluatedConditions;
}
}

private enum EvaluatedConditionToCondition implements Function<EvaluatedCondition, Condition> {
INSTANCE;

@Override
@Nonnull
public Condition apply(@Nonnull EvaluatedCondition input) {
return input.getCondition();
}
}
}

+ 63
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/CeTaskImplTest.java View File

@@ -0,0 +1,63 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.ce.posttask.CeTask;

import static org.assertj.core.api.Assertions.assertThat;

public class CeTaskImplTest {
private static final String SOME_ID = "some id";

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void constructor_throws_NPE_if_id_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("id can not be null");

new CeTaskImpl(null, CeTask.Status.SUCCESS);
}

@Test
public void constructor_throws_NPE_if_status_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status can not be null");

new CeTaskImpl(SOME_ID, null);
}

@Test
public void verify_getters() {
CeTaskImpl underTest = new CeTaskImpl(SOME_ID, CeTask.Status.FAILED);

assertThat(underTest.getId()).isEqualTo(SOME_ID);
assertThat(underTest.getStatus()).isEqualTo(CeTask.Status.FAILED);
}

@Test
public void verify_toString() {
assertThat(new CeTaskImpl(SOME_ID, CeTask.Status.SUCCESS).toString()).isEqualTo("CeTaskImpl{id='some id', status=SUCCESS}");
}
}

+ 168
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ConditionImplTest.java View File

@@ -0,0 +1,168 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.ce.posttask.QualityGate;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(DataProviderRunner.class)
public class ConditionImplTest {
private static final String METRIC_KEY = "metricKey";
private static final String ERROR_THRESHOLD = "error threshold";
private static final String WARN_THRESHOLD = "warn threshold";
private static final String VALUE = "value";

@Rule
public ExpectedException expectedException = ExpectedException.none();

private ConditionImpl.Builder builder = ConditionImpl.newBuilder()
.setStatus(QualityGate.EvaluationStatus.OK)
.setMetricKey(METRIC_KEY)
.setOperator(QualityGate.Operator.GREATER_THAN)
.setErrorThreshold(ERROR_THRESHOLD)
.setWarningThreshold(WARN_THRESHOLD)
.setOnLeakPeriod(true)
.setValue(VALUE);

@Test
public void build_throws_NPE_if_status_is_null() {
builder.setStatus(null);

expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status can not be null");

builder.build();
}

@Test
public void build_throws_NPE_if_metricKey_is_null() {
builder.setMetricKey(null);

expectedException.expect(NullPointerException.class);
expectedException.expectMessage("metricKey can not be null");

builder.build();
}

@Test
public void build_throws_NPE_if_operator_is_null() {
builder.setOperator(null);

expectedException.expect(NullPointerException.class);
expectedException.expectMessage("operator can not be null");

builder.build();
}

@Test
public void build_throws_IAE_if_both_thresholds_are_null() {
builder.setWarningThreshold(null)
.setErrorThreshold(null);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At least one of errorThreshold and warningThreshold must be non null");

builder.build();
}

@Test
public void getValue_throws_ISE_when_condition_type_is_NO_VALUE() {
builder.setStatus(QualityGate.EvaluationStatus.NO_VALUE).setValue(null);
ConditionImpl condition = builder.build();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("There is no value when status is NO_VALUE");

condition.getValue();
}

@DataProvider
public static Object[][] allStatusesButNO_VALUE() {
Object[][] res = new Object[QualityGate.EvaluationStatus.values().length - 1][1];
int i = 0;
for (QualityGate.EvaluationStatus status : QualityGate.EvaluationStatus.values()) {
if (status != QualityGate.EvaluationStatus.NO_VALUE) {
res[i][0] = status;
i++;
}
}
return res;
}

@Test
@UseDataProvider("allStatusesButNO_VALUE")
public void build_throws_IAE_if_value_is_null_but_status_is_not_NO_VALUE(QualityGate.EvaluationStatus status) {
builder.setStatus(status)
.setValue(null);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("value can not be null when status is not NO_VALUE");

builder.build();
}

@Test
public void build_throws_IAE_if_value_is_not_null_but_status_is_NO_VALUE() {
builder.setStatus(QualityGate.EvaluationStatus.NO_VALUE);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("value must be null when status is NO_VALUE");

builder.build();
}

@Test
public void toString_ConditionImpl_of_type_different_from_NO_VALUE() {
assertThat(builder.build().toString())
.isEqualTo(
"ConditionImpl{status=OK, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', onLeakPeriod=true, value='value'}");
}

@Test
public void toString_ConditionImpl_of_type_NO_VALUE() {
builder.setStatus(QualityGate.EvaluationStatus.NO_VALUE)
.setValue(null);

assertThat(builder.build().toString())
.isEqualTo(
"ConditionImpl{status=NO_VALUE, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', onLeakPeriod=true, value='null'}");
}

@Test
public void verify_getters() {
ConditionImpl underTest = builder.build();

assertThat(underTest.getStatus()).isEqualTo(QualityGate.EvaluationStatus.OK);
assertThat(underTest.getMetricKey()).isEqualTo(METRIC_KEY);
assertThat(underTest.getOperator()).isEqualTo(QualityGate.Operator.GREATER_THAN);
assertThat(underTest.getErrorThreshold()).isEqualTo(ERROR_THRESHOLD);
assertThat(underTest.getWarningThreshold()).isEqualTo(WARN_THRESHOLD);
assertThat(underTest.isOnLeakPeriod()).isEqualTo(true);
assertThat(underTest.getValue()).isEqualTo(VALUE);
}
}

+ 163
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ConditionToConditionTest.java View File

@@ -0,0 +1,163 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.Collections;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.ce.posttask.QualityGate;
import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionStatus;

import static com.google.common.collect.ImmutableMap.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(DataProviderRunner.class)
public class ConditionToConditionTest {
private static final String METRIC_KEY = "metricKey";
private static final String ERROR_THRESHOLD = "error threshold";
private static final String WARN_THRESHOLD = "warn threshold";
private static final Map<Condition, ConditionStatus> NO_STATUS_PER_CONDITIONS = Collections.emptyMap();
private static final String SOME_VALUE = "some value";
private static final ConditionStatus SOME_CONDITION_STATUS = ConditionStatus.create(ConditionStatus.EvaluationStatus.OK, SOME_VALUE);
private static final Condition SOME_CONDITION = new Condition(newMetric(METRIC_KEY), Condition.Operator.EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, 1);

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void apply_throws_NPE_if_Condition_argument_is_null() {
ConditionToCondition underTest = new ConditionToCondition(NO_STATUS_PER_CONDITIONS);

expectedException.expect(NullPointerException.class);

underTest.apply(null);
}

@Test
public void apply_throws_ISE_if_there_is_no_ConditionStatus_for_Condition_argument() {
ConditionToCondition underTest = new ConditionToCondition(NO_STATUS_PER_CONDITIONS);

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Missing ConditionStatus for condition on metric key " + METRIC_KEY);

underTest.apply(SOME_CONDITION);
}

@Test
@UseDataProvider("allEvaluationStatuses")
public void apply_converts_all_values_of_status(ConditionStatus.EvaluationStatus status) {
ConditionToCondition underTest = new ConditionToCondition(of(
SOME_CONDITION,
status == ConditionStatus.EvaluationStatus.NO_VALUE ? ConditionStatus.NO_VALUE_STATUS : ConditionStatus.create(status, SOME_VALUE)));

assertThat(underTest.apply(SOME_CONDITION).getStatus().name()).isEqualTo(status.name());
}

@Test
public void apply_converts_key_from_metric() {
ConditionToCondition underTest = new ConditionToCondition(of(SOME_CONDITION, SOME_CONDITION_STATUS));

assertThat(underTest.apply(SOME_CONDITION).getMetricKey()).isEqualTo(METRIC_KEY);
}

@Test
public void apply_copies_thresholds() {
ConditionToCondition underTest = new ConditionToCondition(of(SOME_CONDITION, SOME_CONDITION_STATUS));

assertThat(underTest.apply(SOME_CONDITION).getErrorThreshold()).isEqualTo(ERROR_THRESHOLD);
assertThat(underTest.apply(SOME_CONDITION).getWarningThreshold()).isEqualTo(WARN_THRESHOLD);
}

@Test
@UseDataProvider("allOperatorValues")
public void apply_converts_all_values_of_operator(Condition.Operator operator) {
Condition condition = new Condition(newMetric(METRIC_KEY), operator.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, 1);
ConditionToCondition underTest = new ConditionToCondition(of(condition, SOME_CONDITION_STATUS));

assertThat(underTest.apply(condition).getOperator().name()).isEqualTo(operator.name());
}

@Test
public void apply_sets_onLeakPeriod_flag_when_Condition_has_non_null_Period() {
Condition noPeriodCondition = new Condition(newMetric(METRIC_KEY), Condition.Operator.NOT_EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, null);
ConditionToCondition underTest = new ConditionToCondition(of(
SOME_CONDITION, SOME_CONDITION_STATUS,
noPeriodCondition, SOME_CONDITION_STATUS));

assertThat(underTest.apply(SOME_CONDITION).isOnLeakPeriod()).isTrue();
assertThat(underTest.apply(noPeriodCondition).isOnLeakPeriod()).isFalse();
}

@Test
public void apply_copies_value() {
Condition otherCondition = new Condition(newMetric(METRIC_KEY), Condition.Operator.NOT_EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, null);
ConditionToCondition underTest = new ConditionToCondition(of(
SOME_CONDITION, SOME_CONDITION_STATUS,
otherCondition, ConditionStatus.NO_VALUE_STATUS
));

assertThat(underTest.apply(SOME_CONDITION).getValue()).isEqualTo(SOME_VALUE);

QualityGate.Condition res = underTest.apply(otherCondition);

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("There is no value when status is NO_VALUE");

res.getValue();
}

@DataProvider
public static Object[][] allEvaluationStatuses() {
Object[][] res = new Object[ConditionStatus.EvaluationStatus.values().length][1];
int i = 0;
for (ConditionStatus.EvaluationStatus status : ConditionStatus.EvaluationStatus.values()) {
res[i][0] = status;
i++;
}
return res;
}

@DataProvider
public static Object[][] allOperatorValues() {
Object[][] res = new Object[Condition.Operator.values().length][1];
int i = 0;
for (Condition.Operator operator : Condition.Operator.values()) {
res[i][0] = operator;
i++;
}
return res;
}

private static Metric newMetric(String metricKey) {
Metric metric = mock(Metric.class);
when(metric.getKey()).thenReturn(metricKey);
return metric;
}
}

+ 197
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/PostProjectAnalysisTasksExecutorTest.java View File

@@ -0,0 +1,197 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.google.common.collect.ImmutableMap;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
import org.sonar.api.ce.posttask.Project;
import org.sonar.ce.queue.CeTask;
import org.sonar.server.computation.analysis.AnalysisMetadataHolderRule;
import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionStatus;
import org.sonar.server.computation.qualitygate.MutableQualityGateHolderRule;
import org.sonar.server.computation.qualitygate.MutableQualityGateStatusHolderRule;
import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateStatus;

import static com.google.common.collect.ImmutableList.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(DataProviderRunner.class)
public class PostProjectAnalysisTasksExecutorTest {
private static final long QUALITY_GATE_ID = 98451;
private static final String QUALITY_GATE_NAME = "qualityGate name";
private static final Condition CONDITION_1 = createCondition("metric key 1");
private static final Condition CONDITION_2 = createCondition("metric key 2");

@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule()
.setAnalysisDate(8465132498L);
@Rule
public MutableQualityGateHolderRule qualityGateHolder = new MutableQualityGateHolderRule();
@Rule
public MutableQualityGateStatusHolderRule qualityGateStatusHolder = new MutableQualityGateStatusHolderRule();

private ArgumentCaptor<PostProjectAnalysisTask.ProjectAnalysis> projectAnalysisArgumentCaptor = ArgumentCaptor.forClass(PostProjectAnalysisTask.ProjectAnalysis.class);
private CeTask ceTask = new CeTask.Builder()
.setType("type")
.setUuid("uuid")
.setComponentKey("component key")
.setComponentName("component name")
.setComponentUuid("component uuid")
.build();
private PostProjectAnalysisTask postProjectAnalysisTask = mock(PostProjectAnalysisTask.class);
private PostProjectAnalysisTasksExecutor underTest = new PostProjectAnalysisTasksExecutor(
ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder,
new PostProjectAnalysisTask[] {postProjectAnalysisTask});

@Before
public void setUp() throws Exception {
qualityGateHolder.setQualityGate(new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, of(CONDITION_1, CONDITION_2)));
qualityGateStatusHolder.setStatus(QualityGateStatus.OK, ImmutableMap.of(
CONDITION_1, ConditionStatus.create(ConditionStatus.EvaluationStatus.OK, "value"),
CONDITION_2, ConditionStatus.NO_VALUE_STATUS));
}

@Test
@UseDataProvider("booleanValues")
public void does_not_fail_when_there_is_no_PostProjectAnalysisTasksExecutor(boolean allStepsExecuted) {
new PostProjectAnalysisTasksExecutor(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder)
.finished(allStepsExecuted);
}

@Test
@UseDataProvider("booleanValues")
public void finished_calls_all_PostProjectAnalysisTask_in_order_of_the_array_and_passes_the_same_object_to_all(boolean allStepsExecuted) {
PostProjectAnalysisTask postProjectAnalysisTask1 = mock(PostProjectAnalysisTask.class);
PostProjectAnalysisTask postProjectAnalysisTask2 = mock(PostProjectAnalysisTask.class);
InOrder inOrder = inOrder(postProjectAnalysisTask1, postProjectAnalysisTask2);

new PostProjectAnalysisTasksExecutor(
ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder,
new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2})
.finished(allStepsExecuted);

inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture());
inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture());
inOrder.verifyNoMoreInteractions();

List<PostProjectAnalysisTask.ProjectAnalysis> allValues = projectAnalysisArgumentCaptor.getAllValues();
assertThat(allValues).hasSize(2);
assertThat(allValues.get(0)).isSameAs(allValues.get(1));
}

@Test
@UseDataProvider("booleanValues")
public void CeTask_status_depends_on_finished_method_argument_is_true_or_false(boolean allStepsExecuted) {
underTest.finished(allStepsExecuted);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

assertThat(projectAnalysisArgumentCaptor.getValue().getCeTask().getStatus())
.isEqualTo(
allStepsExecuted ? org.sonar.api.ce.posttask.CeTask.Status.SUCCESS : org.sonar.api.ce.posttask.CeTask.Status.FAILED);
}

@Test
public void ceTask_uuid_is_UUID_of_CeTask() {
underTest.finished(true);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

assertThat(projectAnalysisArgumentCaptor.getValue().getCeTask().getId())
.isEqualTo(ceTask.getUuid());
}

@Test
public void project_uuid_key_and_name_come_from_CeTask() {
underTest.finished(true);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

Project project = projectAnalysisArgumentCaptor.getValue().getProject();
assertThat(project.getUuid()).isEqualTo(ceTask.getComponentUuid());
assertThat(project.getKey()).isEqualTo(ceTask.getComponentKey());
assertThat(project.getName()).isEqualTo(ceTask.getComponentName());
}

@Test
public void analysisDate_comes_from_AnalysisMetadataHolder() {
underTest.finished(true);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

assertThat(projectAnalysisArgumentCaptor.getValue().getDate())
.isEqualTo(new Date(analysisMetadataHolder.getAnalysisDate()));
}

@Test
public void qualityGate_is_null_when_finished_method_argument_is_false() {
underTest.finished(false);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

assertThat(projectAnalysisArgumentCaptor.getValue().getQualityGate()).isNull();
}

@Test
public void qualityGate_is_populated_when_finished_method_argument_is_true() {
underTest.finished(true);

verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());

org.sonar.api.ce.posttask.QualityGate qualityGate = projectAnalysisArgumentCaptor.getValue().getQualityGate();
assertThat(qualityGate.getStatus()).isEqualTo(org.sonar.api.ce.posttask.QualityGate.Status.OK);
assertThat(qualityGate.getId()).isEqualTo(String.valueOf(QUALITY_GATE_ID));
assertThat(qualityGate.getName()).isEqualTo(QUALITY_GATE_NAME);
assertThat(qualityGate.getConditions()).hasSize(2);
}

@DataProvider
public static Object[][] booleanValues() {
return new Object[][] {
{true},
{false}
};
}

private static Condition createCondition(String metricKey) {
Metric metric = mock(Metric.class);
when(metric.getKey()).thenReturn(metricKey);
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), "error threshold", "warn threshold", null);
}

}

+ 75
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/ProjectImplTest.java View File

@@ -0,0 +1,75 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.assertj.core.api.Assertions.assertThat;

public class ProjectImplTest {
private static final String SOME_UUID = "some uuid";
private static final String SOME_KEY = "some key";
private static final String SOME_NAME = "some name";

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void constructor_throws_NPE_if_uuid_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("uuid can not be null");

new ProjectImpl(null, SOME_KEY, SOME_NAME);
}

@Test
public void constructor_throws_NPE_if_key_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("key can not be null");

new ProjectImpl(SOME_UUID, null, SOME_NAME);
}

@Test
public void constructor_throws_NPE_if_name_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("name can not be null");

new ProjectImpl(SOME_UUID, SOME_KEY, null);
}

@Test
public void verify_getters() {
ProjectImpl underTest = new ProjectImpl(SOME_UUID, SOME_KEY, SOME_NAME);

assertThat(underTest.getUuid()).isEqualTo(SOME_UUID);
assertThat(underTest.getKey()).isEqualTo(SOME_KEY);
assertThat(underTest.getName()).isEqualTo(SOME_NAME);
}

@Test
public void verify_toString() {
assertThat(new ProjectImpl(SOME_UUID, SOME_KEY, SOME_NAME).toString())
.isEqualTo("ProjectImpl{uuid='some uuid', key='some key', name='some name'}");

}
}

+ 96
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/posttask/QualityGateImplTest.java View File

@@ -0,0 +1,96 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.posttask;

import com.google.common.collect.ImmutableList;
import java.util.Collections;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.ce.posttask.QualityGate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class QualityGateImplTest {
private static final String SOME_ID = "some id";
private static final String SOME_NAME = "some name";
private static final QualityGate.Status SOME_STATUS = QualityGate.Status.OK;

@Rule
public ExpectedException expectedException = ExpectedException.none();

private QualityGate.Condition condition = mock(QualityGate.Condition.class);
private QualityGateImpl underTest = new QualityGateImpl(SOME_ID, SOME_NAME, SOME_STATUS, ImmutableList.of(condition));

@Test
public void constructor_throws_NPE_if_id_argument_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("id can not be null");

new QualityGateImpl(null, SOME_NAME, SOME_STATUS, Collections.<QualityGate.Condition>emptyList());
}

@Test
public void constructor_throws_NPE_if_name_argument_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("name can not be null");

new QualityGateImpl(SOME_ID, null, SOME_STATUS, Collections.<QualityGate.Condition>emptyList());
}

@Test
public void constructor_throws_NPE_if_status_argument_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status can not be null");

new QualityGateImpl(SOME_ID, SOME_NAME, null, Collections.<QualityGate.Condition>emptyList());
}

@Test
public void constructor_throws_NPE_if_conditions_argument_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("conditions can not be null");

new QualityGateImpl(SOME_ID, SOME_NAME, SOME_STATUS, null);
}

@Test
public void verify_getters() {
List<QualityGate.Condition> conditions = ImmutableList.of(condition);

QualityGateImpl underTest = new QualityGateImpl(SOME_ID, SOME_NAME, SOME_STATUS, conditions);

assertThat(underTest.getId()).isEqualTo(SOME_ID);
assertThat(underTest.getName()).isEqualTo(SOME_NAME);
assertThat(underTest.getStatus()).isEqualTo(SOME_STATUS);
assertThat(underTest.getConditions()).isEqualTo(conditions);
}

@Test
public void verify_toString() {
when(condition.toString()).thenReturn("{Condition}");

assertThat(underTest.toString())
.isEqualTo("QualityGateImpl{id='some id', name='some name', status=OK, conditions=[{Condition}]}");
}
}

+ 99
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionStatusTest.java View File

@@ -0,0 +1,99 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.computation.qualitygate.ConditionStatus.EvaluationStatus.NO_VALUE;
import static org.sonar.server.computation.qualitygate.ConditionStatus.EvaluationStatus.OK;
import static org.sonar.server.computation.qualitygate.ConditionStatus.EvaluationStatus.values;

@RunWith(DataProviderRunner.class)
public class ConditionStatusTest {
private static final String SOME_VALUE = "value";

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void create_throws_NPE_if_status_argument_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status can not be null");

ConditionStatus.create(null, SOME_VALUE);
}

@Test
public void create_throws_IAE_if_status_argument_is_NO_VALUE() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("EvaluationStatus 'NO_VALUE' can not be used with this method, use constant ConditionStatus.NO_VALUE_STATUS instead.");

ConditionStatus.create(NO_VALUE, SOME_VALUE);
}

@Test
@UseDataProvider("allStatusesButNO_VALUE")
public void create_throws_NPE_if_value_is_null_and_status_argument_is_not_NO_VALUE(ConditionStatus.EvaluationStatus status) {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("value can not be null");

ConditionStatus.create(status, null);
}

@Test
public void verify_getters() {
ConditionStatus underTest = ConditionStatus.create(OK, SOME_VALUE);

assertThat(underTest.getStatus()).isEqualTo(OK);
assertThat(underTest.getValue()).isEqualTo(SOME_VALUE);
}

@Test
public void verify_toString() {
assertThat(ConditionStatus.create(OK, SOME_VALUE).toString()).isEqualTo("ConditionStatus{status=OK, value='value'}");
assertThat(ConditionStatus.NO_VALUE_STATUS.toString()).isEqualTo("ConditionStatus{status=NO_VALUE, value='null'}");
}

@Test
public void constant_NO_VALUE_STATUS_has_status_NO_VALUE_and_null_value() {
assertThat(ConditionStatus.NO_VALUE_STATUS.getStatus()).isEqualTo(NO_VALUE);
assertThat(ConditionStatus.NO_VALUE_STATUS.getValue()).isNull();
}

@DataProvider
public static Object[][] allStatusesButNO_VALUE() {
Object[][] res = new Object[values().length - 1][1];
int i = 0;
for (ConditionStatus.EvaluationStatus status : values()) {
if (status != NO_VALUE) {
res[i][0] = status;
i++;
}
}
return res;
}
}

+ 51
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/MutableQualityGateStatusHolderRule.java View File

@@ -0,0 +1,51 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import java.util.Map;
import org.junit.rules.ExternalResource;

public class MutableQualityGateStatusHolderRule extends ExternalResource implements MutableQualityGateStatusHolder {
private MutableQualityGateStatusHolder delegate = new QualityGateStatusHolderImpl();

@Override
public void setStatus(QualityGateStatus globalStatus, Map<Condition, ConditionStatus> statusPerCondition) {
delegate.setStatus(globalStatus, statusPerCondition);
}

@Override
public QualityGateStatus getStatus() {
return delegate.getStatus();
}

@Override
public Map<Condition, ConditionStatus> getStatusPerConditions() {
return delegate.getStatusPerConditions();
}

@Override
protected void after() {
reset();
}

public void reset() {
this.delegate = new QualityGateStatusHolderImpl();
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateHolderImplTest.java View File

@@ -27,7 +27,7 @@ import static org.assertj.guava.api.Assertions.assertThat;

public class QualityGateHolderImplTest {

public static final QualityGate QUALITY_GATE = new QualityGate("name", Collections.<Condition>emptyList());
public static final QualityGate QUALITY_GATE = new QualityGate(4612, "name", Collections.<Condition>emptyList());

@Test(expected = IllegalStateException.class)
public void getQualityGate_throws_ISE_if_QualityGate_not_set() {

+ 2
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateServiceImplTest.java View File

@@ -64,6 +64,7 @@ public class QualityGateServiceImplTest {
Optional<QualityGate> res = underTest.findById(SOME_ID);

assertThat(res).isPresent();
assertThat(res.get().getId()).isEqualTo(SOME_ID);
assertThat(res.get().getName()).isEqualTo(SOME_NAME);
assertThat(res.get().getConditions()).isEmpty();
}
@@ -79,6 +80,7 @@ public class QualityGateServiceImplTest {
Optional<QualityGate> res = underTest.findById(SOME_ID);

assertThat(res).isPresent();
assertThat(res.get().getId()).isEqualTo(SOME_ID);
assertThat(res.get().getName()).isEqualTo(SOME_NAME);
assertThat(res.get().getConditions()).containsOnly(
new Condition(METRIC_1, CONDITION_1.getOperator(), CONDITION_1.getErrorThreshold(), CONDITION_1.getWarningThreshold(), CONDITION_1.getPeriod()),

+ 117
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/QualityGateStatusHolderImplTest.java View File

@@ -0,0 +1,117 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.qualitygate;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.Collections;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

@RunWith(DataProviderRunner.class)
public class QualityGateStatusHolderImplTest {
private static final Map<Condition, ConditionStatus> SOME_STATUS_PER_CONDITION = Collections.singletonMap(
mock(Condition.class), ConditionStatus.create(ConditionStatus.EvaluationStatus.OK, "val"));

@Rule
public ExpectedException expectedException = ExpectedException.none();

private QualityGateStatusHolderImpl underTest = new QualityGateStatusHolderImpl();

@Test
public void setStatus_throws_NPE_if_globalStatus_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("global status can not be null");

underTest.setStatus(null, SOME_STATUS_PER_CONDITION);
}

@Test
public void setStatus_throws_NPE_if_statusPerCondition_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status per condition can not be null");

underTest.setStatus(QualityGateStatus.OK, null);
}

@Test
public void setStatus_throws_ISE_if_called_twice() {
underTest.setStatus(QualityGateStatus.OK, SOME_STATUS_PER_CONDITION);

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Quality gate status has already been set in the holder");

underTest.setStatus(null, null);
}

@Test
public void getStatus_throws_ISE_if_setStatus_not_called_yet() {
expectQGNotSetYetISE();

underTest.getStatus();
}

@Test
@UseDataProvider("qualityGateStatusValue")
public void getStatus_returns_status_argument_from_setStatus(QualityGateStatus status) {
underTest.setStatus(status, SOME_STATUS_PER_CONDITION);

assertThat(underTest.getStatus()).isEqualTo(status);
}

@Test
public void getStatusPerConditions_throws_ISE_if_setStatus_not_called_yet() {
expectQGNotSetYetISE();

underTest.getStatusPerConditions();
}

@Test
public void getStatusPerConditions_returns_statusPerCondition_argument_from_setStatus() {
underTest.setStatus(QualityGateStatus.ERROR, SOME_STATUS_PER_CONDITION);

assertThat(underTest.getStatusPerConditions()).isEqualTo(SOME_STATUS_PER_CONDITION);
// a copy is made to be immutable
assertThat(underTest.getStatusPerConditions()).isNotSameAs(SOME_STATUS_PER_CONDITION);
}

private void expectQGNotSetYetISE() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Quality gate status has not been set yet");
}

@DataProvider
public static Object[][] qualityGateStatusValue() {
Object[][] res = new Object[QualityGateStatus.values().length][1];
int i = 0;
for (QualityGateStatus status : QualityGateStatus.values()) {
res[i][0] = status;
i++;
}
return res;
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityGateLoadingStepTest.java View File

@@ -101,7 +101,7 @@ public class QualityGateLoadingStepTest {

@Test
public void execute_sets_QualityGate_if_it_can_be_found_by_service() {
QualityGate qualityGate = new QualityGate("name", Collections.<Condition>emptyList());
QualityGate qualityGate = new QualityGate(465, "name", Collections.<Condition>emptyList());

treeRootHolder.setRoot(PROJECT_ALONE);
when(settingsRepository.getSettings(PROJECT_ALONE)).thenReturn(new Settings().setProperty("sonar.qualitygate", 10));

+ 132
- 27
server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityGateMeasuresStepTest.java View File

@@ -21,10 +21,14 @@ package org.sonar.server.computation.step;

import com.google.common.base.Optional;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -40,10 +44,14 @@ import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.metric.MetricImpl;
import org.sonar.server.computation.metric.MetricRepository;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.ConditionStatus;
import org.sonar.server.computation.qualitygate.EvaluationResult;
import org.sonar.server.computation.qualitygate.EvaluationResultTextConverter;
import org.sonar.server.computation.qualitygate.MutableQualityGateStatusHolderRule;
import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateHolderRule;
import org.sonar.server.computation.qualitygate.QualityGateStatus;
import org.sonar.server.computation.qualitygate.QualityGateStatusHolder;

import static com.google.common.collect.ImmutableList.of;
import static org.mockito.Matchers.any;
@@ -62,11 +70,17 @@ public class QualityGateMeasuresStepTest {
private static final MetricImpl INT_METRIC_2 = createIntMetric(2);

private static final ReportComponent PROJECT_COMPONENT = ReportComponent.builder(Component.Type.PROJECT, 1).build();
private static final long SOME_QG_ID = 7521551;
private static final String SOME_QG_NAME = "name";

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
@Rule
public QualityGateHolderRule qualityGateHolder = new QualityGateHolderRule();
@Rule
public MutableQualityGateStatusHolderRule qualityGateStatusHolder = new MutableQualityGateStatusHolderRule();

private static final Metric ALERT_STATUS_METRIC = mock(Metric.class);
private static final Metric QUALITY_GATE_DETAILS_METRIC = mock(Metric.class);
@@ -77,7 +91,8 @@ public class QualityGateMeasuresStepTest {
private MeasureRepository measureRepository = mock(MeasureRepository.class);
private MetricRepository metricRepository = mock(MetricRepository.class);
private EvaluationResultTextConverter resultTextConverter = mock(EvaluationResultTextConverter.class);
private QualityGateMeasuresStep underTest = new QualityGateMeasuresStep(treeRootHolder, qualityGateHolder, measureRepository, metricRepository, resultTextConverter);
private QualityGateMeasuresStep underTest = new QualityGateMeasuresStep(treeRootHolder, qualityGateHolder, qualityGateStatusHolder, measureRepository, metricRepository,
resultTextConverter);

@Before
public void setUp() {
@@ -121,10 +136,22 @@ public class QualityGateMeasuresStepTest {
verifyNoMoreInteractions(measureRepository);
}

@Test
public void mutableQualityGateStatusHolder_is_not_populated_if_there_is_no_qualitygate() {
qualityGateHolder.setQualityGate(null);

underTest.execute();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Quality gate status has not been set yet");

qualityGateStatusHolder.getStatus();
}

@Test
public void new_measures_are_created_even_if_there_is_no_rawMeasure_for_metric_of_condition() {
Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
qualityGateHolder.setQualityGate(new QualityGate("name", of(equals2Condition)));
qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition)));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_1)).thenReturn(Optional.<Measure>absent());

underTest.execute();
@@ -139,6 +166,11 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateText("");
assertThat(qgDetailsMeasureCaptor.getValue())
.hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList()).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
.hasConditionCount(1)
.hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.NO_VALUE, null);
}

@Test
@@ -147,7 +179,7 @@ public class QualityGateMeasuresStepTest {
Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
Measure rawMeasure = Measure.newMeasureBuilder().create(rawValue, null);

qualityGateHolder.setQualityGate(new QualityGate("name", of(equals2Condition)));
qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition)));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_1)).thenReturn(Optional.of(rawMeasure));

underTest.execute();
@@ -168,6 +200,11 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
assertThat(qgDetailsMeasureCaptor.getValue())
.hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue))).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
.hasConditionCount(1)
.hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.OK, String.valueOf(rawValue));
}

@Test
@@ -177,7 +214,7 @@ public class QualityGateMeasuresStepTest {
Condition equals1WarningCondition = createEqualsCondition(INT_METRIC_2, null, "1");
Measure rawMeasure = Measure.newMeasureBuilder().create(rawValue, null);

qualityGateHolder.setQualityGate(new QualityGate("name", of(equals1ErrorCondition, equals1WarningCondition)));
qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals1ErrorCondition, equals1WarningCondition)));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_1)).thenReturn(Optional.of(rawMeasure));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_2)).thenReturn(Optional.of(rawMeasure));

@@ -195,20 +232,25 @@ public class QualityGateMeasuresStepTest {
verifyNoMoreInteractions(measureRepository);

assertThat(equals1ErrorConditionMeasureCaptor.getValue())
.hasQualityGateLevel(ERROR)
.hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue));
.hasQualityGateLevel(ERROR)
.hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue));
assertThat(equals1WarningConditionMeasureCaptor.getValue())
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
assertThat(alertStatusMeasureCaptor.getValue())
.hasQualityGateLevel(ERROR)
.hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue) + ", "
+ dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
.hasQualityGateLevel(ERROR)
.hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue) + ", "
+ dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
assertThat(qgDetailsMeasureCaptor.getValue())
.hasValue(new QualityGateDetailsData(ERROR, of(
new EvaluatedCondition(equals1ErrorCondition, ERROR, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)
)).toJson());
.hasValue(new QualityGateDetailsData(ERROR, of(
new EvaluatedCondition(equals1ErrorCondition, ERROR, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.ERROR)
.hasConditionCount(2)
.hasCondition(equals1ErrorCondition, ConditionStatus.EvaluationStatus.ERROR, String.valueOf(rawValue))
.hasCondition(equals1WarningCondition, ConditionStatus.EvaluationStatus.WARN, String.valueOf(rawValue));
}

@Test
@@ -218,7 +260,7 @@ public class QualityGateMeasuresStepTest {
Condition equals1WarningCondition = createEqualsCondition(INT_METRIC_2, null, "1");
Measure rawMeasure = Measure.newMeasureBuilder().create(rawValue, null);

qualityGateHolder.setQualityGate(new QualityGate("name", of(equals2Condition, equals1WarningCondition)));
qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition, equals1WarningCondition)));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_1)).thenReturn(Optional.of(rawMeasure));
when(measureRepository.getRawMeasure(PROJECT_COMPONENT, INT_METRIC_2)).thenReturn(Optional.of(rawMeasure));

@@ -236,20 +278,25 @@ public class QualityGateMeasuresStepTest {
verifyNoMoreInteractions(measureRepository);

assertThat(equals2ConditionMeasureCaptor.getValue())
.hasQualityGateLevel(OK)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
.hasQualityGateLevel(OK)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
assertThat(equals1WarningConditionMeasureCaptor.getValue())
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
assertThat(alertStatusMeasureCaptor.getValue())
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue) + ", "
+ dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue) + ", "
+ dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
assertThat(qgDetailsMeasureCaptor.getValue())
.hasValue(new QualityGateDetailsData(WARN, of(
new EvaluatedCondition(equals2Condition, OK, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)
)).toJson());
.hasValue(new QualityGateDetailsData(WARN, of(
new EvaluatedCondition(equals2Condition, OK, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.WARN)
.hasConditionCount(2)
.hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.OK, String.valueOf(rawValue))
.hasCondition(equals1WarningCondition, ConditionStatus.EvaluationStatus.WARN, String.valueOf(rawValue));
}

private static Condition createEqualsCondition(Metric metric, @Nullable String errorThreshold, @Nullable String warningThreshold) {
@@ -260,4 +307,62 @@ public class QualityGateMeasuresStepTest {
return new MetricImpl(index, "metricKey" + index, "metricName" + index, Metric.MetricType.INT);
}

private static class QualityGateStatusHolderAssertions extends AbstractAssert<QualityGateStatusHolderAssertions, QualityGateStatusHolder> {

private QualityGateStatusHolderAssertions(QualityGateStatusHolder actual) {
super(actual, QualityGateStatusHolderAssertions.class);
}

public static QualityGateStatusHolderAssertions assertThat(QualityGateStatusHolder holder) {
return new QualityGateStatusHolderAssertions(holder);
}

public QualityGateStatusHolderAssertions hasStatus(QualityGateStatus status) {
if (actual.getStatus() != status) {
failWithMessage(
"Expected QualityGateStatusHolder to have global status <%s> but was <%s>",
status, actual.getStatus());
}

return this;
}

public QualityGateStatusHolderAssertions hasConditionCount(int count) {
int conditionCount = actual.getStatusPerConditions().size();
if (conditionCount != count) {
failWithMessage(
"Expected QualityGateStatusHolder to have <%s> conditions but it has <%s>",
count, conditionCount);
}

return this;
}

public QualityGateStatusHolderAssertions hasCondition(Condition condition, ConditionStatus.EvaluationStatus evaluationStatus, @Nullable String expectedValue) {
for (Map.Entry<Condition, ConditionStatus> entry : actual.getStatusPerConditions().entrySet()) {
if (entry.getKey() == condition) {
ConditionStatus.EvaluationStatus actualStatus = entry.getValue().getStatus();
if (actualStatus != evaluationStatus) {
failWithMessage(
"Expected Status of condition <%s> in QualityGateStatusHolder to be <%s> but it was <%s>",
condition, evaluationStatus, actualStatus);
}
String actualValue = entry.getValue().getValue();
if (!Objects.equals(expectedValue, actualValue)) {
failWithMessage(
"Expected Value of condition <%s> in QualityGateStatusHolder to be <%s> but it was <%s>",
condition, expectedValue, actualValue);
}
return this;
}
}

failWithMessage(
"Expected QualityGateStatusHolder to have an entry for <%s> but none was found",
condition);

return this;
}
}

}

Loading…
Cancel
Save