diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-20 16:40:20 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-22 14:10:31 +0200 |
commit | e34e860366092c1546718919e7852b10b64ab341 (patch) | |
tree | 259d30e31fdb27a4bac1f70d60c1f9d43107e906 | |
parent | 7b348e0ba5ce74367fc15d7aef4b163a4ecb1048 (diff) | |
download | sonarqube-e34e860366092c1546718919e7852b10b64ab341.tar.gz sonarqube-e34e860366092c1546718919e7852b10b64ab341.zip |
SONAR-8117 Extract creation of quality gate condition into QualityGateConditionsUpdater
25 files changed, 1122 insertions, 330 deletions
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 new file mode 100644 index 00000000000..f5a988c1ce5 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java @@ -0,0 +1,148 @@ +/* + * 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; + +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.ObjectUtils; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.qualitygate.QualityGateConditionDto; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.server.exceptions.BadRequestException; +import org.sonar.server.exceptions.Errors; +import org.sonar.server.exceptions.NotFoundException; + +import static java.lang.String.format; +import static org.sonar.db.qualitygate.QualityGateConditionDto.isOperatorAllowed; + +public class QualityGateConditionsUpdater { + + private final DbClient dbClient; + + public QualityGateConditionsUpdater(DbClient dbClient) { + this.dbClient = dbClient; + } + + public QualityGateConditionDto createCondition(DbSession dbSession, long qGateId, String metricKey, String operator, + @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { + getNonNullQgate(dbSession, qGateId); + MetricDto metric = getNonNullMetric(dbSession, metricKey); + validateCondition(metric, operator, warningThreshold, errorThreshold, period); + checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(dbSession, qGateId, null), metric, period); + + QualityGateConditionDto newCondition = new QualityGateConditionDto().setQualityGateId(qGateId) + .setMetricId(metric.getId()).setMetricKey(metric.getKey()) + .setOperator(operator) + .setWarningThreshold(warningThreshold) + .setErrorThreshold(errorThreshold) + .setPeriod(period); + dbClient.gateConditionDao().insert(newCondition, dbSession); + return newCondition; + } + + private QualityGateDto getNonNullQgate(DbSession dbSession, long id) { + QualityGateDto qGate = dbClient.qualityGateDao().selectById(dbSession, id); + if (qGate == null) { + throw new NotFoundException(format("There is no quality gate with id=%s", id)); + } + return qGate; + } + + private MetricDto getNonNullMetric(DbSession dbSession, String metricKey) { + MetricDto metric = dbClient.metricDao().selectByKey(dbSession, metricKey); + if (metric == null) { + throw new NotFoundException(format("There is no metric with key=%s", metricKey)); + } + return metric; + } + + private Collection<QualityGateConditionDto> getConditions(DbSession dbSession, long qGateId, @Nullable Long conditionId) { + Collection<QualityGateConditionDto> conditions = dbClient.gateConditionDao().selectForQualityGate(qGateId, dbSession); + if (conditionId == null) { + return conditions; + } + return dbClient.gateConditionDao().selectForQualityGate(qGateId, dbSession).stream() + .filter(condition -> condition.getId() != conditionId) + .collect(Collectors.toList()); + } + + private static void validateCondition(MetricDto 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 validateMetric(MetricDto metric, Errors errors) { + errors.check(isAlertable(metric), format("Metric '%s' cannot be used to define a condition.", metric.getKey())); + } + + private static boolean isAlertable(MetricDto metric) { + return isAvailableForInit(metric) && BooleanUtils.isFalse(metric.isHidden()); + } + + private static boolean isAvailableForInit(MetricDto metric) { + return !metric.isDataType() && !CoreMetrics.ALERT_STATUS_KEY.equals(metric.getKey()) && !Objects.equals(Metric.ValueType.RATING.name(), metric.getValueType()); + } + + private static void checkOperator(MetricDto metric, String operator, Errors errors) { + Metric.ValueType valueType = Metric.ValueType.valueOf(metric.getValueType()); + errors.check(isOperatorAllowed(operator, valueType), format("Operator %s is not allowed for metric type %s.", operator, metric.getValueType())); + } + + 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 checkPeriod(MetricDto 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 checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(Collection<QualityGateConditionDto> conditions, MetricDto metric, @Nullable final Integer period) { + if (conditions.isEmpty()) { + return; + } + + boolean conditionExists = conditions.stream().anyMatch(c -> c.getMetricId() == metric.getId() && ObjectUtils.equals(c.getPeriod(), period)); + if (conditionExists) { + String errorMessage = period == null + ? format("Condition on metric '%s' already exists.", metric.getShortName()) + : format("Condition on metric '%s' over leak period already exists.", metric.getShortName()); + throw new BadRequestException(errorMessage); + } + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java index 89989a4f61d..c2a225eec0e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java @@ -46,6 +46,7 @@ public class QualityGateModule extends Module { add( QualityGates.class, QualityGateUpdater.class, + QualityGateConditionsUpdater.class, QgateProjectFinder.class, // WS QualityGatesWs.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java index a501c0d00a7..5eac4df76c9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java @@ -22,6 +22,7 @@ package org.sonar.server.qualitygate; import javax.annotation.Nullable; import org.sonar.db.DbClient; +import org.sonar.db.DbSession; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.Errors; @@ -38,10 +39,10 @@ public class QualityGateUpdater { this.dbClient = dbClient; } - public QualityGateDto create(String name) { + public QualityGateDto create(DbSession dbSession, String name) { validateQualityGate(null, name); QualityGateDto newQualityGate = new QualityGateDto().setName(name); - dbClient.qualityGateDao().insert(newQualityGate); + dbClient.qualityGateDao().insert(dbSession, newQualityGate); return newQualityGate; } 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 47edf399e2a..5dfa118f475 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 @@ -140,13 +140,23 @@ public class QualityGates { } } - public void setDefault(@Nullable Long idToUseAsDefault) { + public void setDefault(DbSession dbSession, @Nullable Long idToUseAsDefault) { checkPermission(); if (idToUseAsDefault == null) { - propertiesDao.deleteGlobalProperty(SONAR_QUALITYGATE_PROPERTY); + propertiesDao.deleteGlobalProperty(SONAR_QUALITYGATE_PROPERTY, dbSession); } else { - QualityGateDto newDefault = getNonNullQgate(idToUseAsDefault); - propertiesDao.saveProperty(new PropertyDto().setKey(SONAR_QUALITYGATE_PROPERTY).setValue(newDefault.getId().toString())); + QualityGateDto newDefault = getNonNullQgate(dbSession, idToUseAsDefault); + propertiesDao.saveProperty(dbSession, new PropertyDto().setKey(SONAR_QUALITYGATE_PROPERTY).setValue(newDefault.getId().toString())); + } + } + + public void setDefault(@Nullable Long idToUseAsDefault) { + DbSession dbSession = dbClient.openSession(false); + try { + setDefault(dbSession, idToUseAsDefault); + dbSession.commit(); + } finally { + dbClient.closeSession(dbSession); } } @@ -160,23 +170,6 @@ public class QualityGates { } } - public QualityGateConditionDto createCondition(long qGateId, String metricKey, String operator, - @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { - checkPermission(); - getNonNullQgate(qGateId); - Metric metric = getNonNullMetric(metricKey); - validateCondition(metric, operator, warningThreshold, errorThreshold, period); - checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(qGateId, null), metric, period); - QualityGateConditionDto newCondition = new QualityGateConditionDto().setQualityGateId(qGateId) - .setMetricId(metric.getId()).setMetricKey(metric.getKey()) - .setOperator(operator) - .setWarningThreshold(warningThreshold) - .setErrorThreshold(errorThreshold) - .setPeriod(period); - conditionDao.insert(newCondition); - return newCondition; - } - public QualityGateConditionDto updateCondition(long condId, String metricKey, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) { checkPermission(); @@ -312,7 +305,16 @@ public class QualityGates { } private QualityGateDto getNonNullQgate(long id) { - QualityGateDto qGate = dao.selectById(id); + DbSession dbSession = dbClient.openSession(false); + try { + return getNonNullQgate(dbSession, id); + } finally { + dbClient.closeSession(dbSession); + } + } + + private QualityGateDto getNonNullQgate(DbSession dbSession, long id) { + QualityGateDto qGate = dao.selectById(dbSession, id); if (qGate == null) { throw new NotFoundException("There is no quality gate with id=" + id); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java index 90bfef1ff30..77eda12c413 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java @@ -20,6 +20,8 @@ package org.sonar.server.qualitygate; import org.picocontainer.Startable; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; import org.sonar.db.loadedtemplate.LoadedTemplateDao; import org.sonar.db.loadedtemplate.LoadedTemplateDto; import org.sonar.db.qualitygate.QualityGateDto; @@ -40,21 +42,32 @@ public class RegisterQualityGates implements Startable { private static final String DEBT_ON_NEW_CODE_ERROR_THRESHOLD = "5"; private static final String NEW_COVERAGE_ERROR_THRESHOLD = "80"; - private final QualityGates qualityGates; + private final DbClient dbClient; private final QualityGateUpdater qualityGateUpdater; + private final QualityGateConditionsUpdater qualityGateConditionsUpdater; private final LoadedTemplateDao loadedTemplateDao; + private final QualityGates qualityGates; - public RegisterQualityGates(QualityGates qualityGates, QualityGateUpdater qualityGateUpdater, LoadedTemplateDao loadedTemplateDao) { - this.qualityGates = qualityGates; + public RegisterQualityGates(DbClient dbClient, QualityGateUpdater qualityGateUpdater, QualityGateConditionsUpdater qualityGateConditionsUpdater, + LoadedTemplateDao loadedTemplateDao, QualityGates qualityGates) { + this.dbClient = dbClient; this.qualityGateUpdater = qualityGateUpdater; + this.qualityGateConditionsUpdater = qualityGateConditionsUpdater; this.loadedTemplateDao = loadedTemplateDao; + this.qualityGates = qualityGates; } @Override public void start() { - if (shouldRegisterBuiltinQualityGate()) { - createBuiltinQualityGate(); - registerBuiltinQualityGate(); + DbSession dbSession = dbClient.openSession(false); + try { + if (shouldRegisterBuiltinQualityGate(dbSession)) { + createBuiltinQualityGate(dbSession); + registerBuiltinQualityGate(dbSession); + dbSession.commit(); + } + } finally { + dbClient.closeSession(dbSession); } } @@ -63,20 +76,21 @@ public class RegisterQualityGates implements Startable { // do nothing } - private boolean shouldRegisterBuiltinQualityGate() { - return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.QUALITY_GATE_TYPE, BUILTIN_QUALITY_GATE) == 0; + private boolean shouldRegisterBuiltinQualityGate(DbSession dbSession) { + return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.QUALITY_GATE_TYPE, BUILTIN_QUALITY_GATE, dbSession) == 0; } - private void createBuiltinQualityGate() { - QualityGateDto builtin = qualityGateUpdater.create(BUILTIN_QUALITY_GATE); - qualityGates.createCondition(builtin.getId(), NEW_VULNERABILITIES_KEY, OPERATOR_GREATER_THAN, null, NEW_VULNERABILITIES_ERROR_THRESHOLD, LEAK_PERIOD); - qualityGates.createCondition(builtin.getId(), NEW_BUGS_KEY, OPERATOR_GREATER_THAN, null, NEW_BUGS_ERROR_THRESHOLD, LEAK_PERIOD); - qualityGates.createCondition(builtin.getId(), NEW_SQALE_DEBT_RATIO_KEY, OPERATOR_GREATER_THAN, null, DEBT_ON_NEW_CODE_ERROR_THRESHOLD, LEAK_PERIOD); - qualityGates.createCondition(builtin.getId(), NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, NEW_COVERAGE_ERROR_THRESHOLD, LEAK_PERIOD); - qualityGates.setDefault(builtin.getId()); + private void createBuiltinQualityGate(DbSession dbSession) { + QualityGateDto builtin = qualityGateUpdater.create(dbSession, BUILTIN_QUALITY_GATE); + qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(), NEW_VULNERABILITIES_KEY, OPERATOR_GREATER_THAN, null, NEW_VULNERABILITIES_ERROR_THRESHOLD, + LEAK_PERIOD); + qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(), NEW_BUGS_KEY, OPERATOR_GREATER_THAN, null, NEW_BUGS_ERROR_THRESHOLD, LEAK_PERIOD); + qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(), NEW_SQALE_DEBT_RATIO_KEY, OPERATOR_GREATER_THAN, null, DEBT_ON_NEW_CODE_ERROR_THRESHOLD, LEAK_PERIOD); + qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(), NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, NEW_COVERAGE_ERROR_THRESHOLD, LEAK_PERIOD); + qualityGates.setDefault(dbSession, builtin.getId()); } - private void registerBuiltinQualityGate() { - loadedTemplateDao.insert(new LoadedTemplateDto(BUILTIN_QUALITY_GATE, LoadedTemplateDto.QUALITY_GATE_TYPE)); + private void registerBuiltinQualityGate(DbSession dbSession) { + loadedTemplateDao.insert(new LoadedTemplateDto(BUILTIN_QUALITY_GATE, LoadedTemplateDto.QUALITY_GATE_TYPE), dbSession); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/AppAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/AppAction.java index e72c78d87a8..c0d5900ce54 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/AppAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/AppAction.java @@ -31,8 +31,6 @@ import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsQualityGates.AppWsResponse.Metric; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.Metric.ValueType.DATA; -import static org.sonar.api.measures.Metric.ValueType.DISTRIB; import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.WsQualityGates.AppWsResponse; @@ -86,15 +84,11 @@ public class AppAction implements QualityGatesWsAction { DbSession dbSession = dbClient.openSession(false); try { return dbClient.metricDao().selectEnabled(dbSession).stream() - .filter(metric -> !isDataType(metric) && !ALERT_STATUS_KEY.equals(metric.getKey())) + .filter(metric -> !metric.isDataType() && !ALERT_STATUS_KEY.equals(metric.getKey())) .collect(Collectors.toList()); } finally { dbClient.closeSession(dbSession); } } - private static boolean isDataType(MetricDto metric) { - return DATA.name().equals(metric.getValueType()) || DISTRIB.name().equals(metric.getValueType()); - } - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java index de6cb73768e..669e05174b8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java @@ -23,6 +23,8 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.core.permission.GlobalPermissions; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.qualitygate.QualityGateUpdater; import org.sonar.server.user.UserSession; @@ -34,10 +36,12 @@ import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM public class CreateAction implements QualityGatesWsAction { + private final DbClient dbClient; private final UserSession userSession; private final QualityGateUpdater qualityGateUpdater; - public CreateAction(UserSession userSession, QualityGateUpdater qualityGateUpdater) { + public CreateAction(DbClient dbClient, UserSession userSession, QualityGateUpdater qualityGateUpdater) { + this.dbClient = dbClient; this.userSession = userSession; this.qualityGateUpdater = qualityGateUpdater; } @@ -59,11 +63,17 @@ public class CreateAction implements QualityGatesWsAction { @Override public void handle(Request request, Response response) { userSession.checkPermission(GlobalPermissions.QUALITY_GATE_ADMIN); - QualityGateDto newQualityGate = qualityGateUpdater.create(request.mandatoryParam(PARAM_NAME)); - CreateWsResponse.Builder createWsResponse = CreateWsResponse.newBuilder() - .setId(newQualityGate.getId()) - .setName(newQualityGate.getName()); - writeProtobuf(createWsResponse.build(), request, response); + DbSession dbSession = dbClient.openSession(false); + try { + QualityGateDto newQualityGate = qualityGateUpdater.create(dbSession, request.mandatoryParam(PARAM_NAME)); + CreateWsResponse.Builder createWsResponse = CreateWsResponse.newBuilder() + .setId(newQualityGate.getId()) + .setName(newQualityGate.getName()); + writeProtobuf(createWsResponse.build(), request, response); + dbSession.commit(); + } finally { + dbClient.closeSession(dbSession); + } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java index fbaf599cea6..b11e23edef2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java @@ -22,46 +22,104 @@ 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.CreateConditionWsResponse; +import org.sonarqube.ws.client.qualitygate.CreateConditionRequest; + +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_CREATE_CONDITION; +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_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 CreateConditionAction implements QualityGatesWsAction { - private final QualityGates qualityGates; + private final UserSession userSession; + private final DbClient dbClient; + private final QualityGateConditionsUpdater qualityGateConditionsUpdater; - public CreateConditionAction(QualityGates qualityGates) { - this.qualityGates = qualityGates; + public CreateConditionAction(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("create_condition") + WebService.NewAction createCondition = controller.createAction(ACTION_CREATE_CONDITION) .setDescription("Add a new condition to a quality gate. Require Administer Quality Gates permission") .setPost(true) .setSince("4.3") .setHandler(this); createCondition - .createParam(QualityGatesWsParameters.PARAM_GATE_ID) + .createParam(PARAM_GATE_ID) .setDescription("ID of the quality gate") .setRequired(true) .setExampleValue("1"); - QualityGatesWs.addConditionParams(createCondition); + addConditionParams(createCondition); } @Override public void handle(Request request, Response response) { - QualityGatesWs.writeQualityGateCondition( - qualityGates.createCondition( - QualityGatesWs.parseId(request, QualityGatesWsParameters.PARAM_GATE_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 CreateConditionWsResponse doHandle(CreateConditionRequest request, DbSession dbSession){ + QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, + request.getQualityGateId(), + request.getMetricKey(), + request.getOperator(), + request.getWarning(), + request.getError(), + request.getPeriod()); + + CreateConditionWsResponse.Builder response = CreateConditionWsResponse.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 CreateConditionRequest toWsRequest(Request request) { + return CreateConditionRequest.builder() + .setQualityGateId(request.mandatoryParamAsInt(PARAM_GATE_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/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java index fc8c989501c..be591fab166 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java @@ -25,9 +25,15 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.exceptions.BadRequestException; -import org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.CONTROLLER_QUALITY_GATES; +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_NAME; +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 QualityGatesWs implements WebService { private final QualityGatesWsAction[] actions; @@ -51,12 +57,12 @@ public class QualityGatesWs implements WebService { static void addConditionParams(NewAction action) { action - .createParam(QualityGatesWsParameters.PARAM_METRIC) + .createParam(PARAM_METRIC) .setDescription("Condition metric") .setRequired(true) .setExampleValue("blocker_violations"); - action.createParam(QualityGatesWsParameters.PARAM_OPERATOR) + action.createParam(PARAM_OPERATOR) .setDescription("Condition operator:<br/>" + "<ul>" + "<li>EQ = equals</li>" + @@ -67,15 +73,15 @@ public class QualityGatesWs implements WebService { .setExampleValue(QualityGateConditionDto.OPERATOR_EQUALS) .setPossibleValues(QualityGateConditionDto.ALL_OPERATORS); - action.createParam(QualityGatesWsParameters.PARAM_PERIOD) + action.createParam(PARAM_PERIOD) .setDescription("Condition period. If not set, the absolute value is considered.") .setPossibleValues("1"); - action.createParam(QualityGatesWsParameters.PARAM_WARNING) + action.createParam(PARAM_WARNING) .setDescription("Condition warning threshold") .setExampleValue("5"); - action.createParam(QualityGatesWsParameters.PARAM_ERROR) + action.createParam(PARAM_ERROR) .setDescription("Condition error threshold") .setExampleValue("10"); } @@ -90,24 +96,24 @@ public class QualityGatesWs implements WebService { static JsonWriter writeQualityGate(QualityGateDto qualityGate, JsonWriter writer) { return writer.beginObject() - .prop(QualityGatesWsParameters.PARAM_ID, qualityGate.getId()) - .prop(QualityGatesWsParameters.PARAM_NAME, qualityGate.getName()) + .prop(PARAM_ID, qualityGate.getId()) + .prop(PARAM_NAME, qualityGate.getName()) .endObject(); } static JsonWriter writeQualityGateCondition(QualityGateConditionDto condition, JsonWriter writer) { writer.beginObject() - .prop(QualityGatesWsParameters.PARAM_ID, condition.getId()) - .prop(QualityGatesWsParameters.PARAM_METRIC, condition.getMetricKey()) - .prop(QualityGatesWsParameters.PARAM_OPERATOR, condition.getOperator()); + .prop(PARAM_ID, condition.getId()) + .prop(PARAM_METRIC, condition.getMetricKey()) + .prop(PARAM_OPERATOR, condition.getOperator()); if (condition.getWarningThreshold() != null) { - writer.prop(QualityGatesWsParameters.PARAM_WARNING, condition.getWarningThreshold()); + writer.prop(PARAM_WARNING, condition.getWarningThreshold()); } if (condition.getErrorThreshold() != null) { - writer.prop(QualityGatesWsParameters.PARAM_ERROR, condition.getErrorThreshold()); + writer.prop(PARAM_ERROR, condition.getErrorThreshold()); } if (condition.getPeriod() != null) { - writer.prop(QualityGatesWsParameters.PARAM_PERIOD, condition.getPeriod()); + writer.prop(PARAM_PERIOD, condition.getPeriod()); } writer.endObject(); return writer; 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 new file mode 100644 index 00000000000..8bd0c1194bd --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java @@ -0,0 +1,198 @@ +/* + * 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; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.sonar.api.measures.Metric; +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.BadRequestException; +import org.sonar.server.exceptions.NotFoundException; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.api.measures.Metric.ValueType.DATA; +import static org.sonar.api.measures.Metric.ValueType.INT; +import static org.sonar.api.measures.Metric.ValueType.RATING; +import static org.sonar.db.metric.MetricTesting.newMetricDto; +import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.PERCENT; + +@RunWith(DataProviderRunner.class) +public class QualityGateConditionsUpdaterTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + DbClient dbClient = db.getDbClient(); + DbSession dbSession = db.getSession(); + QualityGateDbTester qualityGateDbTester = new QualityGateDbTester(db); + + QualityGateDto qualityGateDto; + MetricDto coverageMetricDto = newMetricDto() + .setKey("coverage") + .setShortName("Coverage") + .setValueType(PERCENT.name()) + .setHidden(false); + + QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(dbClient); + + @Before + public void setUp() throws Exception { + qualityGateDto = qualityGateDbTester.insertQualityGate(); + + dbClient.metricDao().insert(dbSession, coverageMetricDto); + dbSession.commit(); + } + + @Test + 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(); + } + + @Test + public void create_error_condition_with_period() { + MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto() + .setKey("new_coverage") + .setValueType(INT.name()) + .setHidden(false)); + dbSession.commit(); + + 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(); + } + + @Test + public void fail_to_create_condition_when_condition_on_same_metric_already_exist() throws Exception { + dbClient.gateConditionDao().insert(new QualityGateConditionDto() + .setQualityGateId(qualityGateDto.getId()) + .setMetricId(coverageMetricDto.getId()) + .setPeriod(null), + dbSession); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Condition on metric 'Coverage' already exists."); + underTest.createCondition(dbSession, qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, null); + } + + @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), + dbSession); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Condition on metric 'Coverage' over leak period already exists."); + underTest.createCondition(dbSession, qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, 1); + } + + @Test + public void fail_to_create_condition_on_missing_metric() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("There is no metric with key=new_coverage"); + underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "LT", null, "80", 2); + } + + @Test + @UseDataProvider("invalid_metrics") + public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) { + dbClient.metricDao().insert(dbSession, newMetricDto() + .setKey(metricKey) + .setValueType(valueType.name()) + .setHidden(hidden)); + dbSession.commit(); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition."); + underTest.createCondition(dbSession, qualityGateDto.getId(), metricKey, "EQ", null, "80", null); + } + + @Test + public void fail_to_create_condition_on_not_allowed_operator() { + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT."); + underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "UNKNOWN", null, "80", 2); + } + + @Test + public void fail_to_create_condition_on_missing_period() { + dbClient.metricDao().insert(dbSession, newMetricDto() + .setKey("new_coverage") + .setValueType(INT.name()) + .setHidden(false)); + dbSession.commit(); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("A period must be selected for differential metrics."); + underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "EQ", null, "90", null); + } + + @Test + public void fail_to_create_condition_on_invalid_period() { + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("The only valid quality gate period is 1, the leak period."); + underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "EQ", null, "90", 6); + } + + @DataProvider + public static Object[][] invalid_metrics() { + return new Object[][] { + {ALERT_STATUS_KEY, INT, false}, + {"data_metric", DATA, false}, + {"hidden", INT, true}, + {"rating_metric", RATING, false}, + }; + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java index 4f8c1d8342a..bb8ad41e8b7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java @@ -30,6 +30,6 @@ public class QualityGateModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QualityGateModule().configure(container); - assertThat(container.size()).isEqualTo(21 + 2); + assertThat(container.size()).isEqualTo(22 + 2); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java index 0f95091a800..cd01ce3ccd9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; 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.qualitygate.QualityGateDto; import org.sonar.server.exceptions.BadRequestException; @@ -43,17 +44,18 @@ public class QualityGateUpdaterTest { public DbTester db = DbTester.create(System2.INSTANCE); DbClient dbClient = db.getDbClient(); + DbSession dbSession= db.getSession(); QualityGateUpdater underTest = new QualityGateUpdater(dbClient); @Test public void create_quality_gate() throws Exception { - QualityGateDto result = underTest.create(QGATE_NAME); + QualityGateDto result = underTest.create(dbSession, QGATE_NAME); assertThat(result).isNotNull(); assertThat(result.getName()).isEqualTo(QGATE_NAME); assertThat(result.getCreatedAt()).isNotNull(); - QualityGateDto reloaded = dbClient.qualityGateDao().selectByName(QGATE_NAME); + QualityGateDto reloaded = dbClient.qualityGateDao().selectByName(dbSession, QGATE_NAME); assertThat(reloaded).isNotNull(); } @@ -61,7 +63,7 @@ public class QualityGateUpdaterTest { public void fail_to_create_when_name_is_empty() throws Exception { expectedException.expect(BadRequestException.class); expectedException.expectMessage(format("errors.cant_be_empty", "Name")); - underTest.create(""); + underTest.create(dbSession, ""); } @Test @@ -70,6 +72,6 @@ public class QualityGateUpdaterTest { expectedException.expect(BadRequestException.class); expectedException.expectMessage("errors.is_already_used"); - underTest.create(QGATE_NAME); + underTest.create(dbSession, QGATE_NAME); } } 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 e67c7bf2698..8a12dd1f046 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 @@ -62,7 +62,6 @@ 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; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -126,9 +125,9 @@ public class QualityGatesTest { long id = QUALITY_GATE_ID; final String name = "Golden"; QualityGateDto existing = new QualityGateDto().setId(id).setName(name); - when(dao.selectById(id)).thenReturn(existing); + when(dao.selectById(dbSession, id)).thenReturn(existing); assertThat(underTest.get(id)).isEqualTo(existing); - verify(dao).selectById(id); + verify(dao).selectById(dbSession, id); } @Test @@ -151,10 +150,10 @@ public class QualityGatesTest { long id = QUALITY_GATE_ID; String name = "SG-1"; QualityGateDto existing = new QualityGateDto().setId(id).setName("Golden"); - when(dao.selectById(id)).thenReturn(existing); + when(dao.selectById(dbSession, id)).thenReturn(existing); QualityGateDto sg1 = underTest.rename(id, name); assertThat(sg1.getName()).isEqualTo(name); - verify(dao).selectById(id); + verify(dao).selectById(dbSession, id); verify(dao).selectByName(name); verify(dao).update(sg1); } @@ -164,10 +163,10 @@ public class QualityGatesTest { long id = QUALITY_GATE_ID; String name = "SG-1"; QualityGateDto existing = new QualityGateDto().setId(id).setName(name); - when(dao.selectById(id)).thenReturn(existing); + when(dao.selectById(dbSession, id)).thenReturn(existing); QualityGateDto sg1 = underTest.rename(id, name); assertThat(sg1.getName()).isEqualTo(name); - verify(dao).selectById(id); + verify(dao).selectById(dbSession, id); verify(dao).selectByName(name); verify(dao).update(sg1); } @@ -182,7 +181,7 @@ public class QualityGatesTest { long id = QUALITY_GATE_ID; String name = "SG-1"; QualityGateDto existing = new QualityGateDto().setId(id).setName("Golden"); - when(dao.selectById(id)).thenReturn(existing); + when(dao.selectById(dbSession, id)).thenReturn(existing); when(dao.selectByName(name)).thenReturn(new QualityGateDto().setId(666L).setName(name)); underTest.rename(id, name); } @@ -191,13 +190,13 @@ public class QualityGatesTest { public void should_select_default_qgate() { long defaultId = QUALITY_GATE_ID; String defaultName = "Default Name"; - when(dao.selectById(defaultId)).thenReturn(new QualityGateDto().setId(defaultId).setName(defaultName)); + when(dao.selectById(dbSession, defaultId)).thenReturn(new QualityGateDto().setId(defaultId).setName(defaultName)); underTest.setDefault(defaultId); - verify(dao).selectById(defaultId); + verify(dao).selectById(dbSession, defaultId); ArgumentCaptor<PropertyDto> propertyCaptor = ArgumentCaptor.forClass(PropertyDto.class); - verify(propertiesDao).saveProperty(propertyCaptor.capture()); + verify(propertiesDao).saveProperty(any(DbSession.class), propertyCaptor.capture()); assertThat(propertyCaptor.getValue().getKey()).isEqualTo("sonar.qualitygate"); assertThat(propertyCaptor.getValue().getValue()).isEqualTo("42"); @@ -208,10 +207,10 @@ public class QualityGatesTest { long idToDelete = QUALITY_GATE_ID; String name = "To Delete"; QualityGateDto toDelete = new QualityGateDto().setId(idToDelete).setName(name); - when(dao.selectById(idToDelete)).thenReturn(toDelete); + when(dao.selectById(dbSession, idToDelete)).thenReturn(toDelete); when(dbClient.openSession(false)).thenReturn(dbSession); underTest.delete(idToDelete); - verify(dao).selectById(idToDelete); + verify(dao).selectById(dbSession, idToDelete); verify(propertiesDao).deleteProjectProperties("sonar.qualitygate", "42", dbSession); verify(dao).delete(toDelete, dbSession); } @@ -221,11 +220,11 @@ public class QualityGatesTest { long idToDelete = QUALITY_GATE_ID; String name = "To Delete"; QualityGateDto toDelete = new QualityGateDto().setId(idToDelete).setName(name); - when(dao.selectById(idToDelete)).thenReturn(toDelete); + when(dao.selectById(dbSession, idToDelete)).thenReturn(toDelete); when(propertiesDao.selectGlobalProperty("sonar.qualitygate")).thenReturn(new PropertyDto().setValue("666")); when(dbClient.openSession(false)).thenReturn(dbSession); underTest.delete(idToDelete); - verify(dao).selectById(idToDelete); + verify(dao).selectById(dbSession, idToDelete); verify(propertiesDao).deleteProjectProperties("sonar.qualitygate", "42", dbSession); verify(dao).delete(toDelete, dbSession); } @@ -235,11 +234,11 @@ public class QualityGatesTest { long idToDelete = QUALITY_GATE_ID; String name = "To Delete"; QualityGateDto toDelete = new QualityGateDto().setId(idToDelete).setName(name); - when(dao.selectById(idToDelete)).thenReturn(toDelete); + when(dao.selectById(dbSession, idToDelete)).thenReturn(toDelete); when(propertiesDao.selectGlobalProperty("sonar.qualitygate")).thenReturn(new PropertyDto().setValue("42")); when(dbClient.openSession(false)).thenReturn(dbSession); underTest.delete(idToDelete); - verify(dao).selectById(idToDelete); + verify(dao).selectById(dbSession, idToDelete); verify(propertiesDao).deleteGlobalProperty("sonar.qualitygate", dbSession); verify(propertiesDao).deleteProjectProperties("sonar.qualitygate", "42", dbSession); verify(dao).delete(toDelete, dbSession); @@ -262,167 +261,6 @@ public class QualityGatesTest { } @Test - public void should_create_warning_condition_without_period() { - long qGateId = QUALITY_GATE_ID; - String metricKey = "coverage"; - String operator = "LT"; - String warningThreshold = "90"; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - int metricId = 10; - Metric coverage = Mockito.spy(CoreMetrics.COVERAGE); - when(coverage.getId()).thenReturn(metricId); - when(metricFinder.findByKey(metricKey)).thenReturn(coverage); - - QualityGateConditionDto newCondition = underTest.createCondition(qGateId, metricKey, operator, warningThreshold, null, null); - assertThat(newCondition.getQualityGateId()).isEqualTo(qGateId); - assertThat(newCondition.getMetricId()).isEqualTo((long) metricId); - assertThat(newCondition.getOperator()).isEqualTo(operator); - assertThat(newCondition.getWarningThreshold()).isEqualTo(warningThreshold); - assertThat(newCondition.getErrorThreshold()).isNull(); - assertThat(newCondition.getPeriod()).isNull(); - verify(conditionDao).insert(newCondition); - } - - @Test - public void should_create_error_condition_with_period() { - long qGateId = QUALITY_GATE_ID; - String metricKey = "new_coverage"; - String operator = "LT"; - String errorThreshold = "80"; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - int metricId = 10; - Metric newCoverage = Mockito.spy(CoreMetrics.NEW_COVERAGE); - when(newCoverage.getId()).thenReturn(metricId); - when(metricFinder.findByKey(metricKey)).thenReturn(newCoverage); - int period = 1; - - QualityGateConditionDto newCondition = underTest.createCondition(qGateId, metricKey, operator, null, errorThreshold, period); - assertThat(newCondition.getQualityGateId()).isEqualTo(qGateId); - assertThat(newCondition.getMetricId()).isEqualTo((long) metricId); - assertThat(newCondition.getMetricKey()).isEqualTo(metricKey); - assertThat(newCondition.getOperator()).isEqualTo(operator); - assertThat(newCondition.getWarningThreshold()).isNull(); - assertThat(newCondition.getErrorThreshold()).isEqualTo(errorThreshold); - assertThat(newCondition.getPeriod()).isEqualTo(period); - verify(conditionDao).insert(newCondition); - } - - @Test(expected = NotFoundException.class) - public void should_fail_create_condition_on_missing_metric() { - long qGateId = QUALITY_GATE_ID; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "new_coverage", "LT", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_alert_metric() { - long qGateId = QUALITY_GATE_ID; - when(metricFinder.findByKey(anyString())).thenReturn(CoreMetrics.ALERT_STATUS); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "EQ", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_non_data_metric() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getType()).thenReturn(ValueType.DATA); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "LT", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_hidden_metric() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.isHidden()).thenReturn(true); - when(metric.getType()).thenReturn(ValueType.INT); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "LT", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_rating_metric() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getType()).thenReturn(ValueType.RATING); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "LT", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_unallowed_operator() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getType()).thenReturn(ValueType.BOOL); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "LT", null, "80", 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_missing_thresholds() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getType()).thenReturn(ValueType.BOOL); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "EQ", null, null, 2); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_missing_period() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getKey()).thenReturn("new_coverage"); - when(metric.getType()).thenReturn(ValueType.BOOL); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "EQ", null, "90", null); - } - - @Test(expected = BadRequestException.class) - public void should_fail_create_condition_on_invalid_period() { - long qGateId = QUALITY_GATE_ID; - final Metric metric = mock(Metric.class); - when(metric.getKey()).thenReturn("new_coverage"); - when(metric.getType()).thenReturn(ValueType.BOOL); - when(metricFinder.findByKey(anyString())).thenReturn(metric); - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); - underTest.createCondition(qGateId, "alert_status", "EQ", null, "90", 6); - } - - @Test - public void fail_to_create_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)); - when(conditionDao.selectForQualityGate(QUALITY_GATE_ID)).thenReturn( - singletonList(new QualityGateConditionDto().setMetricKey(metricKey).setMetricId(METRIC_ID))); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Condition on metric 'Coverage' already exists."); - underTest.createCondition(QUALITY_GATE_ID, metricKey, "LT", "90", null, null); - } - - @Test - public void fail_to_create_condition_when_condition_on_same_metric_and_period_already_exist() throws Exception { - String metricKey = "new_coverage"; - addMetric(metricKey, "New Coverage"); - when(dao.selectById(QUALITY_GATE_ID)).thenReturn(new QualityGateDto().setId(QUALITY_GATE_ID)); - - when(conditionDao.selectForQualityGate(QUALITY_GATE_ID)).thenReturn( - singletonList(new QualityGateConditionDto().setMetricKey(metricKey).setMetricId(METRIC_ID).setPeriod(1))); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Condition on metric 'New Coverage' over leak period already exists."); - underTest.createCondition(QUALITY_GATE_ID, metricKey, "LT", "90", null, 1); - } - - @Test public void should_update_condition() { String metricKey = "new_coverage"; String operator = "LT"; @@ -511,9 +349,9 @@ public class QualityGatesTest { public void should_associate_project() { Long qGateId = QUALITY_GATE_ID; Long projectId = 24L; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); + when(dao.selectById(dbSession, qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); underTest.associateProject(qGateId, projectId); - verify(dao).selectById(qGateId); + verify(dao).selectById(dbSession, qGateId); ArgumentCaptor<PropertyDto> propertyCaptor = ArgumentCaptor.forClass(PropertyDto.class); verify(propertiesDao).saveProperty(propertyCaptor.capture()); PropertyDto property = propertyCaptor.getValue(); @@ -528,9 +366,9 @@ public class QualityGatesTest { Long qGateId = QUALITY_GATE_ID; Long projectId = 24L; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); + when(dao.selectById(dbSession, qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); underTest.associateProject(qGateId, projectId); - verify(dao).selectById(qGateId); + verify(dao).selectById(dbSession, qGateId); ArgumentCaptor<PropertyDto> propertyCaptor = ArgumentCaptor.forClass(PropertyDto.class); verify(propertiesDao).saveProperty(propertyCaptor.capture()); PropertyDto property = propertyCaptor.getValue(); @@ -543,9 +381,9 @@ public class QualityGatesTest { public void should_dissociate_project() { Long qGateId = QUALITY_GATE_ID; Long projectId = 24L; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); + when(dao.selectById(dbSession, qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); underTest.dissociateProject(qGateId, projectId); - verify(dao).selectById(qGateId); + verify(dao).selectById(dbSession, qGateId); verify(propertiesDao).deleteProjectProperty("sonar.qualitygate", projectId); } @@ -555,9 +393,9 @@ public class QualityGatesTest { Long qGateId = QUALITY_GATE_ID; Long projectId = 24L; - when(dao.selectById(qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); + when(dao.selectById(dbSession, qGateId)).thenReturn(new QualityGateDto().setId(qGateId)); underTest.dissociateProject(qGateId, projectId); - verify(dao).selectById(qGateId); + verify(dao).selectById(dbSession, qGateId); verify(propertiesDao).deleteProjectProperty("sonar.qualitygate", projectId); } @@ -572,7 +410,7 @@ public class QualityGatesTest { QualityGateConditionDto cond2 = new QualityGateConditionDto().setMetricId(metric2Id); Collection<QualityGateConditionDto> conditions = ImmutableList.of(cond1, cond2); - when(dao.selectById(sourceId)).thenReturn(new QualityGateDto().setId(sourceId).setName("SG-1")); + when(dao.selectById(dbSession, sourceId)).thenReturn(new QualityGateDto().setId(sourceId).setName("SG-1")); Mockito.doAnswer(invocation -> { ((QualityGateDto) invocation.getArguments()[1]).setId(destId); return null; diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java index 929c0818b70..1d1910bc0dd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java @@ -21,26 +21,29 @@ package org.sonar.server.qualitygate; import org.junit.Rule; import org.junit.Test; -import org.mockito.ArgumentCaptor; 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.loadedtemplate.LoadedTemplateDao; import org.sonar.db.loadedtemplate.LoadedTemplateDto; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.qualitygate.QualityGateConditionDto; +import org.sonar.db.qualitygate.QualityGateDto; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.anyInt; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; import static org.sonar.api.measures.CoreMetrics.NEW_BUGS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_SQALE_DEBT_RATIO_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES_KEY; +import static org.sonar.api.measures.Metric.ValueType.INT; +import static org.sonar.api.measures.Metric.ValueType.PERCENT; +import static org.sonar.db.metric.MetricTesting.newMetricDto; import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN; import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN; @@ -50,47 +53,51 @@ public class RegisterQualityGatesTest { public DbTester db = DbTester.create(System2.INSTANCE); DbClient dbClient = db.getDbClient(); + DbSession dbSession = db.getSession(); QualityGates qualityGates = mock(QualityGates.class); - LoadedTemplateDao templateDao = mock(LoadedTemplateDao.class); - RegisterQualityGates task = new RegisterQualityGates(qualityGates, new QualityGateUpdater(dbClient), templateDao); + RegisterQualityGates task = new RegisterQualityGates(dbClient, + new QualityGateUpdater(dbClient), + new QualityGateConditionsUpdater(dbClient), + dbClient.loadedTemplateDao(), + qualityGates); @Test public void register_default_gate() { - String templateType = "QUALITY_GATE"; - String templateName = "SonarQube way"; - when(templateDao.countByTypeAndKey(templateType, templateName)).thenReturn(0); + MetricDto newBugs = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_BUGS_KEY).setValueType(INT.name()).setHidden(false)); + MetricDto newVulnerabilities = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_VULNERABILITIES_KEY).setValueType(INT.name()).setHidden(false)); + MetricDto newSqaleDebtRatio = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SQALE_DEBT_RATIO_KEY).setValueType(PERCENT.name()).setHidden(false)); + MetricDto newCoverage = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_COVERAGE_KEY).setValueType(PERCENT.name()).setHidden(false)); + dbSession.commit(); task.start(); - verify(templateDao).countByTypeAndKey(templateType, templateName); - verify(qualityGates).createCondition(anyInt(), eq(NEW_BUGS_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("0"), eq(1)); - verify(qualityGates).createCondition(anyInt(), eq(NEW_VULNERABILITIES_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("0"), eq(1)); - verify(qualityGates).createCondition(anyInt(), eq(NEW_SQALE_DEBT_RATIO_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("5"), eq(1)); - verify(qualityGates).createCondition(anyInt(), eq(NEW_COVERAGE_KEY), eq(OPERATOR_LESS_THAN), eq((String) null), eq("80"), eq(1)); - verify(qualityGates).setDefault(anyLong()); - - assertThat(dbClient.qualityGateDao().selectByName(templateName)).isNotNull(); - - ArgumentCaptor<LoadedTemplateDto> templateArg = ArgumentCaptor.forClass(LoadedTemplateDto.class); - verify(templateDao).insert(templateArg.capture()); - LoadedTemplateDto template = templateArg.getValue(); - assertThat(template.getType()).isEqualTo(templateType); - assertThat(template.getKey()).isEqualTo(templateName); + assertThat(dbClient.loadedTemplateDao().countByTypeAndKey("QUALITY_GATE", "SonarQube way", dbSession)).isEqualTo(1); + QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectByName(dbSession, "SonarQube way"); + assertThat(qualityGateDto).isNotNull(); + assertThat(dbClient.gateConditionDao().selectForQualityGate(qualityGateDto.getId())) + .extracting(QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator, QualityGateConditionDto::getWarningThreshold, + QualityGateConditionDto::getErrorThreshold, QualityGateConditionDto::getPeriod) + .containsOnly( + tuple(newBugs.getId().longValue(), OPERATOR_GREATER_THAN, null, "0", 1), + tuple(newVulnerabilities.getId().longValue(), OPERATOR_GREATER_THAN, null, "0", 1), + tuple(newSqaleDebtRatio.getId().longValue(), OPERATOR_GREATER_THAN, null, "5", 1), + tuple(newCoverage.getId().longValue(), OPERATOR_LESS_THAN, null, "80", 1)); + verify(qualityGates).setDefault(any(DbSession.class), anyLong()); task.stop(); } @Test - public void does_not_register_default_gate_if_already_present() { + public void does_not_register_default_gate_if_already_executed() { String templateType = "QUALITY_GATE"; String templateName = "SonarQube way"; - when(templateDao.countByTypeAndKey(templateType, templateName)).thenReturn(1); + dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(templateName, templateType), dbSession); + dbSession.commit(); task.start(); - verify(templateDao).countByTypeAndKey(templateType, templateName); + assertThat(dbClient.qualityGateDao().selectAll(dbSession)).isEmpty(); verifyZeroInteractions(qualityGates); - verifyNoMoreInteractions(templateDao); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java index f2b23b3f243..8c235df8c7d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java @@ -56,7 +56,7 @@ public class CreateActionTest { DbClient dbClient = db.getDbClient(); DbSession dbSession = db.getSession(); - CreateAction underTest = new CreateAction(userSession, new QualityGateUpdater(dbClient)); + CreateAction underTest = new CreateAction(dbClient, userSession, new QualityGateUpdater(dbClient)); WsActionTester ws = new WsActionTester(underTest); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java new file mode 100644 index 00000000000..09fd810d9b9 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java @@ -0,0 +1,200 @@ +/* + * 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_GATE_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 CreateConditionActionTest { + + @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); + + CreateConditionAction underTest = new CreateConditionAction(userSession, dbClient, new QualityGateConditionsUpdater(dbClient)); + + QualityGateDto qualityGateDto; + + MetricDto coverageMetricDto = newMetricDto() + .setKey("coverage") + .setShortName("Coverage") + .setValueType(PERCENT.name()) + .setHidden(false); + + WsActionTester ws = new WsActionTester(underTest); + + @Before + public void setUp() throws Exception { + qualityGateDto = qualityGateDbTester.insertQualityGate(); + dbClient.metricDao().insert(dbSession, coverageMetricDto); + dbSession.commit(); + } + + @Test + public void create_warning_condition() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, null); + + assertCondition(response, "LT", "90", null, null); + } + + @Test + public void create_error_condition() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", null, "90", null); + + assertCondition(response, "LT", null, "90", null); + } + + @Test + public void create_condition_over_leak_period() throws Exception { + setUserAsQualityGateAdmin(); + + CreateConditionWsResponse response = executeRequest(qualityGateDto.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(qualityGateDto.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<QualityGateConditionDto> 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 qualityProfileId, String metricKey, String operator, @Nullable String warning, @Nullable String error, + @Nullable Integer period) { + TestRequest request = ws.newRequest() + .setMediaType(MediaTypes.PROTOBUF) + .setParam(PARAM_GATE_ID, Long.toString(qualityProfileId)) + .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/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 14bcfc5b73f..c5e1430bc25 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 @@ -70,9 +70,9 @@ public class QualityGatesWsTest { tester = new WsTester(new QualityGatesWs( new ListAction(qGates), new ShowAction(qGates), new SearchAction(projectFinder), - new CreateAction(null, null), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates), + new CreateAction(null, null, null), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates), new SetAsDefaultAction(qGates), new UnsetDefaultAction(qGates), - new CreateConditionAction(qGates), new UpdateConditionAction(qGates), new DeleteConditionAction(qGates), + new CreateConditionAction(null, null, null), new UpdateConditionAction(qGates), new DeleteConditionAction(qGates), selectAction, new DeselectAction(qGates, mock(DbClient.class), mock(ComponentFinder.class)), new AppAction(null, null))); } @@ -306,26 +306,6 @@ public class QualityGatesWsTest { } @Test - public void create_condition_nominal() throws Exception { - long qGateId = 42L; - String metricKey = "coverage"; - String operator = "LT"; - String warningThreshold = "80"; - String errorThreshold = "75"; - when(qGates.createCondition(qGateId, metricKey, operator, warningThreshold, errorThreshold, null)) - .thenReturn(new QualityGateConditionDto().setId(12345L).setQualityGateId(qGateId).setMetricId(10).setMetricKey(metricKey) - .setOperator(operator).setWarningThreshold(warningThreshold).setErrorThreshold(errorThreshold)); - tester.newPostRequest("api/qualitygates", "create_condition") - .setParam("gateId", Long.toString(qGateId)) - .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 update_condition_nominal() throws Exception { long condId = 12345L; String metricKey = "coverage"; diff --git a/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java b/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java index 5a3ebb8fe17..7eafcc266c8 100644 --- a/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java +++ b/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java @@ -22,6 +22,9 @@ package org.sonar.db.metric; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import static org.sonar.api.measures.Metric.ValueType.DATA; +import static org.sonar.api.measures.Metric.ValueType.DISTRIB; + public class MetricDto { private Integer id; @@ -208,4 +211,8 @@ public class MetricDto { return this; } + public boolean isDataType() { + return DATA.name().equals(valueType) || DISTRIB.name().equals(valueType); + } + } diff --git a/sonar-db/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java b/sonar-db/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java new file mode 100644 index 00000000000..5f61358b9a7 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java @@ -0,0 +1,49 @@ +/* + * 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.db.qualitygate; + +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; + +public class QualityGateDbTester { + + private final DbTester db; + private final DbClient dbClient; + private final DbSession dbSession; + + public QualityGateDbTester(DbTester db) { + this.db = db; + this.dbClient = db.getDbClient(); + this.dbSession = db.getSession(); + } + + public QualityGateDto insertQualityGate() { + return insertQualityGate(randomAlphanumeric(30)); + } + + public QualityGateDto insertQualityGate(String name) { + QualityGateDto updatedUser = dbClient.qualityGateDao().insert(dbSession, new QualityGateDto().setName(name)); + db.commit(); + return updatedUser; + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequest.java new file mode 100644 index 00000000000..5c4334420ef --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequest.java @@ -0,0 +1,126 @@ +/* + * 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 CreateConditionRequest { + + private final long qualityGateId; + private final String metricKey; + private final String operator; + private final String warning; + private final String error; + private final Integer period; + + public CreateConditionRequest(Builder builder) { + this.qualityGateId = builder.qualityGateId; + this.metricKey = builder.metricKey; + this.operator = builder.operator; + this.warning = builder.warning; + this.error = builder.error; + this.period = builder.period; + } + + public long getQualityGateId() { + return qualityGateId; + } + + 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 qualityGateId; + private String metricKey; + private String operator; + private String warning; + private String error; + private Integer period; + + private Builder() { + // enforce factory method use + } + + public Builder setQualityGateId(long qualityGateId) { + this.qualityGateId = qualityGateId; + 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 CreateConditionRequest build() { + checkArgument(qualityGateId > 0, "Quality gate 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 CreateConditionRequest(this); + } + } +} 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 93d76029483..a4b09d6a357 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 @@ -19,6 +19,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.client.BaseService; @@ -27,14 +28,20 @@ import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsConnector; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_CREATE; +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.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_METRIC; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; +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_PROJECT_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_WARNING; public class QualityGatesService extends BaseService { @@ -62,4 +69,15 @@ public class QualityGatesService extends BaseService { .setParam(PARAM_NAME, name), CreateWsResponse.parser()); } + + public CreateConditionWsResponse createCondition(CreateConditionRequest request) { + return call(new PostRequest(path(ACTION_CREATE_CONDITION)) + .setParam(PARAM_GATE_ID, request.getQualityGateId()) + .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()), + CreateConditionWsResponse.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 722fa0b1b41..1f9fe030d8e 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 @@ -28,6 +28,7 @@ public class QualityGatesWsParameters { public static final String ACTION_GET_BY_PROJECT = "get_by_project"; 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 PARAM_ANALYSIS_ID = "analysisId"; public static final String PARAM_PROJECT_ID = "projectId"; diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto index bbdbe48e581..125e5667d8d 100644 --- a/sonar-ws/src/main/protobuf/ws-qualitygates.proto +++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto @@ -97,5 +97,15 @@ message CreateWsResponse { optional string name = 2; } +// POST api/qualitygates/create_condition +message CreateConditionWsResponse { + 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/CreateConditionRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequestTest.java new file mode 100644 index 00000000000..14f86265904 --- /dev/null +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequestTest.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 CreateConditionRequestTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + CreateConditionRequest.Builder underTest = CreateConditionRequest.builder(); + + @Test + public void create_condition_request() { + CreateConditionRequest result = underTest + .setQualityGateId(10) + .setMetricKey("metric") + .setOperator("LT") + .setWarning("warning") + .setError("error") + .setPeriod(1) + .build(); + + assertThat(result.getQualityGateId()).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("Quality gate 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 + .setQualityGateId(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 + .setQualityGateId(10) + .setMetricKey("metric") + .setWarning("warning") + .build(); + } + +} 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 ec963ef9f5c..386587a536b 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 @@ -22,6 +22,7 @@ package org.sonarqube.ws.client.qualitygate; import org.junit.Rule; 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.client.GetRequest; @@ -32,10 +33,15 @@ import org.sonarqube.ws.client.WsConnector; import static org.assertj.core.api.Assertions.assertThat; 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_METRIC; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; +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_PROJECT_ID; import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; +import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_WARNING; public class QualityGatesServiceTest { private static final String PROJECT_ID_VALUE = "195"; @@ -92,4 +98,29 @@ public class QualityGatesServiceTest { .hasParam(PARAM_NAME, "Default") .andNoOtherParam(); } + + @Test + public void create_condition() { + underTest.createCondition(CreateConditionRequest.builder() + .setQualityGateId(10) + .setMetricKey("metric") + .setOperator("LT") + .setWarning("warning") + .setError("error") + .setPeriod(1) + .build()); + + PostRequest request = serviceTester.getPostRequest(); + + assertThat(serviceTester.getPostParser()).isSameAs(CreateConditionWsResponse.parser()); + serviceTester.assertThat(request) + .hasPath("create_condition") + .hasParam(PARAM_GATE_ID, 10) + .hasParam(PARAM_METRIC, "metric") + .hasParam(PARAM_OPERATOR, "LT") + .hasParam(PARAM_WARNING, "warning") + .hasParam(PARAM_ERROR, "error") + .hasParam(PARAM_PERIOD, 1) + .andNoOtherParam(); + } } |