@@ -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, |
@@ -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 + | |||
'}'; | |||
} | |||
} |
@@ -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 + '\'' + | |||
'}'; | |||
} | |||
} |
@@ -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)); | |||
} | |||
} | |||
} |
@@ -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 + | |||
'}'; | |||
} | |||
} | |||
} |
@@ -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 + '\'' + | |||
'}'; | |||
} | |||
} |
@@ -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 + | |||
'}'; | |||
} | |||
} |
@@ -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; |
@@ -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 | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 | |||
} |
@@ -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(); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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}"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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'}"); | |||
} | |||
} |
@@ -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}]}"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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() { |
@@ -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()), |
@@ -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; | |||
} | |||
} |
@@ -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)); |
@@ -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; | |||
} | |||
} | |||
} |