Browse Source

SONAR-9352 add "ignoredConditions" to response example of api/qualitygates/project_status

tags/6.6-RC1
Daniel Schwarz 6 years ago
parent
commit
454f14e468
13 changed files with 191 additions and 46 deletions
  1. 5
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java
  2. 20
    2
      server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java
  3. 10
    18
      server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java
  4. 5
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
  5. 10
    0
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
  6. 1
    0
      server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
  7. 14
    4
      server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java
  8. 4
    4
      server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java
  9. 28
    14
      server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java
  10. 12
    0
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
  11. 1
    0
      sonar-ws/src/main/protobuf/ws-qualitygates.proto
  12. 1
    1
      tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm
  13. 80
    1
      tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java

+ 5
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java View File

@@ -32,13 +32,16 @@ import static java.util.Objects.requireNonNull;
@Immutable
public class QualityGateDetailsData {
private static final String FIELD_LEVEL = "level";
private static final String FIELD_IGNORED_CONDITIONS = "ignoredConditions";

private final Measure.Level level;
private final List<EvaluatedCondition> conditions;
private final boolean ignoredConditions;

public QualityGateDetailsData(Measure.Level level, Iterable<EvaluatedCondition> conditions) {
public QualityGateDetailsData(Measure.Level level, Iterable<EvaluatedCondition> conditions, boolean ignoredConditions) {
this.level = requireNonNull(level);
this.conditions = from(conditions).toList();
this.ignoredConditions = ignoredConditions;
}

public String toJson() {
@@ -49,6 +52,7 @@ public class QualityGateDetailsData {
conditionResults.add(toJson(condition));
}
details.add("conditions", conditionResults);
details.addProperty(FIELD_IGNORED_CONDITIONS, ignoredConditions);
return details.toString();
}


+ 20
- 2
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java View File

@@ -174,6 +174,7 @@ public class QualityGateMeasuresStep implements ComputationStep {

private void updateMeasures(Component project, Set<Condition> conditions, QualityGateDetailsDataBuilder builder) {
Multimap<Metric, Condition> conditionsPerMetric = conditions.stream().collect(MoreCollectors.index(Condition::getMetric, java.util.function.Function.identity()));
boolean ignoredConditions = false;
for (Map.Entry<Metric, Collection<Condition>> entry : conditionsPerMetric.asMap().entrySet()) {
Metric metric = entry.getKey();
Optional<Measure> measure = measureRepository.getRawMeasure(project, metric);
@@ -182,7 +183,13 @@ public class QualityGateMeasuresStep implements ComputationStep {
}

final MetricEvaluationResult metricEvaluationResult = evaluateQualityGate(measure.get(), entry.getValue());
final MetricEvaluationResult finalMetricEvaluationResult = smallChangesetQualityGateSpecialCase.applyIfNeeded(project, metricEvaluationResult);
final MetricEvaluationResult finalMetricEvaluationResult;
if (smallChangesetQualityGateSpecialCase.appliesTo(project, metricEvaluationResult)) {
finalMetricEvaluationResult = smallChangesetQualityGateSpecialCase.apply(metricEvaluationResult);
ignoredConditions = true;
} else {
finalMetricEvaluationResult = metricEvaluationResult;
}
String text = evaluationResultTextConverter.asText(finalMetricEvaluationResult.condition, finalMetricEvaluationResult.evaluationResult);
builder.addLabel(text);

@@ -193,6 +200,7 @@ public class QualityGateMeasuresStep implements ComputationStep {

builder.addEvaluatedCondition(finalMetricEvaluationResult);
}
builder.setIgnoredConditions(ignoredConditions);
}

private static MetricEvaluationResult evaluateQualityGate(Measure measure, Collection<Condition> conditions) {
@@ -214,7 +222,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
Metric metric = metricRepository.getByKey(CoreMetrics.ALERT_STATUS_KEY);
measureRepository.add(project, metric, globalMeasure);

String detailMeasureValue = new QualityGateDetailsData(builder.getGlobalLevel(), builder.getEvaluatedConditions()).toJson();
String detailMeasureValue = new QualityGateDetailsData(builder.getGlobalLevel(), builder.getEvaluatedConditions(), builder.isIgnoredConditions()).toJson();
Measure detailsMeasure = Measure.newMeasureBuilder().create(detailMeasureValue);
Metric qgDetailsMetric = metricRepository.getByKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY);
measureRepository.add(project, qgDetailsMetric, detailsMeasure);
@@ -229,6 +237,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
private Measure.Level globalLevel = Measure.Level.OK;
private List<String> labels = new ArrayList<>();
private List<EvaluatedCondition> evaluatedConditions = new ArrayList<>();
private boolean ignoredConditions;

public Measure.Level getGlobalLevel() {
return globalLevel;
@@ -259,6 +268,15 @@ public class QualityGateMeasuresStep implements ComputationStep {
public List<EvaluatedCondition> getEvaluatedConditions() {
return evaluatedConditions;
}

public boolean isIgnoredConditions() {
return ignoredConditions;
}

public QualityGateDetailsDataBuilder setIgnoredConditions(boolean ignoredConditions) {
this.ignoredConditions = ignoredConditions;
return this;
}
}

private enum EvaluatedConditionToCondition implements Function<EvaluatedCondition, Condition> {

+ 10
- 18
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java View File

@@ -27,15 +27,16 @@ import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
import org.sonar.server.computation.task.projectanalysis.qualitygate.EvaluationResult;
import org.sonar.server.computation.task.projectanalysis.step.QualityGateMeasuresStep.MetricEvaluationResult;

import static java.util.Arrays.asList;

public class SmallChangesetQualityGateSpecialCase {

/**
* Some metrics will only produce warnings (never errors) on very small change sets.
* Some metrics will be ignored on very small change sets.
*/
private static final Collection<String> METRICS_THAT_CAN_ONLY_PRODUCE_WARNINGS_ON_SMALL_CHANGESETS = asList(
private static final Collection<String> METRICS_TO_IGNORE_ON_SMALL_CHANGESETS = asList(
CoreMetrics.NEW_COVERAGE_KEY,
CoreMetrics.NEW_LINE_COVERAGE_KEY,
CoreMetrics.NEW_BRANCH_COVERAGE_KEY,
@@ -53,24 +54,15 @@ public class SmallChangesetQualityGateSpecialCase {
this.metricRepository = metricRepository;
}

QualityGateMeasuresStep.MetricEvaluationResult applyIfNeeded(Component project, @Nullable QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult) {
if (metricEvaluationResult == null) {
return metricEvaluationResult;
}
if (metricEvaluationResult.evaluationResult.getLevel() == Measure.Level.OK) {
return metricEvaluationResult;
}
if (!METRICS_THAT_CAN_ONLY_PRODUCE_WARNINGS_ON_SMALL_CHANGESETS.contains(metricEvaluationResult.condition.getMetric().getKey())) {
return metricEvaluationResult;
}
if (!isSmallChangeset(project)) {
return metricEvaluationResult;
}
return calculateModifiedResult(metricEvaluationResult);
public boolean appliesTo(Component project, @Nullable MetricEvaluationResult metricEvaluationResult) {
return metricEvaluationResult != null
&& metricEvaluationResult.evaluationResult.getLevel() != Measure.Level.OK
&& METRICS_TO_IGNORE_ON_SMALL_CHANGESETS.contains(metricEvaluationResult.condition.getMetric().getKey())
&& isSmallChangeset(project);
}

private QualityGateMeasuresStep.MetricEvaluationResult calculateModifiedResult(@Nullable QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult) {
return new QualityGateMeasuresStep.MetricEvaluationResult(
MetricEvaluationResult apply(MetricEvaluationResult metricEvaluationResult) {
return new MetricEvaluationResult(
new EvaluationResult(Measure.Level.OK, metricEvaluationResult.evaluationResult.getValue()), metricEvaluationResult.condition);
}


+ 5
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -87,7 +88,10 @@ public class ProjectStatusAction implements QualityGatesWsAction {
"</ul>", QG_STATUSES_ONE_LINE, ProjectStatusWsResponse.Status.NONE))
.setResponseExample(getClass().getResource("project_status-example.json"))
.setSince("5.3")
.setHandler(this);
.setHandler(this)
.setChangelog(
new Change("6.4", "The field 'ignoredConditions' is added to the response")
);

action.createParam(PARAM_ANALYSIS_ID)
.setDescription("Analysis id")

+ 10
- 0
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java View File

@@ -55,12 +55,22 @@ public class QualityGateDetailsFormatter {
ProjectStatusWsResponse.Status qualityGateStatus = measureLevelToQualityGateStatus(json.get("level").getAsString());
projectStatusBuilder.setStatus(qualityGateStatus);

formatIgnoredConditions(json);
formatConditions(json.getAsJsonArray("conditions"));
formatPeriods();

return projectStatusBuilder.build();
}

private void formatIgnoredConditions(JsonObject json) {
JsonElement ignoredConditions = json.get("ignoredConditions");
if (ignoredConditions != null) {
projectStatusBuilder.setIgnoredConditions(ignoredConditions.getAsBoolean());
} else {
projectStatusBuilder.setIgnoredConditions(false);
}
}

private void formatPeriods() {
if (!optionalSnapshot.isPresent()) {
return;

+ 1
- 0
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json View File

@@ -1,6 +1,7 @@
{
"projectStatus": {
"status": "ERROR",
"ignoredConditions": false,
"conditions": [
{
"status": "ERROR",

+ 14
- 4
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java View File

@@ -31,17 +31,17 @@ import org.sonar.test.JsonAssert;
public class QualityGateDetailsDataTest {
@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_if_Level_arg_is_null() {
new QualityGateDetailsData(null, Collections.<EvaluatedCondition>emptyList());
new QualityGateDetailsData(null, Collections.<EvaluatedCondition>emptyList(), false);
}

@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_if_Iterable_arg_is_null() {
new QualityGateDetailsData(Measure.Level.OK, null);
new QualityGateDetailsData(Measure.Level.OK, null, false);
}

@Test
public void verify_json_when_there_is_no_condition() {
String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList()).toJson();
String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), false).toJson();

JsonAssert.assertJson(actualJson).isSimilarTo("{" +
"\"level\":\"OK\"," +
@@ -57,7 +57,7 @@ public class QualityGateDetailsDataTest {
new EvaluatedCondition(condition, Measure.Level.OK, value),
new EvaluatedCondition(condition, Measure.Level.WARN, value),
new EvaluatedCondition(condition, Measure.Level.ERROR, value));
String actualJson = new QualityGateDetailsData(Measure.Level.OK, evaluatedConditions).toJson();
String actualJson = new QualityGateDetailsData(Measure.Level.OK, evaluatedConditions, false).toJson();

JsonAssert.assertJson(actualJson).isSimilarTo("{" +
"\"level\":\"OK\"," +
@@ -92,4 +92,14 @@ public class QualityGateDetailsDataTest {
"]" +
"}");
}

@Test
public void verify_json_for_small_leak() {
String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), false).toJson();
JsonAssert.assertJson(actualJson).isSimilarTo("{\"ignoredConditions\": false}");

String actualJson2 = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), true).toJson();
JsonAssert.assertJson(actualJson2).isSimilarTo("{\"ignoredConditions\": true}");
}

}

+ 4
- 4
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java View File

@@ -161,7 +161,7 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateLevel(OK)
.hasQualityGateText("");
assertThat(getQGDetailsMeasure())
.hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList()).toJson());
.hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList(), false).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
@@ -189,7 +189,7 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateLevel(OK)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
assertThat(getQGDetailsMeasure().get())
.hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue))).toJson());
.hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue)), false).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
@@ -226,7 +226,7 @@ public class QualityGateMeasuresStepTest {
assertThat(getQGDetailsMeasure())
.hasValue(new QualityGateDetailsData(ERROR, of(
new EvaluatedCondition(equals1ErrorCondition, ERROR, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)), false).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.ERROR)
@@ -264,7 +264,7 @@ public class QualityGateMeasuresStepTest {
assertThat(getQGDetailsMeasure())
.hasValue(new QualityGateDetailsData(WARN, of(
new EvaluatedCondition(equals2Condition, OK, rawValue),
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)), false).toJson());

QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.WARN)

+ 28
- 14
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java View File

@@ -61,9 +61,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
assertThat(result).isTrue();
}

@Test
@@ -72,9 +72,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
assertThat(result).isTrue();
}

@Test
@@ -83,9 +83,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(20).create(1000));

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
assertThat(result).isFalse();
}

@Test
@@ -94,9 +94,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
assertThat(result).isFalse();
}

@Test
@@ -105,9 +105,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
assertThat(result).isFalse();
}

@Test
@@ -115,17 +115,31 @@ public class SmallChangesetQualityGateSpecialCaseTest {
QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult = generateEvaluationResult(NEW_COVERAGE_KEY, ERROR);
Component project = generateNewRootProject();

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
boolean result = underTest.appliesTo(project, metricEvaluationResult);

assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
assertThat(result).isFalse();
}

@Test
public void should_silently_ignore_null_values() throws Exception {

QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(mock(Component.class), null);
boolean result = underTest.appliesTo(mock(Component.class), null);

assertThat(result).isNull();
assertThat(result).isFalse();
}

@Test
public void apply() throws Exception {
Comparable<?> value = mock(Comparable.class);
Condition condition = mock(Condition.class);
QualityGateMeasuresStep.MetricEvaluationResult original = new QualityGateMeasuresStep.MetricEvaluationResult(
new EvaluationResult(Measure.Level.ERROR, value), condition);

QualityGateMeasuresStep.MetricEvaluationResult modified = underTest.apply(original);

assertThat(modified.evaluationResult.getLevel()).isSameAs(OK);
assertThat(modified.evaluationResult.getValue()).isSameAs(value);
assertThat(modified.condition).isSameAs(condition);
}

private Component generateNewRootProject() {

+ 12
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java View File

@@ -26,6 +26,8 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
@@ -47,6 +49,7 @@ import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse.Status;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.db.component.SnapshotTesting.newAnalysis;
import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
@@ -77,6 +80,15 @@ public class ProjectStatusActionTest {
ws = new WsActionTester(new ProjectStatusAction(dbClient, TestComponentFinder.from(db), userSession));
}

@Test
public void definition() throws Exception {
WebService.Action def = ws.getDef();
assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("analysisId", "projectKey", "projectId");
assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactly(
tuple("6.4", "The field 'ignoredConditions' is added to the response")
);
}

@Test
public void json_example() throws IOException {
ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());

+ 1
- 0
sonar-ws/src/main/protobuf/ws-qualitygates.proto View File

@@ -32,6 +32,7 @@ message ProjectStatusWsResponse {
optional Status status = 1;
repeated Condition conditions = 2;
repeated Period periods = 3;
optional bool ignoredConditions = 4;
}

message Condition {

+ 1
- 1
tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm View File

@@ -1017,4 +1017,4 @@
2,user2,2014-04-01
2,user2,2014-04-01
2,user2,2014-04-01
3,user3,2014-04-02
3,user3,2014-04-03

+ 80
- 1
tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java View File

@@ -21,17 +21,29 @@ package org.sonarqube.tests.qualityGate;

import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarScanner;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import org.apache.commons.io.FileUtils;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonarqube.tests.Category6Suite;
import org.sonarqube.tests.Tester;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.Organizations;
import org.sonarqube.ws.WsCe;
import org.sonarqube.ws.WsProjects.CreateWsResponse.Project;
import org.sonarqube.ws.WsQualityGates;
import org.sonarqube.ws.WsQualityGates.CreateWsResponse;
import org.sonarqube.ws.WsUsers;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.qualitygate.CreateConditionRequest;
import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest;
import org.sonarqube.ws.client.qualitygate.UpdateConditionRequest;

import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.getMeasure;
@@ -64,6 +76,7 @@ public class QualityGateForSmallChangesetsTest {
String password = "password1";
WsUsers.CreateWsResponse.User user = tester.users().generateAdministrator(organization, u -> u.setPassword(password));

// no leak => use usual behaviour
SonarScanner analysis = SonarScanner
.create(projectDir("qualitygate/small-changesets/v1-1000-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -76,7 +89,9 @@ public class QualityGateForSmallChangesetsTest {
.setDebugLogs(true);
orchestrator.executeBuild(analysis);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
assertIgnoredConditions(project, "qualitygate/small-changesets/v1-1000-lines", false);

// small leak => ignore coverage warning or error
SonarScanner analysis2 = SonarScanner
.create(projectDir("qualitygate/small-changesets/v2-1019-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -89,7 +104,40 @@ public class QualityGateForSmallChangesetsTest {
.setDebugLogs(true);
orchestrator.executeBuild(analysis2);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1019-lines", true);

// small leak => if coverage is OK anyways, we do not have to ignore anything
tester.wsClient().qualityGates().updateCondition(UpdateConditionRequest.builder()
.setConditionId(condition.getId())
.setMetricKey("new_coverage")
.setOperator("LT")
.setWarning("10")
.setError("20")
.setPeriod(1)
.build());
SonarScanner analysis3 = SonarScanner
.create(projectDir("qualitygate/small-changesets/v2-1019-lines"))
.setProperty("sonar.projectKey", project.getKey())
.setProperty("sonar.organization", organization.getKey())
.setProperty("sonar.login", user.getLogin())
.setProperty("sonar.password", password)
.setProperty("sonar.scm.provider", "xoo")
.setProperty("sonar.scm.disabled", "false")
.setProperty("sonar.projectDate", "2014-04-02")
.setDebugLogs(true);
orchestrator.executeBuild(analysis3);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1019-lines", false);

// big leak => use usual behaviour
tester.wsClient().qualityGates().updateCondition(UpdateConditionRequest.builder()
.setConditionId(condition.getId())
.setMetricKey("new_coverage")
.setOperator("LT")
.setWarning(null)
.setError("70")
.setPeriod(1)
.build());
SonarScanner analysis4 = SonarScanner
.create(projectDir("qualitygate/small-changesets/v2-1020-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -98,9 +146,40 @@ public class QualityGateForSmallChangesetsTest {
.setProperty("sonar.password", password)
.setProperty("sonar.scm.provider", "xoo")
.setProperty("sonar.scm.disabled", "false")
.setProperty("sonar.projectDate", "2014-04-02")
.setProperty("sonar.projectDate", "2014-04-03")
.setDebugLogs(true);
orchestrator.executeBuild(analysis4);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("ERROR");
assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1020-lines", false);
}

private void assertIgnoredConditions(Project project, String projectDir, boolean expected) throws IOException {
String analysisId = getAnalysisId(getTaskIdInLocalReport(projectDir(projectDir)));
boolean ignoredConditions = tester.wsClient().qualityGates()
.projectStatus(new ProjectStatusWsRequest().setAnalysisId(analysisId))
.getProjectStatus()
.getIgnoredConditions();
assertThat(ignoredConditions).isEqualTo(expected);
}

private String getAnalysisId(String taskId) throws IOException {
WsResponse activity = tester.wsClient()
.wsConnector()
.call(new GetRequest("api/ce/task")
.setParam("id", taskId)
.setMediaType(MediaTypes.PROTOBUF));
WsCe.TaskResponse activityWsResponse = WsCe.TaskResponse.parseFrom(activity.contentStream());
return activityWsResponse.getTask().getAnalysisId();
}

private String getTaskIdInLocalReport(File projectDirectory) throws IOException {
File metadata = new File(projectDirectory, ".sonar/report-task.txt");
assertThat(metadata).exists().isFile();
// verify properties
Properties props = new Properties();
props.load(new StringReader(FileUtils.readFileToString(metadata, StandardCharsets.UTF_8)));
assertThat(props.getProperty("ceTaskId")).isNotEmpty();

return props.getProperty("ceTaskId");
}
}

Loading…
Cancel
Save