From 3f06e24f94f48209bb847bb5b763c96c59b23ee7 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 20 Sep 2016 19:32:01 +0200 Subject: [PATCH] SONAR-8117 Extract update of quality gate condition into QualityGateConditionsUpdater --- .../QualityGateConditionsUpdater.java | 26 +++ .../server/qualitygate/QualityGates.java | 116 ---------- .../qualitygate/ws/UpdateConditionAction.java | 88 ++++++-- .../QualityGateConditionsUpdaterTest.java | 99 +++++++-- .../server/qualitygate/QualityGatesTest.java | 33 --- .../qualitygate/ws/QualityGatesWsTest.java | 22 +- .../ws/UpdateConditionActionTest.java | 208 ++++++++++++++++++ .../qualitygate/QualityGatesService.java | 14 ++ .../qualitygate/QualityGatesWsParameters.java | 1 + .../qualitygate/UpdateConditionRequest.java | 125 +++++++++++ .../src/main/protobuf/ws-qualitygates.proto | 10 + .../qualitygate/QualityGatesServiceTest.java | 27 +++ .../UpdateConditionRequestTest.java | 91 ++++++++ 13 files changed, 653 insertions(+), 207 deletions(-) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java create mode 100644 sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequest.java create mode 100644 sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequestTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java index f5a988c1ce5..1dbe6f9150e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java @@ -65,6 +65,24 @@ public class QualityGateConditionsUpdater { return newCondition; } + public QualityGateConditionDto updateCondition(DbSession dbSession, long condId, String metricKey, String operator, + @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { + QualityGateConditionDto condition = getNonNullCondition(dbSession, condId); + MetricDto metric = getNonNullMetric(dbSession, metricKey); + validateCondition(metric, operator, warningThreshold, errorThreshold, period); + checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(dbSession, condition.getQualityGateId(), condition.getId()), metric, period); + + condition + .setMetricId(metric.getId()) + .setMetricKey(metric.getKey()) + .setOperator(operator) + .setWarningThreshold(warningThreshold) + .setErrorThreshold(errorThreshold) + .setPeriod(period); + dbClient.gateConditionDao().update(condition, dbSession); + return condition; + } + private QualityGateDto getNonNullQgate(DbSession dbSession, long id) { QualityGateDto qGate = dbClient.qualityGateDao().selectById(dbSession, id); if (qGate == null) { @@ -81,6 +99,14 @@ public class QualityGateConditionsUpdater { return metric; } + private QualityGateConditionDto getNonNullCondition(DbSession dbSession, long id) { + QualityGateConditionDto condition = dbClient.gateConditionDao().selectById(id, dbSession); + if (condition == null) { + throw new NotFoundException("There is no condition with id=" + id); + } + return condition; + } + private Collection getConditions(DbSession dbSession, long qGateId, @Nullable Long conditionId) { Collection conditions = dbClient.gateConditionDao().selectForQualityGate(qGateId, dbSession); if (conditionId == null) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java index 5dfa118f475..4743bb28717 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java @@ -19,19 +19,12 @@ */ package org.sonar.server.qualitygate; -import com.google.common.base.Predicate; import com.google.common.base.Strings; import java.util.Collection; -import java.util.stream.Collectors; import javax.annotation.CheckForNull; -import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.apache.commons.lang.BooleanUtils; -import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; -import org.sonar.api.measures.Metric.ValueType; import org.sonar.api.measures.MetricFinder; import org.sonar.api.web.UserRole; import org.sonar.core.permission.GlobalPermissions; @@ -54,8 +47,6 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import org.sonar.server.util.Validation; -import static java.lang.String.format; - /** * Methods from this class should be moved to {@link QualityGateUpdater} and to new classes QualityGateFinder / QualityGateConditionsUpdater / etc. * in order to have classes with clearer responsibilities and more easily testable (without having to use too much mocks) @@ -170,24 +161,6 @@ public class QualityGates { } } - public QualityGateConditionDto updateCondition(long condId, String metricKey, String operator, - @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { - checkPermission(); - QualityGateConditionDto condition = getNonNullCondition(condId); - Metric metric = getNonNullMetric(metricKey); - validateCondition(metric, operator, warningThreshold, errorThreshold, period); - checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(condition.getQualityGateId(), condition.getId()), metric, period); - condition - .setMetricId(metric.getId()) - .setMetricKey(metric.getKey()) - .setOperator(operator) - .setWarningThreshold(warningThreshold) - .setErrorThreshold(errorThreshold) - .setPeriod(period); - conditionDao.update(condition); - return condition; - } - public Collection listConditions(long qGateId) { Collection conditionsForGate = conditionDao.selectForQualityGate(qGateId); for (QualityGateConditionDto condition : conditionsForGate) { @@ -227,70 +200,6 @@ public class QualityGates { } } - private Collection getConditions(long qGateId, @Nullable Long conditionId) { - Collection conditions = conditionDao.selectForQualityGate(qGateId); - if (conditionId == null) { - return conditions; - } - return conditionDao.selectForQualityGate(qGateId).stream() - .filter(condition -> condition.getId() != conditionId) - .collect(Collectors.toList()); - } - - private static void validateCondition(Metric metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { - Errors errors = new Errors(); - validateMetric(metric, errors); - checkOperator(metric, operator, errors); - checkThresholds(warningThreshold, errorThreshold, errors); - checkPeriod(metric, period, errors); - if (!errors.isEmpty()) { - throw new BadRequestException(errors); - } - } - - private static void checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(Collection conditions, Metric metric, @Nullable final Integer period) { - if (conditions.isEmpty()) { - return; - } - - boolean conditionExists = conditions.stream().anyMatch(new MatchMetricAndPeriod(metric.getId(), period)::apply); - if (conditionExists) { - String errorMessage = period == null - ? format("Condition on metric '%s' already exists.", metric.getName()) - : format("Condition on metric '%s' over leak period already exists.", metric.getName()); - throw new BadRequestException(errorMessage); - } - } - - private static void checkPeriod(Metric metric, @Nullable Integer period, Errors errors) { - if (period == null) { - errors.check(!metric.getKey().startsWith("new_"), "A period must be selected for differential metrics."); - } else { - errors.check(period == 1, "The only valid quality gate period is 1, the leak period."); - } - } - - private static void checkThresholds(@Nullable String warningThreshold, @Nullable String errorThreshold, Errors errors) { - errors.check(warningThreshold != null || errorThreshold != null, "At least one threshold (warning, error) must be set."); - } - - private static void checkOperator(Metric metric, String operator, Errors errors) { - errors - .check(QualityGateConditionDto.isOperatorAllowed(operator, metric.getType()), format("Operator %s is not allowed for metric type %s.", operator, metric.getType())); - } - - private static void validateMetric(Metric metric, Errors errors) { - errors.check(isAlertable(metric), format("Metric '%s' cannot be used to define a condition.", metric.getKey())); - } - - private static boolean isAlertable(Metric metric) { - return isAvailableForInit(metric) && BooleanUtils.isFalse(metric.isHidden()); - } - - private static boolean isAvailableForInit(Metric metric) { - return !metric.isDataType() && !CoreMetrics.ALERT_STATUS.equals(metric) && ValueType.RATING != metric.getType(); - } - private boolean isDefault(QualityGateDto qGate) { return qGate.getId().equals(getDefaultId()); } @@ -329,14 +238,6 @@ public class QualityGates { return qGate; } - private Metric getNonNullMetric(String metricKey) { - Metric metric = metricFinder.findByKey(metricKey); - if (metric == null) { - throw new NotFoundException("There is no metric with key=" + metricKey); - } - return metric; - } - private QualityGateConditionDto getNonNullCondition(long id) { QualityGateConditionDto condition = conditionDao.selectById(id); if (condition == null) { @@ -374,21 +275,4 @@ public class QualityGates { throw new ForbiddenException("Insufficient privileges"); } } - - private static class MatchMetricAndPeriod implements Predicate { - private final int metricId; - @CheckForNull - private final Integer period; - - public MatchMetricAndPeriod(int metricId, @Nullable Integer period) { - this.metricId = metricId; - this.period = period; - } - - @Override - public boolean apply(@Nonnull QualityGateConditionDto input) { - return input.getMetricId() == metricId && - ObjectUtils.equals(input.getPeriod(), period); - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java index 1c9f637a59e..b5a427a617f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java @@ -22,46 +22,98 @@ package org.sonar.server.qualitygate.ws; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; -import org.sonar.server.qualitygate.QualityGates; -import org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.qualitygate.QualityGateConditionDto; +import org.sonar.server.qualitygate.QualityGateConditionsUpdater; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.WsQualityGates.UpdateConditionWsResponse; +import org.sonarqube.ws.client.qualitygate.UpdateConditionRequest; + +import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; +import static org.sonar.server.qualitygate.ws.QualityGatesWs.addConditionParams; +import static org.sonar.server.ws.WsUtils.writeProtobuf; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_UPDATE_CONDITION; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ERROR; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ID; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_METRIC; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_OPERATOR; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PERIOD; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_WARNING; public class UpdateConditionAction implements QualityGatesWsAction { - private final QualityGates qualityGates; + private final UserSession userSession; + private final DbClient dbClient; + private final QualityGateConditionsUpdater qualityGateConditionsUpdater; - public UpdateConditionAction(QualityGates qualityGates) { - this.qualityGates = qualityGates; + public UpdateConditionAction(UserSession userSession, DbClient dbClient, QualityGateConditionsUpdater qualityGateConditionsUpdater) { + this.userSession = userSession; + this.dbClient = dbClient; + this.qualityGateConditionsUpdater = qualityGateConditionsUpdater; } @Override public void define(WebService.NewController controller) { - WebService.NewAction createCondition = controller.createAction("update_condition") + WebService.NewAction createCondition = controller.createAction(ACTION_UPDATE_CONDITION) .setDescription("Update a condition attached to a quality gate. Require Administer Quality Gates permission") .setPost(true) .setSince("4.3") .setHandler(this); createCondition - .createParam(QualityGatesWsParameters.PARAM_ID) + .createParam(PARAM_ID) .setDescription("Condition ID") .setRequired(true) .setExampleValue("10"); - QualityGatesWs.addConditionParams(createCondition); + addConditionParams(createCondition); } @Override public void handle(Request request, Response response) { - QualityGatesWs.writeQualityGateCondition( - qualityGates.updateCondition( - QualityGatesWs.parseId(request, QualityGatesWsParameters.PARAM_ID), - request.mandatoryParam(QualityGatesWsParameters.PARAM_METRIC), - request.mandatoryParam(QualityGatesWsParameters.PARAM_OPERATOR), - request.param(QualityGatesWsParameters.PARAM_WARNING), - request.param(QualityGatesWsParameters.PARAM_ERROR), - request.paramAsInt(QualityGatesWsParameters.PARAM_PERIOD) - ), response.newJsonWriter() - ).close(); + userSession.checkPermission(QUALITY_GATE_ADMIN); + + DbSession dbSession = dbClient.openSession(false); + try { + writeProtobuf(doHandle(toWsRequest(request), dbSession), request, response); + dbSession.commit(); + } finally { + dbClient.closeSession(dbSession); + } + } + + private UpdateConditionWsResponse doHandle(UpdateConditionRequest request, DbSession dbSession) { + QualityGateConditionDto condition = qualityGateConditionsUpdater.updateCondition(dbSession, request.getConditionId(), request.getMetricKey(), request.getOperator(), + request.getWarning(), request.getError(), request.getPeriod()); + UpdateConditionWsResponse.Builder response = UpdateConditionWsResponse.newBuilder() + .setId(condition.getId()) + .setMetric(condition.getMetricKey()) + .setOp(condition.getOperator()); + String warning = condition.getWarningThreshold(); + if (warning != null) { + response.setWarning(warning); + } + String error = condition.getErrorThreshold(); + if (error != null) { + response.setError(error); + } + Integer period = condition.getPeriod(); + if (period != null) { + response.setPeriod(period); + } + return response.build(); + } + + private static UpdateConditionRequest toWsRequest(Request request) { + return UpdateConditionRequest.builder() + .setConditionId(request.mandatoryParamAsInt(PARAM_ID)) + .setMetricKey(request.mandatoryParam(PARAM_METRIC)) + .setOperator(request.mandatoryParam(PARAM_OPERATOR)) + .setWarning(request.param(PARAM_WARNING)) + .setError(request.param(PARAM_ERROR)) + .setPeriod(request.paramAsInt(PARAM_PERIOD)) + .build(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java index 8bd0c1194bd..dab499a560f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java @@ -23,6 +23,7 @@ package org.sonar.server.qualitygate; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -73,7 +74,6 @@ public class QualityGateConditionsUpdaterTest { @Before public void setUp() throws Exception { qualityGateDto = qualityGateDbTester.insertQualityGate(); - dbClient.metricDao().insert(dbSession, coverageMetricDto); dbSession.commit(); } @@ -82,13 +82,7 @@ public class QualityGateConditionsUpdaterTest { public void create_warning_condition_without_period() { QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "LT", "90", null, null); - assertThat(result.getQualityGateId()).isEqualTo(qualityGateDto.getId()); - assertThat(result.getMetricId()).isEqualTo(coverageMetricDto.getId().longValue()); - assertThat(result.getOperator()).isEqualTo("LT"); - assertThat(result.getWarningThreshold()).isEqualTo("90"); - assertThat(result.getErrorThreshold()).isNull(); - assertThat(result.getPeriod()).isNull(); - assertThat(dbClient.gateConditionDao().selectById(result.getId(), dbSession)).isNotNull(); + verifyCondition(result, coverageMetricDto.getId(), "LT", "90", null, null); } @Test @@ -101,14 +95,7 @@ public class QualityGateConditionsUpdaterTest { QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "LT", null, "80", 1); - assertThat(result.getQualityGateId()).isEqualTo(qualityGateDto.getId()); - assertThat(result.getMetricId()).isEqualTo(metricDto.getId().longValue()); - assertThat(result.getMetricKey()).isEqualTo("new_coverage"); - assertThat(result.getOperator()).isEqualTo("LT"); - assertThat(result.getWarningThreshold()).isNull(); - assertThat(result.getErrorThreshold()).isEqualTo("80"); - assertThat(result.getPeriod()).isEqualTo(1); - assertThat(dbClient.gateConditionDao().selectById(result.getId(), dbSession)).isNotNull(); + verifyCondition(result, metricDto.getId(), "LT", null, "80", 1); } @Test @@ -127,9 +114,9 @@ public class QualityGateConditionsUpdaterTest { @Test public void fail_to_create_condition_when_condition_on_same_metric_and_on_leak_period_already_exist() throws Exception { dbClient.gateConditionDao().insert(new QualityGateConditionDto() - .setQualityGateId(qualityGateDto.getId()) - .setMetricId(coverageMetricDto.getId()) - .setPeriod(1), + .setQualityGateId(qualityGateDto.getId()) + .setMetricId(coverageMetricDto.getId()) + .setPeriod(1), dbSession); expectedException.expect(BadRequestException.class); @@ -185,6 +172,50 @@ public class QualityGateConditionsUpdaterTest { underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "EQ", null, "90", 6); } + @Test + public void update_condition() { + QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "LT", null, "80", null); + + QualityGateConditionDto result = underTest.updateCondition(dbSession, condition.getId(), "coverage", "GT", "60", null, 1); + + verifyCondition(result, coverageMetricDto.getId(), "GT", "60", null, 1); + } + + @Test + public void update_condition_over_leak_period() { + QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1); + + QualityGateConditionDto result = underTest.updateCondition(dbSession, condition.getId(), "coverage", "LT", null, "80", null); + + verifyCondition(result, coverageMetricDto.getId(), "LT", null, "80", null); + } + + @Test + @UseDataProvider("invalid_metrics") + public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) { + MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto() + .setKey(metricKey) + .setValueType(valueType.name()) + .setHidden(hidden)); + QualityGateConditionDto condition = insertCondition(metricDto.getId(), "LT", null, "80", null); + dbSession.commit(); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition."); + underTest.updateCondition(dbSession, condition.getId(), metricDto.getKey(), "GT", "60", null, 1); + } + + @Test + public void fail_to_update_condition_when_condition_on_same_metric_already_exist() throws Exception { + QualityGateConditionDto conditionNotOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, null); + QualityGateConditionDto conditionOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Condition on metric 'Coverage' over leak period already exists."); + // Update condition not on leak period to be on leak period => will fail as this condition already exist + underTest.updateCondition(dbSession, conditionNotOnLeakPeriod.getId(), coverageMetricDto.getKey(), "GT", "80", null, 1); + } + @DataProvider public static Object[][] invalid_metrics() { return new Object[][] { @@ -195,4 +226,34 @@ public class QualityGateConditionsUpdaterTest { }; } + private QualityGateConditionDto insertCondition(long metricId, String operator, @Nullable String warning, @Nullable String error, + @Nullable Integer period) { + QualityGateConditionDto qualityGateConditionDto = new QualityGateConditionDto().setQualityGateId(qualityGateDto.getId()) + .setMetricId(metricId) + .setOperator(operator) + .setWarningThreshold(warning) + .setErrorThreshold(error) + .setPeriod(period); + dbClient.gateConditionDao().insert(qualityGateConditionDto, dbSession); + dbSession.commit(); + return qualityGateConditionDto; + } + + private void verifyCondition(QualityGateConditionDto dto, int metricId, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) { + QualityGateConditionDto reloaded = dbClient.gateConditionDao().selectById(dto.getId(), dbSession); + assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGateDto.getId()); + assertThat(reloaded.getMetricId()).isEqualTo(metricId); + assertThat(reloaded.getOperator()).isEqualTo(operator); + assertThat(reloaded.getWarningThreshold()).isEqualTo(warning); + assertThat(reloaded.getErrorThreshold()).isEqualTo(error); + assertThat(reloaded.getPeriod()).isEqualTo(period); + + assertThat(dto.getQualityGateId()).isEqualTo(qualityGateDto.getId()); + assertThat(dto.getMetricId()).isEqualTo(metricId); + assertThat(dto.getOperator()).isEqualTo(operator); + assertThat(dto.getWarningThreshold()).isEqualTo(warning); + assertThat(dto.getErrorThreshold()).isEqualTo(error); + assertThat(dto.getPeriod()).isEqualTo(period); + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java index 8a12dd1f046..8f10230fe31 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java @@ -57,8 +57,6 @@ import org.sonar.server.tester.MockUserSession; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.user.UserSession; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; @@ -260,37 +258,6 @@ public class QualityGatesTest { assertThat(underTest.getDefault()).isNull(); } - @Test - public void should_update_condition() { - String metricKey = "new_coverage"; - String operator = "LT"; - String errorThreshold = "80"; - addMetric(metricKey, "New Coverage"); - - QualityGateConditionDto condition = insertQualityGateConditionDto(newCondition(metricKey, METRIC_ID)); - when(conditionDao.selectForQualityGate(QUALITY_GATE_ID)).thenReturn(singletonList(condition)); - - assertThat(underTest.updateCondition(condition.getId(), metricKey, operator, null, errorThreshold, 1)).isEqualTo(condition); - verify(conditionDao).update(condition); - } - - @Test - public void fail_to_update_condition_when_condition_on_same_metric_already_exist() throws Exception { - String metricKey = "coverage"; - addMetric(metricKey, "Coverage"); - when(dao.selectById(QUALITY_GATE_ID)).thenReturn(new QualityGateDto().setId(QUALITY_GATE_ID)); - - QualityGateConditionDto conditionNotOnLeakPeriod = insertQualityGateConditionDto(newCondition(metricKey, METRIC_ID)).setPeriod(0); - QualityGateConditionDto conditionOnLeakPeriod = insertQualityGateConditionDto(newCondition(metricKey, METRIC_ID)).setPeriod(1); - when(conditionDao.selectForQualityGate(QUALITY_GATE_ID)).thenReturn(asList(conditionNotOnLeakPeriod, conditionOnLeakPeriod)); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Condition on metric 'Coverage' over leak period already exists."); - - // Update condition not on leak period to be on leak period => will fail as this condition already exist - underTest.updateCondition(conditionNotOnLeakPeriod.getId(), metricKey, "LT", null, "60", 1); - } - @Test public void should_list_conditions() { long qGateId = QUALITY_GATE_ID; diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java index c5e1430bc25..bfdbee6307e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java @@ -72,7 +72,7 @@ public class QualityGatesWsTest { new ListAction(qGates), new ShowAction(qGates), new SearchAction(projectFinder), new CreateAction(null, null, null), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates), new SetAsDefaultAction(qGates), new UnsetDefaultAction(qGates), - new CreateConditionAction(null, null, null), new UpdateConditionAction(qGates), new DeleteConditionAction(qGates), + new CreateConditionAction(null, null, null), new UpdateConditionAction(null, null, null), new DeleteConditionAction(qGates), selectAction, new DeselectAction(qGates, mock(DbClient.class), mock(ComponentFinder.class)), new AppAction(null, null))); } @@ -305,26 +305,6 @@ public class QualityGatesWsTest { tester.newGetRequest("api/qualitygates", "show").setParam("id", "12345").setParam("name", "Polop").execute(); } - @Test - public void update_condition_nominal() throws Exception { - long condId = 12345L; - String metricKey = "coverage"; - String operator = "LT"; - String warningThreshold = "80"; - String errorThreshold = "75"; - when(qGates.updateCondition(condId, metricKey, operator, warningThreshold, errorThreshold, null)) - .thenReturn(new QualityGateConditionDto().setId(condId).setMetricId(10).setMetricKey(metricKey) - .setOperator(operator).setWarningThreshold(warningThreshold).setErrorThreshold(errorThreshold)); - tester.newPostRequest("api/qualitygates", "update_condition") - .setParam("id", Long.toString(condId)) - .setParam("metric", metricKey) - .setParam("op", operator) - .setParam("warning", warningThreshold) - .setParam("error", errorThreshold) - .execute() - .assertJson("{\"id\":12345,\"metric\":\"coverage\",\"op\":\"LT\",\"warning\":\"80\",\"error\":\"75\"}"); - } - @Test public void delete_condition_nominal() throws Exception { long condId = 12345L; diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java new file mode 100644 index 00000000000..9c8acdff094 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java @@ -0,0 +1,208 @@ +/* + * 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.qualitygate.ws; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.qualitygate.QualityGateConditionDto; +import org.sonar.db.qualitygate.QualityGateDbTester; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.qualitygate.QualityGateConditionsUpdater; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.MediaTypes; +import org.sonarqube.ws.WsQualityGates.CreateConditionWsResponse; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; +import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; +import static org.sonar.db.metric.MetricTesting.newMetricDto; +import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.PERCENT; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ERROR; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ID; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_METRIC; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_OPERATOR; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PERIOD; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_WARNING; + +public class UpdateConditionActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + DbClient dbClient = db.getDbClient(); + DbSession dbSession = db.getSession(); + QualityGateDbTester qualityGateDbTester = new QualityGateDbTester(db); + + UpdateConditionAction underTest = new UpdateConditionAction(userSession, dbClient, new QualityGateConditionsUpdater(dbClient)); + + QualityGateDto qualityGateDto; + QualityGateConditionDto conditionDto; + + MetricDto coverageMetricDto = newMetricDto() + .setKey("coverage") + .setShortName("Coverage") + .setValueType(PERCENT.name()) + .setHidden(false); + + WsActionTester ws = new WsActionTester(underTest); + + @Before + public void setUp() throws Exception { + MetricDto metricDto = dbClient.metricDao().insert(dbSession, coverageMetricDto); + qualityGateDto = qualityGateDbTester.insertQualityGate(); + conditionDto = new QualityGateConditionDto().setQualityGateId(qualityGateDto.getId()) + .setMetricId(metricDto.getId()) + .setOperator("GT") + .setWarningThreshold(null) + .setErrorThreshold("80") + .setPeriod(1); + dbClient.gateConditionDao().insert(conditionDto, dbSession); + dbSession.commit(); + } + + @Test + public void update_warning_condition() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(conditionDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, null); + + assertCondition(response, "LT", "90", null, null); + } + + @Test + public void update_error_condition() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(conditionDto.getId(), coverageMetricDto.getKey(), "LT", null, "90", null); + + assertCondition(response, "LT", null, "90", null); + } + + @Test + public void update_condition_over_leak_period() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(conditionDto.getId(), coverageMetricDto.getKey(), "LT", null, "90", 1); + + assertCondition(response, "LT", null, "90", 1); + } + + @Test + public void fail_when_not_quality_gate_admin() throws Exception { + setUserAsNotQualityGateAdmin(); + + expectedException.expect(ForbiddenException.class); + executeRequest(conditionDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, null); + } + + @Test + public void test_ws_definition() { + WebService.Action action = ws.getDef(); + assertThat(action).isNotNull(); + assertThat(action.isInternal()).isFalse(); + assertThat(action.isPost()).isTrue(); + assertThat(action.responseExampleAsString()).isNull(); + assertThat(action.params()).hasSize(6); + } + + private void assertCondition(CreateConditionWsResponse response, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) { + List conditionDtoList = new ArrayList<>(dbClient.gateConditionDao().selectForQualityGate(qualityGateDto.getId(), dbSession)); + assertThat(conditionDtoList).hasSize(1); + QualityGateConditionDto qualityGateConditionDto = conditionDtoList.get(0); + assertThat(qualityGateConditionDto.getQualityGateId()).isEqualTo(qualityGateDto.getId()); + assertThat(qualityGateConditionDto.getMetricId()).isEqualTo(coverageMetricDto.getId().longValue()); + assertThat(qualityGateConditionDto.getOperator()).isEqualTo(operator); + assertThat(qualityGateConditionDto.getWarningThreshold()).isEqualTo(warning); + assertThat(qualityGateConditionDto.getErrorThreshold()).isEqualTo(error); + assertThat(qualityGateConditionDto.getPeriod()).isEqualTo(period); + + assertThat(response.getId()).isEqualTo(qualityGateConditionDto.getId()); + assertThat(response.getMetric()).isEqualTo(coverageMetricDto.getKey()); + assertThat(response.getOp()).isEqualTo(operator); + if (warning != null) { + assertThat(response.getWarning()).isEqualTo(warning); + } else { + assertThat(response.hasWarning()).isFalse(); + } + if (error != null) { + assertThat(response.getError()).isEqualTo(error); + } else { + assertThat(response.hasError()).isFalse(); + } + if (period != null) { + assertThat(response.getPeriod()).isEqualTo(period); + } else { + assertThat(response.hasPeriod()).isFalse(); + } + } + + private CreateConditionWsResponse executeRequest(long conditionId, String metricKey, String operator, @Nullable String warning, @Nullable String error, + @Nullable Integer period) { + TestRequest request = ws.newRequest() + .setMediaType(MediaTypes.PROTOBUF) + .setParam(PARAM_ID, Long.toString(conditionId)) + .setParam(PARAM_METRIC, metricKey) + .setParam(PARAM_OPERATOR, operator); + if (warning != null) { + request.setParam(PARAM_WARNING, warning); + } + if (error != null) { + request.setParam(PARAM_ERROR, error); + } + if (period != null) { + request.setParam(PARAM_PERIOD, Integer.toString(period)); + } + try { + return CreateConditionWsResponse.parseFrom(request.execute().getInputStream()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private void setUserAsQualityGateAdmin() { + userSession.login("project-admin").setGlobalPermissions(QUALITY_GATE_ADMIN); + } + + private void setUserAsNotQualityGateAdmin() { + userSession.login("not-admin").setGlobalPermissions(SCAN_EXECUTION); + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java index a4b09d6a357..d77534878de 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java @@ -22,6 +22,7 @@ package org.sonarqube.ws.client.qualitygate; import org.sonarqube.ws.WsQualityGates.CreateConditionWsResponse; import org.sonarqube.ws.WsQualityGates.CreateWsResponse; import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse; +import org.sonarqube.ws.WsQualityGates.UpdateConditionWsResponse; import org.sonarqube.ws.client.BaseService; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.PostRequest; @@ -31,10 +32,12 @@ import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTIO import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_CREATE_CONDITION; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_PROJECT_STATUS; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_SELECT; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_UPDATE_CONDITION; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.CONTROLLER_QUALITY_GATES; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ERROR; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_METRIC; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_OPERATOR; @@ -80,4 +83,15 @@ public class QualityGatesService extends BaseService { .setParam(PARAM_PERIOD, request.getPeriod()), CreateConditionWsResponse.parser()); } + + public UpdateConditionWsResponse updateCondition(UpdateConditionRequest request) { + return call(new PostRequest(path(ACTION_UPDATE_CONDITION)) + .setParam(PARAM_ID, request.getConditionId()) + .setParam(PARAM_METRIC, request.getMetricKey()) + .setParam(PARAM_OPERATOR, request.getOperator()) + .setParam(PARAM_WARNING, request.getWarning()) + .setParam(PARAM_ERROR, request.getError()) + .setParam(PARAM_PERIOD, request.getPeriod()), + UpdateConditionWsResponse.parser()); + } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java index 1f9fe030d8e..d984571e7c0 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java @@ -29,6 +29,7 @@ public class QualityGatesWsParameters { public static final String ACTION_SELECT = "select"; public static final String ACTION_CREATE = "create"; public static final String ACTION_CREATE_CONDITION = "create_condition"; + public static final String ACTION_UPDATE_CONDITION = "update_condition"; public static final String PARAM_ANALYSIS_ID = "analysisId"; public static final String PARAM_PROJECT_ID = "projectId"; diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequest.java new file mode 100644 index 00000000000..13abf90feda --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequest.java @@ -0,0 +1,125 @@ +/* + * 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.sonarqube.ws.client.qualitygate; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; + +public class UpdateConditionRequest { + + private final long conditionId; + private final String metricKey; + private final String operator; + private final String warning; + private final String error; + private final Integer period; + + public UpdateConditionRequest(Builder builder) { + this.conditionId = builder.conditionId; + this.metricKey = builder.metricKey; + this.operator = builder.operator; + this.warning = builder.warning; + this.error = builder.error; + this.period = builder.period; + } + + public long getConditionId() { + return conditionId; + } + + public String getMetricKey() { + return metricKey; + } + + public String getOperator() { + return operator; + } + + @CheckForNull + public String getWarning() { + return warning; + } + + @CheckForNull + public String getError() { + return error; + } + + @CheckForNull + public Integer getPeriod() { + return period; + } + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private long conditionId; + private String metricKey; + private String operator; + private String warning; + private String error; + private Integer period; + + private Builder() { + // enforce factory method use + } + + public Builder setConditionId(long conditionId) { + this.conditionId = conditionId; + return this; + } + + public Builder setMetricKey(String metricKey) { + this.metricKey = metricKey; + return this; + } + + public Builder setOperator(String operator) { + this.operator = operator; + return this; + } + + public Builder setWarning(@Nullable String warning) { + this.warning = warning; + return this; + } + + public Builder setError(@Nullable String error) { + this.error = error; + return this; + } + + public Builder setPeriod(@Nullable Integer period) { + this.period = period; + return this; + } + + public UpdateConditionRequest build() { + checkArgument(conditionId > 0, "Condition id is mandatory and must not be empty"); + checkArgument(!isNullOrEmpty(metricKey), "Metric key is mandatory and must not be empty"); + checkArgument(!isNullOrEmpty(operator), "Operator is mandatory and must not be empty"); + return new UpdateConditionRequest(this); + } + } +} diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto index 125e5667d8d..ff1fc870376 100644 --- a/sonar-ws/src/main/protobuf/ws-qualitygates.proto +++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto @@ -107,5 +107,15 @@ message CreateConditionWsResponse { optional int32 period = 6; } +// POST api/qualitygates/update_condition +message UpdateConditionWsResponse { + optional int64 id = 1; + optional string metric = 2; + optional string op = 3; + optional string warning = 4; + optional string error = 5; + optional int32 period = 6; +} + diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java index 386587a536b..66d6a62fff4 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.sonarqube.ws.WsQualityGates.CreateConditionWsResponse; import org.sonarqube.ws.WsQualityGates.CreateWsResponse; import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse; +import org.sonarqube.ws.WsQualityGates.UpdateConditionWsResponse; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.ServiceTester; @@ -35,6 +36,7 @@ import static org.mockito.Mockito.mock; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ERROR; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_METRIC; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_OPERATOR; @@ -123,4 +125,29 @@ public class QualityGatesServiceTest { .hasParam(PARAM_PERIOD, 1) .andNoOtherParam(); } + + @Test + public void update_condition() { + underTest.updateCondition(UpdateConditionRequest.builder() + .setConditionId(10) + .setMetricKey("metric") + .setOperator("LT") + .setWarning("warning") + .setError("error") + .setPeriod(1) + .build()); + + PostRequest request = serviceTester.getPostRequest(); + + assertThat(serviceTester.getPostParser()).isSameAs(UpdateConditionWsResponse.parser()); + serviceTester.assertThat(request) + .hasPath("update_condition") + .hasParam(PARAM_ID, 10) + .hasParam(PARAM_METRIC, "metric") + .hasParam(PARAM_OPERATOR, "LT") + .hasParam(PARAM_WARNING, "warning") + .hasParam(PARAM_ERROR, "error") + .hasParam(PARAM_PERIOD, 1) + .andNoOtherParam(); + } } diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequestTest.java new file mode 100644 index 00000000000..3864615cdd8 --- /dev/null +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/UpdateConditionRequestTest.java @@ -0,0 +1,91 @@ +/* + * 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.sonarqube.ws.client.qualitygate; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UpdateConditionRequestTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + UpdateConditionRequest.Builder underTest = UpdateConditionRequest.builder(); + + @Test + public void create_condition_request() { + UpdateConditionRequest result = underTest + .setConditionId(10) + .setMetricKey("metric") + .setOperator("LT") + .setWarning("warning") + .setError("error") + .setPeriod(1) + .build(); + + assertThat(result.getConditionId()).isEqualTo(10); + assertThat(result.getMetricKey()).isEqualTo("metric"); + assertThat(result.getOperator()).isEqualTo("LT"); + assertThat(result.getWarning()).isEqualTo("warning"); + assertThat(result.getError()).isEqualTo("error"); + assertThat(result.getPeriod()).isEqualTo(1); + } + + @Test + public void fail_when_no_quality_gate() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Condition id is mandatory and must not be empty"); + + underTest + .setMetricKey("metric") + .setOperator("LT") + .setWarning("warning") + .build(); + } + + @Test + public void fail_when_no_metric() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Metric key is mandatory and must not be empty"); + + underTest + .setConditionId(10) + .setOperator("LT") + .setWarning("warning") + .build(); + } + + @Test + public void fail_when_no_operator() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Operator is mandatory and must not be empty"); + + underTest + .setConditionId(10) + .setMetricKey("metric") + .setWarning("warning") + .build(); + } + +} -- 2.39.5