@@ -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); | |||
} | |||
} | |||
} |
@@ -46,6 +46,7 @@ public class QualityGateModule extends Module { | |||
add( | |||
QualityGates.class, | |||
QualityGateUpdater.class, | |||
QualityGateConditionsUpdater.class, | |||
QgateProjectFinder.class, | |||
// WS | |||
QualityGatesWs.class, |
@@ -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; | |||
} | |||
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; |
@@ -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}, | |||
}; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
@@ -261,167 +260,6 @@ public class QualityGatesTest { | |||
assertThat(underTest.getDefault()).isNull(); | |||
} | |||
@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"; | |||
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
@@ -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); | |||
} | |||
} |
@@ -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))); | |||
} | |||
@@ -305,26 +305,6 @@ public class QualityGatesWsTest { | |||
tester.newGetRequest("api/qualitygates", "show").setParam("id", "12345").setParam("name", "Polop").execute(); | |||
} | |||
@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; |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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"; |
@@ -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; | |||
} | |||
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |