diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-20 14:23:28 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-22 14:10:30 +0200 |
commit | 7b348e0ba5ce74367fc15d7aef4b163a4ecb1048 (patch) | |
tree | c3cc16e22c245c1881a2ece03415e1e18bda7d23 | |
parent | 1d8455866b14fc692bfebe2de64e4437438a5ce8 (diff) | |
download | sonarqube-7b348e0ba5ce74367fc15d7aef4b163a4ecb1048.tar.gz sonarqube-7b348e0ba5ce74367fc15d7aef4b163a4ecb1048.zip |
SONAR-8117 Extract creation of quality gate into QualityGateUpdater
19 files changed, 375 insertions, 82 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java index 4999167b855..89989a4f61d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java @@ -45,6 +45,7 @@ public class QualityGateModule extends Module { protected void configureModule() { add( QualityGates.class, + QualityGateUpdater.class, QgateProjectFinder.class, // WS QualityGatesWs.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java new file mode 100644 index 00000000000..a501c0d00a7 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java @@ -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"); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java index 70b462cd45e..47edf399e2a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java @@ -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); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java index 999c1461284..90bfef1ff30 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java @@ -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); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java index 49b2e837d7c..de6cb73768e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateAction.java @@ -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); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java index 2fbb8d03f4b..c51422284ad 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java @@ -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> " + diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java index 40b7cc507e6..704474df243 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java @@ -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 />" + diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java index 8e103f8e235..fc8c989501c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java @@ -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."); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java index 8791715abcb..c4ea2e424e7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java @@ -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>" + diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java index 0ea94b7f023..4f8c1d8342a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java @@ -30,6 +30,6 @@ public class QualityGateModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QualityGateModule().configure(container); - assertThat(container.size()).isEqualTo(20 + 2); + assertThat(container.size()).isEqualTo(21 + 2); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java new file mode 100644 index 00000000000..0f95091a800 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java @@ -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); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java index be41b48e548..e67c7bf2698 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java @@ -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; diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java index 05a4ac88467..929c0818b70 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java @@ -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()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java new file mode 100644 index 00000000000..f2b23b3f243 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateActionTest.java @@ -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); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java index 1f711722b8b..14bcfc5b73f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java @@ -70,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))); @@ -187,14 +187,6 @@ public class QualityGatesWsTest { } @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"; when(qGates.copy(24L, name)).thenReturn(new QualityGateDto().setId(42L).setName(name)); @@ -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; diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java index fa8a57ab4b9..93d76029483 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java @@ -19,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()); + } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java index e01d58e7b70..722fa0b1b41 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java @@ -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"; diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto index a8b26096d13..bbdbe48e581 100644 --- a/sonar-ws/src/main/protobuf/ws-qualitygates.proto +++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto @@ -91,3 +91,11 @@ message AppWsResponse { } } +// POST api/qualitygates/create +message CreateWsResponse { + optional int64 id = 1; + optional string name = 2; +} + + + diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java index 38ef7ba77c2..ec963ef9f5c 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualitygate/QualityGatesServiceTest.java @@ -22,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(); + } } |