@@ -45,6 +45,7 @@ public class QualityGateModule extends Module { | |||
protected void configureModule() { | |||
add( | |||
QualityGates.class, | |||
QualityGateUpdater.class, | |||
QgateProjectFinder.class, | |||
// WS | |||
QualityGatesWs.class, |
@@ -0,0 +1,65 @@ | |||
/* | |||
* 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 javax.annotation.Nullable; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.Errors; | |||
import org.sonar.server.exceptions.Message; | |||
import org.sonar.server.util.Validation; | |||
import static com.google.common.base.Strings.isNullOrEmpty; | |||
public class QualityGateUpdater { | |||
private final DbClient dbClient; | |||
public QualityGateUpdater(DbClient dbClient) { | |||
this.dbClient = dbClient; | |||
} | |||
public QualityGateDto create(String name) { | |||
validateQualityGate(null, name); | |||
QualityGateDto newQualityGate = new QualityGateDto().setName(name); | |||
dbClient.qualityGateDao().insert(newQualityGate); | |||
return newQualityGate; | |||
} | |||
private void validateQualityGate(@Nullable Long qGateId, @Nullable String name) { | |||
Errors errors = new Errors(); | |||
if (isNullOrEmpty(name)) { | |||
errors.add(Message.of(Validation.CANT_BE_EMPTY_MESSAGE, "Name")); | |||
} else { | |||
checkQualityGateDoesNotAlreadyExist(qGateId, name, errors); | |||
} | |||
if (!errors.isEmpty()) { | |||
throw new BadRequestException(errors); | |||
} | |||
} | |||
private void checkQualityGateDoesNotAlreadyExist(@Nullable Long qGateId, String name, Errors errors) { | |||
QualityGateDto existingQgate = dbClient.qualityGateDao().selectByName(name); | |||
boolean isModifyingCurrentQgate = qGateId != null && existingQgate != null && existingQgate.getId().equals(qGateId); | |||
errors.check(isModifyingCurrentQgate || existingQgate == null, Validation.IS_ALREADY_USED_MESSAGE, "Name"); | |||
} | |||
} |
@@ -57,7 +57,8 @@ import org.sonar.server.util.Validation; | |||
import static java.lang.String.format; | |||
/** | |||
* @since 4.3 | |||
* Methods from this class should be moved to {@link QualityGateUpdater} and to new classes QualityGateFinder / QualityGateConditionsUpdater / etc. | |||
* in order to have classes with clearer responsibilities and more easily testable (without having to use too much mocks) | |||
*/ | |||
public class QualityGates { | |||
@@ -81,14 +82,6 @@ public class QualityGates { | |||
this.userSession = userSession; | |||
} | |||
public QualityGateDto create(String name) { | |||
checkPermission(); | |||
validateQualityGate(null, name); | |||
QualityGateDto newQualityGate = new QualityGateDto().setName(name); | |||
dao.insert(newQualityGate); | |||
return newQualityGate; | |||
} | |||
public QualityGateDto get(Long qGateId) { | |||
return getNonNullQgate(qGateId); | |||
} |
@@ -41,10 +41,12 @@ public class RegisterQualityGates implements Startable { | |||
private static final String NEW_COVERAGE_ERROR_THRESHOLD = "80"; | |||
private final QualityGates qualityGates; | |||
private final QualityGateUpdater qualityGateUpdater; | |||
private final LoadedTemplateDao loadedTemplateDao; | |||
public RegisterQualityGates(QualityGates qualityGates, LoadedTemplateDao loadedTemplateDao) { | |||
public RegisterQualityGates(QualityGates qualityGates, QualityGateUpdater qualityGateUpdater, LoadedTemplateDao loadedTemplateDao) { | |||
this.qualityGates = qualityGates; | |||
this.qualityGateUpdater = qualityGateUpdater; | |||
this.loadedTemplateDao = loadedTemplateDao; | |||
} | |||
@@ -66,7 +68,7 @@ public class RegisterQualityGates implements Startable { | |||
} | |||
private void createBuiltinQualityGate() { | |||
QualityGateDto builtin = qualityGates.create(BUILTIN_QUALITY_GATE); | |||
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); |
@@ -22,28 +22,35 @@ 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.api.utils.text.JsonWriter; | |||
import org.sonar.core.permission.GlobalPermissions; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import org.sonar.server.qualitygate.QualityGates; | |||
import org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters; | |||
import org.sonar.server.qualitygate.QualityGateUpdater; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.WsQualityGates.CreateWsResponse; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_CREATE; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; | |||
public class CreateAction implements QualityGatesWsAction { | |||
private final QualityGates qualityGates; | |||
private final UserSession userSession; | |||
private final QualityGateUpdater qualityGateUpdater; | |||
public CreateAction(QualityGates qualityGates) { | |||
this.qualityGates = qualityGates; | |||
public CreateAction(UserSession userSession, QualityGateUpdater qualityGateUpdater) { | |||
this.userSession = userSession; | |||
this.qualityGateUpdater = qualityGateUpdater; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("create") | |||
WebService.NewAction action = controller.createAction(ACTION_CREATE) | |||
.setDescription("Create a Quality Gate. Require Administer Quality Gates permission") | |||
.setSince("4.3") | |||
.setPost(true) | |||
.setHandler(this); | |||
action.createParam(QualityGatesWsParameters.PARAM_NAME) | |||
action.createParam(PARAM_NAME) | |||
.setDescription("The name of the quality gate to create") | |||
.setRequired(true) | |||
.setExampleValue("My Quality Gate"); | |||
@@ -51,9 +58,12 @@ public class CreateAction implements QualityGatesWsAction { | |||
@Override | |||
public void handle(Request request, Response response) { | |||
QualityGateDto newQualityGate = qualityGates.create(request.mandatoryParam(QualityGatesWsParameters.PARAM_NAME)); | |||
JsonWriter writer = response.newJsonWriter(); | |||
QualityGatesWs.writeQualityGate(newQualityGate, writer).close(); | |||
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); | |||
} | |||
} |
@@ -39,6 +39,7 @@ import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | |||
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_GET_BY_PROJECT; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; | |||
@@ -57,7 +58,7 @@ public class GetByProjectAction implements QualityGatesWsAction { | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction("get_by_project") | |||
WebService.NewAction action = context.createAction(ACTION_GET_BY_PROJECT) | |||
.setInternal(true) | |||
.setSince("6.1") | |||
.setDescription("Get the quality gate of a project.<br> " + |
@@ -52,6 +52,7 @@ import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesEx | |||
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | |||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_PROJECT_STATUS; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; | |||
@@ -80,7 +81,7 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("project_status") | |||
WebService.NewAction action = controller.createAction(ACTION_PROJECT_STATUS) | |||
.setDescription(String.format("Get the quality gate status of a project or a Compute Engine task.<br />" + | |||
MSG_ONE_PARAMETER_ONLY + "<br />" + | |||
"The different statuses returned are: %s. The %s status is returned when there is no quality gate associated with the analysis.<br />" + |
@@ -27,6 +27,8 @@ 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; | |||
public class QualityGatesWs implements WebService { | |||
private final QualityGatesWsAction[] actions; | |||
@@ -36,7 +38,7 @@ public class QualityGatesWs implements WebService { | |||
@Override | |||
public void define(Context context) { | |||
NewController controller = context.createController("api/qualitygates") | |||
NewController controller = context.createController(CONTROLLER_QUALITY_GATES) | |||
.setSince("4.3") | |||
.setDescription("Manage quality gates, including conditions and project association."); | |||
@@ -40,6 +40,7 @@ import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPER | |||
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsUtils.checkFound; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.ACTION_SELECT; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_GATE_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; | |||
@@ -57,7 +58,7 @@ public class SelectAction implements QualityGatesWsAction { | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("select") | |||
WebService.NewAction action = controller.createAction(ACTION_SELECT) | |||
.setDescription("Associate a project to a quality gate.<br>" + | |||
"The '%s' or '%s' must be provided.<br>" + | |||
"Project id as a numeric value is deprecated since 6.1. Please use the id similar to '%s'.<br>" + |
@@ -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(20 + 2); | |||
assertThat(container.size()).isEqualTo(21 + 2); | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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 org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import static java.lang.String.format; | |||
import static org.assertj.core.api.Java6Assertions.assertThat; | |||
public class QualityGateUpdaterTest { | |||
static final String QGATE_NAME = "Default"; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
DbClient dbClient = db.getDbClient(); | |||
QualityGateUpdater underTest = new QualityGateUpdater(dbClient); | |||
@Test | |||
public void create_quality_gate() throws Exception { | |||
QualityGateDto result = underTest.create(QGATE_NAME); | |||
assertThat(result).isNotNull(); | |||
assertThat(result.getName()).isEqualTo(QGATE_NAME); | |||
assertThat(result.getCreatedAt()).isNotNull(); | |||
QualityGateDto reloaded = dbClient.qualityGateDao().selectByName(QGATE_NAME); | |||
assertThat(reloaded).isNotNull(); | |||
} | |||
@Test | |||
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(""); | |||
} | |||
@Test | |||
public void fail_to_create_when_name_already_exists() throws Exception { | |||
dbClient.qualityGateDao().insert(new QualityGateDto().setName(QGATE_NAME)); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("errors.is_already_used"); | |||
underTest.create(QGATE_NAME); | |||
} | |||
} |
@@ -51,7 +51,6 @@ import org.sonar.db.qualitygate.QualityGateConditionDto; | |||
import org.sonar.db.qualitygate.QualityGateDao; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.tester.AnonymousMockUserSession; | |||
import org.sonar.server.tester.MockUserSession; | |||
@@ -122,24 +121,6 @@ public class QualityGatesTest { | |||
assertThat(underTest.list()).isEqualTo(allQgates); | |||
} | |||
@Test(expected = ForbiddenException.class) | |||
public void should_fail_create_on_missing_permission() { | |||
userSessionRule.set(unauthorizedUserSession); | |||
underTest.create("polop"); | |||
} | |||
@Test(expected = BadRequestException.class) | |||
public void should_fail_create_on_empty_name() { | |||
underTest.create(""); | |||
} | |||
@Test(expected = BadRequestException.class) | |||
public void should_fail_create_on_duplicate_name() { | |||
String name = "SG-1"; | |||
when(dao.selectByName(name)).thenReturn(new QualityGateDto().setName(name).setId(QUALITY_GATE_ID)); | |||
underTest.create(name); | |||
} | |||
@Test | |||
public void should_get_qgate_by_id() { | |||
long id = QUALITY_GATE_ID; |
@@ -19,13 +19,18 @@ | |||
*/ | |||
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.DbTester; | |||
import org.sonar.db.loadedtemplate.LoadedTemplateDao; | |||
import org.sonar.db.loadedtemplate.LoadedTemplateDto; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.anyInt; | |||
import static org.mockito.Matchers.anyLong; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
@@ -41,28 +46,31 @@ import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THA | |||
public class RegisterQualityGatesTest { | |||
static long QGATE_ID = 42L; | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
DbClient dbClient = db.getDbClient(); | |||
QualityGates qualityGates = mock(QualityGates.class); | |||
LoadedTemplateDao templateDao = mock(LoadedTemplateDao.class); | |||
RegisterQualityGates task = new RegisterQualityGates(qualityGates, templateDao); | |||
RegisterQualityGates task = new RegisterQualityGates(qualityGates, new QualityGateUpdater(dbClient), templateDao); | |||
@Test | |||
public void register_default_gate() { | |||
String templateType = "QUALITY_GATE"; | |||
String templateName = "SonarQube way"; | |||
when(templateDao.countByTypeAndKey(templateType, templateName)).thenReturn(0); | |||
when(qualityGates.create(templateName)).thenReturn(new QualityGateDto().setId(QGATE_ID)); | |||
task.start(); | |||
verify(templateDao).countByTypeAndKey(templateType, templateName); | |||
verify(qualityGates).create(templateName); | |||
verify(qualityGates).createCondition(eq(QGATE_ID), eq(NEW_BUGS_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("0"), eq(1)); | |||
verify(qualityGates).createCondition(eq(QGATE_ID), eq(NEW_VULNERABILITIES_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("0"), eq(1)); | |||
verify(qualityGates).createCondition(eq(QGATE_ID), eq(NEW_SQALE_DEBT_RATIO_KEY), eq(OPERATOR_GREATER_THAN), eq((String) null), eq("5"), eq(1)); | |||
verify(qualityGates).createCondition(eq(QGATE_ID), eq(NEW_COVERAGE_KEY), eq(OPERATOR_LESS_THAN), eq((String) null), eq("80"), eq(1)); | |||
verify(qualityGates).setDefault(eq(QGATE_ID)); | |||
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()); |
@@ -0,0 +1,113 @@ | |||
/* | |||
* 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 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.qualitygate.QualityGateDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.qualitygate.QualityGateUpdater; | |||
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.CreateWsResponse; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; | |||
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; | |||
public class CreateActionTest { | |||
@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(); | |||
CreateAction underTest = new CreateAction(userSession, new QualityGateUpdater(dbClient)); | |||
WsActionTester ws = new WsActionTester(underTest); | |||
@Test | |||
public void create_quality_gate() throws Exception { | |||
setUserAsQualityGateAdmin(); | |||
CreateWsResponse response = executeRequest("Default"); | |||
assertThat(response.getName()).isEqualTo("Default"); | |||
assertThat(response.getId()).isNotNull(); | |||
dbSession.commit(); | |||
QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectByName("Default"); | |||
assertThat(qualityGateDto).isNotNull(); | |||
} | |||
@Test | |||
public void fail_when_not_quality_gate_admin() throws Exception { | |||
setUserAsNotQualityGateAdmin(); | |||
expectedException.expect(ForbiddenException.class); | |||
executeRequest("Default"); | |||
} | |||
@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(1); | |||
} | |||
private CreateWsResponse executeRequest(String name) { | |||
TestRequest request = ws.newRequest() | |||
.setMediaType(MediaTypes.PROTOBUF) | |||
.setParam("name", name); | |||
try { | |||
return CreateWsResponse.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,7 +70,7 @@ public class QualityGatesWsTest { | |||
tester = new WsTester(new QualityGatesWs( | |||
new ListAction(qGates), new ShowAction(qGates), new SearchAction(projectFinder), | |||
new CreateAction(qGates), new CopyAction(qGates), new DestroyAction(qGates), new RenameAction(qGates), | |||
new CreateAction(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), | |||
selectAction, new DeselectAction(qGates, mock(DbClient.class), mock(ComponentFinder.class)), new AppAction(null, null))); | |||
@@ -186,14 +186,6 @@ public class QualityGatesWsTest { | |||
assertThat(appInit.isInternal()).isTrue(); | |||
} | |||
@Test | |||
public void create_nominal() throws Exception { | |||
String name = "New QG"; | |||
when(qGates.create(name)).thenReturn(new QualityGateDto().setId(42L).setName(name)); | |||
tester.newPostRequest("api/qualitygates", "create").setParam("name", name).execute() | |||
.assertJson("{\"id\":42,\"name\":\"New QG\"}"); | |||
} | |||
@Test | |||
public void copy_nominal() throws Exception { | |||
String name = "Copied QG"; | |||
@@ -202,18 +194,6 @@ public class QualityGatesWsTest { | |||
.assertJson("{\"id\":42,\"name\":\"Copied QG\"}"); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void create_with_missing_name() throws Exception { | |||
tester.newPostRequest("api/qualitygates", "create").execute(); | |||
} | |||
@Test(expected = BadRequestException.class) | |||
public void create_with_duplicate_name() throws Exception { | |||
String name = "New QG"; | |||
when(qGates.create(name)).thenThrow(new BadRequestException("Name is already used")); | |||
tester.newPostRequest("api/qualitygates", "create").setParam("name", name).execute(); | |||
} | |||
@Test | |||
public void rename_nominal() throws Exception { | |||
Long id = 42L; |
@@ -19,25 +19,31 @@ | |||
*/ | |||
package org.sonarqube.ws.client.qualitygate; | |||
import org.sonarqube.ws.WsQualityGates.CreateWsResponse; | |||
import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
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_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_GATE_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY; | |||
public class QualityGatesService extends BaseService { | |||
public QualityGatesService(WsConnector wsConnector) { | |||
super(wsConnector, "api/qualitygates"); | |||
super(wsConnector, CONTROLLER_QUALITY_GATES); | |||
} | |||
public ProjectStatusWsResponse projectStatus(ProjectStatusWsRequest request) { | |||
return call(new GetRequest(path("project_status")) | |||
return call(new GetRequest(path(ACTION_PROJECT_STATUS)) | |||
.setParam(PARAM_ANALYSIS_ID, request.getAnalysisId()) | |||
.setParam(PARAM_PROJECT_ID, request.getProjectId()) | |||
.setParam(PARAM_PROJECT_KEY, request.getProjectKey()), | |||
@@ -45,9 +51,15 @@ public class QualityGatesService extends BaseService { | |||
} | |||
public void associateProject(SelectWsRequest request) { | |||
call(new PostRequest(path("select")) | |||
call(new PostRequest(path(ACTION_SELECT)) | |||
.setParam(PARAM_GATE_ID, request.getGateId()) | |||
.setParam(PARAM_PROJECT_ID, request.getProjectId()) | |||
.setParam(PARAM_PROJECT_KEY, request.getProjectKey())); | |||
} | |||
public CreateWsResponse create(String name) { | |||
return call(new PostRequest(path(ACTION_CREATE)) | |||
.setParam(PARAM_NAME, name), | |||
CreateWsResponse.parser()); | |||
} | |||
} |
@@ -21,6 +21,14 @@ | |||
package org.sonarqube.ws.client.qualitygate; | |||
public class QualityGatesWsParameters { | |||
public static final String CONTROLLER_QUALITY_GATES = "api/qualitygates"; | |||
public static final String ACTION_PROJECT_STATUS = "project_status"; | |||
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 PARAM_ANALYSIS_ID = "analysisId"; | |||
public static final String PARAM_PROJECT_ID = "projectId"; | |||
public static final String PARAM_PROJECT_KEY = "projectKey"; |
@@ -91,3 +91,11 @@ message AppWsResponse { | |||
} | |||
} | |||
// POST api/qualitygates/create | |||
message CreateWsResponse { | |||
optional int64 id = 1; | |||
optional string name = 2; | |||
} | |||
@@ -22,15 +22,20 @@ package org.sonarqube.ws.client.qualitygate; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonarqube.ws.WsQualityGates.CreateWsResponse; | |||
import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.ServiceTester; | |||
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_GATE_ID; | |||
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_NAME; | |||
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_GATE_ID; | |||
public class QualityGatesServiceTest { | |||
private static final String PROJECT_ID_VALUE = "195"; | |||
@@ -43,7 +48,7 @@ public class QualityGatesServiceTest { | |||
private QualityGatesService underTest = serviceTester.getInstanceUnderTest(); | |||
@Test | |||
public void associate_project_does_POST_request() { | |||
public void associate_project() { | |||
underTest.associateProject(new SelectWsRequest() | |||
.setGateId(GATE_ID_VALUE) | |||
.setProjectId(PROJECT_ID_VALUE) | |||
@@ -60,4 +65,31 @@ public class QualityGatesServiceTest { | |||
.hasParam(PARAM_PROJECT_KEY, PROJECT_KEY_VALUE) | |||
.andNoOtherParam(); | |||
} | |||
@Test | |||
public void project_status() { | |||
underTest.projectStatus(new ProjectStatusWsRequest() | |||
.setAnalysisId("analysisId") | |||
.setProjectId("projectId") | |||
.setProjectKey("projectKey")); | |||
GetRequest getRequest = serviceTester.getGetRequest(); | |||
assertThat(serviceTester.getGetParser()).isSameAs(ProjectStatusWsResponse.parser()); | |||
serviceTester.assertThat(getRequest) | |||
.hasParam(PARAM_ANALYSIS_ID, "analysisId") | |||
.hasParam(PARAM_PROJECT_ID, "projectId") | |||
.hasParam(PARAM_PROJECT_KEY, "projectKey") | |||
.andNoOtherParam(); | |||
} | |||
@Test | |||
public void create() { | |||
underTest.create("Default"); | |||
PostRequest request = serviceTester.getPostRequest(); | |||
assertThat(serviceTester.getPostParser()).isSameAs(CreateWsResponse.parser()); | |||
serviceTester.assertThat(request) | |||
.hasParam(PARAM_NAME, "Default") | |||
.andNoOtherParam(); | |||
} | |||
} |