aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-09-20 16:40:20 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-09-22 14:10:31 +0200
commite34e860366092c1546718919e7852b10b64ab341 (patch)
tree259d30e31fdb27a4bac1f70d60c1f9d43107e906
parent7b348e0ba5ce74367fc15d7aef4b163a4ecb1048 (diff)
downloadsonarqube-e34e860366092c1546718919e7852b10b64ab341.tar.gz
sonarqube-e34e860366092c1546718919e7852b10b64ab341.zip
SONAR-8117 Extract creation of quality gate condition into QualityGateConditionsUpdater
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java148
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java46
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java48
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/AppAction.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java94
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java34
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java198
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java10
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java212
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java65
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java200
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java24
-rw-r--r--sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java7
-rw-r--r--sonar-db/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java49
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequest.java126
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java18
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java1
-rw-r--r--sonar-ws/src/main/protobuf/ws-qualitygates.proto10
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/CreateConditionRequestTest.java91
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java31
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();
+ }
}