diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-08-21 14:56:16 -0500 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-09-24 20:21:15 +0200 |
commit | d53977760baa53c56b53c369a2e027c61a6ec2c2 (patch) | |
tree | df63bf62317f82f49fbc376cfbff7fd8a6861e90 | |
parent | 89ab883abdf49d899598608c69359b0139ffb68a (diff) | |
download | sonarqube-d53977760baa53c56b53c369a2e027c61a6ec2c2.tar.gz sonarqube-d53977760baa53c56b53c369a2e027c61a6ec2c2.zip |
Improve code quality and test coverage
17 files changed, 1288 insertions, 24 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStep.java index f9b0311f7e5..46b46ed41bc 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStep.java @@ -89,7 +89,7 @@ public class LoadPeriodsStep implements ComputationStep { } } - private <T> Optional<T> firstPresent(Supplier<Optional<T>>... suppliers) { + private static <T> Optional<T> firstPresent(Supplier<Optional<T>>... suppliers) { for (Supplier<Optional<T>> supplier : suppliers) { Optional<T> result = supplier.get(); if (result.isPresent()) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java index a1d9ee6c8d6..265848f541a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java @@ -31,7 +31,7 @@ import static java.util.Objects.requireNonNull; import static org.sonar.api.utils.Preconditions.checkArgument; public class NewCodePeriodDao implements Dao { - + private static final String MSG_PROJECT_UUID_NOT_SPECIFIED = "Project uuid must be specified."; private final System2 system2; private final UuidFactory uuidFactory; @@ -73,23 +73,23 @@ public class NewCodePeriodDao implements Dao { } public Optional<NewCodePeriodDto> selectByProject(DbSession dbSession, String projectUuid) { - requireNonNull(projectUuid, "Project uuid must be specified."); + requireNonNull(projectUuid, MSG_PROJECT_UUID_NOT_SPECIFIED); return Optional.ofNullable(mapper(dbSession).selectByProject(projectUuid)); } public List<NewCodePeriodDto> selectAllByProject(DbSession dbSession, String projectUuid) { - requireNonNull(projectUuid, "Project uuid must be specified."); + requireNonNull(projectUuid, MSG_PROJECT_UUID_NOT_SPECIFIED); return mapper(dbSession).selectAllByProject(projectUuid); } public Optional<NewCodePeriodDto> selectByBranch(DbSession dbSession, String projectUuid, String branchUuid) { - requireNonNull(projectUuid, "Project uuid must be specified."); + requireNonNull(projectUuid, MSG_PROJECT_UUID_NOT_SPECIFIED); requireNonNull(branchUuid, "Branch uuid must be specified."); return Optional.ofNullable(mapper(dbSession).selectByBranch(projectUuid, branchUuid)); } public boolean existsByProjectAnalysisUuid(DbSession dbSession, String projectAnalysisUuid) { - requireNonNull(projectAnalysisUuid, "Project analysis uuid must be specified."); + requireNonNull(projectAnalysisUuid, MSG_PROJECT_UUID_NOT_SPECIFIED); return mapper(dbSession).countByProjectAnalysis(projectAnalysisUuid) > 0; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodParser.java b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodParser.java index f0c2304b4ff..34168e68e5b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodParser.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodParser.java @@ -22,6 +22,10 @@ package org.sonar.db.newcodeperiod; import java.time.LocalDate; public class NewCodePeriodParser { + private NewCodePeriodParser() { + // static only + } + public static LocalDate parseDate(String value) { return LocalDate.parse(value); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/package-info.java b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/package-info.java new file mode 100644 index 00000000000..4d471334ab6 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.db.newcodeperiod; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java index 4e86529f544..1b32e961ed4 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java @@ -21,6 +21,7 @@ package org.sonar.db.component; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import java.util.Collection; import java.util.Map; import javax.annotation.Nullable; import org.junit.Rule; @@ -38,6 +39,7 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang.StringUtils.repeat; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; +import static org.assertj.core.api.Assertions.tuple; @RunWith(DataProviderRunner.class) public class BranchDaoTest { @@ -101,7 +103,7 @@ public class BranchDaoTest { @DataProvider public static Object[][] nullOrEmpty() { - return new Object[][]{ + return new Object[][] { {null}, {""} }; @@ -111,7 +113,7 @@ public class BranchDaoTest { public static Object[][] oldAndNewValuesCombinations() { String value1 = randomAlphabetic(10); String value2 = randomAlphabetic(20); - return new Object[][]{ + return new Object[][] { {null, value1}, {"", value1}, {value1, null}, @@ -125,7 +127,7 @@ public class BranchDaoTest { @DataProvider public static Object[][] nonLongBranchType() { - return new Object[][]{ + return new Object[][] { {BranchType.SHORT}, {BranchType.PULL_REQUEST} }; @@ -367,6 +369,35 @@ public class BranchDaoTest { } @Test + public void selectByComponent() { + BranchDto mainBranch = new BranchDto(); + mainBranch.setProjectUuid("U1"); + mainBranch.setUuid("U1"); + mainBranch.setBranchType(BranchType.LONG); + mainBranch.setKey("master"); + underTest.insert(dbSession, mainBranch); + + BranchDto featureBranch = new BranchDto(); + featureBranch.setProjectUuid("U1"); + featureBranch.setUuid("U2"); + featureBranch.setBranchType(BranchType.SHORT); + featureBranch.setKey("feature/foo"); + featureBranch.setMergeBranchUuid("U3"); + underTest.insert(dbSession, featureBranch); + + ComponentDto component = new ComponentDto().setProjectUuid(mainBranch.getUuid()); + + // select the component + Collection<BranchDto> branches = underTest.selectByComponent(dbSession, component); + + assertThat(branches).hasSize(2); + + assertThat(branches).extracting(BranchDto::getUuid, BranchDto::getKey, BranchDto::getProjectUuid, BranchDto::getBranchType, BranchDto::getMergeBranchUuid) + .containsOnly(tuple(mainBranch.getUuid(), mainBranch.getKey(), mainBranch.getProjectUuid(), mainBranch.getBranchType(), mainBranch.getMergeBranchUuid()), + tuple(featureBranch.getUuid(), featureBranch.getKey(), featureBranch.getProjectUuid(), featureBranch.getBranchType(), featureBranch.getMergeBranchUuid())); + } + + @Test public void selectByPullRequestKey() { BranchDto mainBranch = new BranchDto(); mainBranch.setProjectUuid("U1"); diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateNewCodePeriodTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateNewCodePeriodTable.java index c2fbb0ffcad..0c35184c2a4 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateNewCodePeriodTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateNewCodePeriodTable.java @@ -227,7 +227,6 @@ public class PopulateNewCodePeriodTable extends DataChange { } private static List<EventDto> getVersionsByMostRecentFirst(Context context, String branchUuid) throws SQLException { - // TODO in LoadPeriodsStep we do a join with snapshots and see if the analysis is still unprocessed. Do we need to do it here? return context.prepareSelect("SELECT name, analysis_uuid FROM events " + "WHERE component_uuid = '" + branchUuid + "' AND category = 'Version' " + "ORDER BY created_at DESC") diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ListAction.java index 5e0c15df75c..9410a755b71 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ListAction.java @@ -105,7 +105,7 @@ public class ListAction implements NewCodePeriodsWsAction { } } - private NewCodePeriods.ShowWSResponse build(String projectKey, String branchKey, NewCodePeriodType newCodePeriodType, @Nullable String value, boolean inherited) { + private static NewCodePeriods.ShowWSResponse build(String projectKey, String branchKey, NewCodePeriodType newCodePeriodType, @Nullable String value, boolean inherited) { NewCodePeriods.ShowWSResponse.Builder builder = newBuilder() .setType(convertType(newCodePeriodType)) .setInherited(inherited) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java index 796c929fd23..4c99f809f97 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java @@ -147,6 +147,7 @@ public class SetAction implements NewCodePeriodsWsAction { break; case SPECIFIC_ANALYSIS: requireValue(type, value); + requireBranch(type, projectBranch); SnapshotDto analysis = getAnalysis(dbSession, value, projectBranch, branch); dto.setValue(analysis.getUuid()); break; @@ -155,10 +156,14 @@ public class SetAction implements NewCodePeriodsWsAction { } } - private void requireValue(NewCodePeriodType type, @Nullable String value) { + private static void requireValue(NewCodePeriodType type, @Nullable String value) { Preconditions.checkArgument(value != null, "New Code Period type '%s' requires a value", type); } + private static void requireBranch(NewCodePeriodType type, @Nullable ComponentDto projectBranch) { + Preconditions.checkArgument(projectBranch != null, "New Code Period type '%s' requires a branch", type); + } + private ComponentDto getProject(DbSession dbSession, String projectKey, @Nullable String branchKey) { if (branchKey == null) { return componentFinder.getByUuidOrKey(dbSession, null, projectKey, PROJECT_ID_AND_KEY); @@ -174,7 +179,7 @@ public class SetAction implements NewCodePeriodsWsAction { return project; } - private NewCodePeriodType validateType(String typeStr, boolean isOverall, boolean isBranch) { + private static NewCodePeriodType validateType(String typeStr, boolean isOverall, boolean isBranch) { NewCodePeriodType type; try { type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US)); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ShowAction.java index 6dff716e39d..86f95269dfe 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/ShowAction.java @@ -150,7 +150,7 @@ public class ShowAction implements NewCodePeriodsWsAction { .setInherited(inherited); } - private NewCodePeriods.NewCodePeriodType convertType(NewCodePeriodType type) { + private static NewCodePeriods.NewCodePeriodType convertType(NewCodePeriodType type) { switch (type) { case NUMBER_OF_DAYS: return NewCodePeriods.NewCodePeriodType.NUMBER_OF_DAYS; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java index f6a4236b03b..b826c847508 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java @@ -78,10 +78,9 @@ public class SetAction implements SettingsWsAction { private final SettingsUpdater settingsUpdater; private final SettingsChangeNotifier settingsChangeNotifier; private final SettingValidations validations; - private final SettingsWsSupport settingsWsSupport; public SetAction(PropertyDefinitions propertyDefinitions, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, - SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidations validations, SettingsWsSupport settingsWsSupport) { + SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidations validations) { this.propertyDefinitions = propertyDefinitions; this.dbClient = dbClient; this.componentFinder = componentFinder; @@ -89,7 +88,6 @@ public class SetAction implements SettingsWsAction { this.settingsUpdater = settingsUpdater; this.settingsChangeNotifier = settingsChangeNotifier; this.validations = validations; - this.settingsWsSupport = settingsWsSupport; } @Override diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java index 8be99c1d254..af2c062570e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java @@ -20,8 +20,6 @@ package org.sonar.server.setting.ws; import java.util.Optional; -import java.util.stream.Collector; -import java.util.stream.Collectors; import org.sonar.api.server.ServerSide; import org.sonar.api.web.UserRole; import org.sonar.db.component.ComponentDto; @@ -36,9 +34,6 @@ import static org.sonar.api.web.UserRole.ADMIN; @ServerSide public class SettingsWsSupport { - - private static final Collector<CharSequence, ?, String> COMMA_JOINER = Collectors.joining(","); - public static final String DOT_SECURED = ".secured"; private final DefaultOrganizationProvider defaultOrganizationProvider; diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ListActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ListActionTest.java new file mode 100644 index 00000000000..24e15d68b00 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ListActionTest.java @@ -0,0 +1,319 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.newcodeperiod.ws; + +import java.util.Optional; +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.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodDbTester; +import org.sonar.db.newcodeperiod.NewCodePeriodDto; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.NewCodePeriods; +import org.sonarqube.ws.NewCodePeriods.ListWSResponse; +import org.sonarqube.ws.NewCodePeriods.ShowWSResponse; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ListActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentDbTester componentDb = new ComponentDbTester(db); + private DbClient dbClient = db.getDbClient(); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); + private NewCodePeriodDbTester tester = new NewCodePeriodDbTester(db); + private ListAction underTest = new ListAction(dbClient, userSession, componentFinder, dao); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + + assertThat(definition.key()).isEqualTo("list"); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.since()).isEqualTo("8.0"); + assertThat(definition.isPost()).isFalse(); + + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("project"); + assertThat(definition.param("project").isRequired()).isTrue(); + } + + @Test + public void throw_NFE_if_project_not_found() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'unknown' not found"); + + ws.newRequest() + .setParam("project", "unknown") + .execute(); + } + + @Test + public void throw_FE_if_no_project_permission() { + ComponentDto project = componentDb.insertMainBranch(); + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + } + + @Test + public void list_only_LLB() { + ComponentDto project = componentDb.insertMainBranch(); + + createBranches(project, 5, BranchType.LONG); + createBranches(project, 3, BranchType.SHORT); + + logInAsProjectAdministrator(project); + + ListWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWSResponse.class); + + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(6); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .contains("master", "LONG_0", "LONG_1", "LONG_2", "LONG_3", "LONG_4"); + + //check if global default is set + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.PREVIOUS_VERSION); + } + + @Test + public void list_inherited_global_settings() { + ComponentDto project = componentDb.insertMainBranch(); + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.SPECIFIC_ANALYSIS).setValue("uuid")); + + createBranches(project, 5, BranchType.LONG); + + logInAsProjectAdministrator(project); + + ListWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWSResponse.class); + + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(6); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .contains("master", "LONG_0", "LONG_1", "LONG_2", "LONG_3", "LONG_4"); + + //check if global default is set + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getValue) + .contains("uuid"); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getInherited) + .contains(true); + } + + @Test + public void list_inherited_project_settings() { + ComponentDto projectWithOwnSettings = componentDb.insertMainBranch(); + ComponentDto projectWithGlobalSettings = componentDb.insertMainBranch(); + tester.insert(new NewCodePeriodDto() + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("global_uuid")); + tester.insert(new NewCodePeriodDto() + .setProjectUuid(projectWithOwnSettings.uuid()) + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("project_uuid")); + + createBranches(projectWithOwnSettings, 5, BranchType.LONG); + + logInAsProjectAdministrator(projectWithOwnSettings, projectWithGlobalSettings); + + ListWSResponse response = ws.newRequest() + .setParam("project", projectWithOwnSettings.getKey()) + .executeProtobuf(ListWSResponse.class); + + //verify project with project level settings + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(6); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .contains("master", "LONG_0", "LONG_1", "LONG_2", "LONG_3", "LONG_4"); + + //check if project setting is set + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getValue) + .containsOnly("project_uuid"); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getInherited) + .containsOnly(true); + + //verify project with global level settings + response = ws.newRequest() + .setParam("project", projectWithGlobalSettings.getKey()) + .executeProtobuf(ListWSResponse.class); + + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(1); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .containsOnly("master"); + + //check if global setting is set + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getValue) + .contains("global_uuid"); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getInherited) + .containsOnly(true); + } + + @Test + public void list_branch_and_inherited_global_settings() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branchWithOwnSettings = componentDb.insertProjectBranch(project, branchDto -> branchDto.setKey("OWN_SETTINGS")); + componentDb.insertProjectBranch(project, branchDto -> branchDto.setKey("GLOBAL_SETTINGS")); + + tester.insert(new NewCodePeriodDto() + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("global_uuid")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setBranchUuid(branchWithOwnSettings.uuid()) + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("branch_uuid")); + + logInAsProjectAdministrator(project); + + ListWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWSResponse.class); + + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(3); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .contains("master", "OWN_SETTINGS", "GLOBAL_SETTINGS"); + + Optional<ShowWSResponse> ownSettings = response.getNewCodePeriodsList().stream() + .filter(s -> !s.getInherited()) + .findFirst(); + + assertThat(ownSettings).isNotNull(); + assertThat(ownSettings).isNotEmpty(); + assertThat(ownSettings.get().getProjectKey()).isEqualTo(project.getKey()); + assertThat(ownSettings.get().getBranchKey()).isEqualTo("OWN_SETTINGS"); + assertThat(ownSettings.get().getType()).isEqualTo(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(ownSettings.get().getValue()).isEqualTo("branch_uuid"); + assertThat(ownSettings.get().getInherited()).isFalse(); + + //check if global default is set + assertThat(response.getNewCodePeriodsList()) + .filteredOn(ShowWSResponse::getInherited) + .extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(response.getNewCodePeriodsList()) + .filteredOn(ShowWSResponse::getInherited) + .extracting(ShowWSResponse::getValue) + .contains("global_uuid"); + } + + @Test + public void list_branch_and_inherited_project_settings() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branchWithOwnSettings = componentDb.insertProjectBranch(project, branchDto -> branchDto.setKey("OWN_SETTINGS")); + componentDb.insertProjectBranch(project, branchDto -> branchDto.setKey("PROJECT_SETTINGS")); + + tester.insert(new NewCodePeriodDto() + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("global_uuid")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("project_uuid")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setBranchUuid(branchWithOwnSettings.uuid()) + .setType(NewCodePeriodType.SPECIFIC_ANALYSIS) + .setValue("branch_uuid")); + + logInAsProjectAdministrator(project); + + ListWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWSResponse.class); + + assertThat(response).isNotNull(); + assertThat(response.getNewCodePeriodsCount()).isEqualTo(3); + assertThat(response.getNewCodePeriodsList()).extracting(ShowWSResponse::getBranchKey) + .contains("master", "OWN_SETTINGS", "PROJECT_SETTINGS"); + + Optional<ShowWSResponse> ownSettings = response.getNewCodePeriodsList().stream() + .filter(s -> !s.getInherited()) + .findFirst(); + + assertThat(ownSettings).isNotNull(); + assertThat(ownSettings).isNotEmpty(); + assertThat(ownSettings.get().getProjectKey()).isEqualTo(project.getKey()); + assertThat(ownSettings.get().getBranchKey()).isEqualTo("OWN_SETTINGS"); + assertThat(ownSettings.get().getType()).isEqualTo(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(ownSettings.get().getValue()).isEqualTo("branch_uuid"); + assertThat(ownSettings.get().getInherited()).isFalse(); + + //check if global default is set + assertThat(response.getNewCodePeriodsList()) + .filteredOn(ShowWSResponse::getInherited) + .extracting(ShowWSResponse::getType) + .contains(NewCodePeriods.NewCodePeriodType.SPECIFIC_ANALYSIS); + assertThat(response.getNewCodePeriodsList()) + .filteredOn(ShowWSResponse::getInherited) + .extracting(ShowWSResponse::getValue) + .contains("project_uuid"); + } + + private void createBranches(ComponentDto project, int numberOfBranches, BranchType branchType) { + for (int branchCount = 0; branchCount < numberOfBranches; branchCount++) { + String branchKey = String.format("%s_%d", branchType.name(), branchCount); + componentDb.insertProjectBranch(project, branchDto -> branchDto.setKey(branchKey).setBranchType(branchType)); + } + } + + private void logInAsProjectAdministrator(ComponentDto... project) { + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + } +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/NewCodePeriodsWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/NewCodePeriodsWsModuleTest.java new file mode 100644 index 00000000000..60166ae4756 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/NewCodePeriodsWsModuleTest.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.newcodeperiod.ws; + +import org.junit.Test; +import org.sonar.core.platform.ComponentContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NewCodePeriodsWsModuleTest { + + @Test + public void verify_count_of_added_components() { + ComponentContainer container = new ComponentContainer(); + new NewCodePeriodsWsModule().configure(container); + assertThat(container.size()).isEqualTo(7); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/SetActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/SetActionTest.java new file mode 100644 index 00000000000..e18763e72eb --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/SetActionTest.java @@ -0,0 +1,378 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.newcodeperiod.ws; + +import javax.annotation.Nullable; +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.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.SnapshotDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class SetActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentDbTester componentDb = new ComponentDbTester(db); + private DbClient dbClient = db.getDbClient(); + private DbSession dbSession = db.getSession(); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); + + private SetAction underTest = new SetAction(dbClient, userSession, componentFinder, dao); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + + assertThat(definition.key()).isEqualTo("set"); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.since()).isEqualTo("8.0"); + assertThat(definition.isPost()).isTrue(); + + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("value", "type", "project", "branch"); + assertThat(definition.param("value").isRequired()).isFalse(); + assertThat(definition.param("type").isRequired()).isTrue(); + assertThat(definition.param("project").isRequired()).isFalse(); + assertThat(definition.param("branch").isRequired()).isFalse(); + } + + // validation of type + @Test + public void throw_IAE_if_no_type_specified() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("The 'type' parameter is missing"); + + ws.newRequest() + .execute(); + } + + @Test + public void throw_IAE_if_type_is_invalid() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Invalid type: unknown"); + + ws.newRequest() + .setParam("type", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_type_is_invalid_for_global() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Invalid type 'SPECIFIC_ANALYSIS'. Overall setting can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS]"); + + ws.newRequest() + .setParam("type", "specific_analysis") + .execute(); + } + + @Test + public void throw_IAE_if_type_is_invalid_for_project() { + ComponentDto project = componentDb.insertPublicProject(); + logInAsProjectAdministrator(project); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Invalid type 'SPECIFIC_ANALYSIS'. Projects can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS]"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .execute(); + } + + @Test + public void throw_IAE_if_no_value_for_days() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("New Code Period type 'NUMBER_OF_DAYS' requires a value"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "master") + .setParam("type", "number_of_days") + .execute(); + } + + @Test + public void throw_IAE_if_no_value_for_analysis() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("New Code Period type 'SPECIFIC_ANALYSIS' requires a value"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "master") + .execute(); + } + + @Test + public void throw_IAE_if_days_is_invalid() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Failed to parse number of days: unknown"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "number_of_days") + .setParam("branch", "master") + .setParam("value", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_analysis_is_not_found() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Analysis 'unknown' is not found"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "master") + .setParam("value", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_analysis_doesnt_belong_to_branch() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + SnapshotDto analysisMaster = db.components().insertSnapshot(project); + SnapshotDto analysisBranch = db.components().insertSnapshot(branch); + + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Analysis '" + analysisBranch.getUuid() + "' does not belong to branch 'master' of project '" + project.getKey() + "'"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "master") + .setParam("value", analysisBranch.getUuid()) + .execute(); + } + + // validation of project/branch + @Test + public void throw_IAE_if_branch_is_specified_without_project() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("If branch key is specified, project key needs to be specified too"); + + ws.newRequest() + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_NFE_if_project_not_found() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'unknown' not found"); + + ws.newRequest() + .setParam("type", "previous_version") + .setParam("project", "unknown") + .execute(); + } + + @Test + public void throw_NFE_if_branch_not_found() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component '" + project.getKey() + "' on branch 'unknown' not found"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .setParam("branch", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_branch_is_a_SLB() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch").setBranchType(BranchType.SHORT)); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Not a long-living branch: 'branch'"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .setParam("branch", "branch") + .execute(); + } + + // permission + @Test + public void throw_NFE_if_no_project_permission() { + ComponentDto project = componentDb.insertMainBranch(); + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .execute(); + } + + @Test + public void throw_NFE_if_no_system_permission() { + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("type", "previous_version") + .execute(); + } + + // success cases + @Test + public void set_global_period_to_previous_version() { + logInAsSystemAdministrator(); + ws.newRequest() + .setParam("type", "previous_version") + .execute(); + + assertTableContainsOnly(null, null, NewCodePeriodType.PREVIOUS_VERSION, null); + } + + @Test + public void set_project_period_to_number_of_days() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "number_of_days") + .setParam("value", "5") + .execute(); + assertTableContainsOnly(project.uuid(), null, NewCodePeriodType.NUMBER_OF_DAYS, "5"); + } + + @Test + public void set_project_twice_period_to_number_of_days() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .execute(); + assertTableContainsOnly(project.uuid(), null, NewCodePeriodType.PREVIOUS_VERSION, null); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "number_of_days") + .setParam("value", "5") + .execute(); + assertTableContainsOnly(project.uuid(), null, NewCodePeriodType.NUMBER_OF_DAYS, "5"); + } + + @Test + public void set_branch_period_to_analysis() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + SnapshotDto analysisMaster = db.components().insertSnapshot(project); + SnapshotDto analysisBranch = db.components().insertSnapshot(branch); + + logInAsProjectAdministrator(project); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "branch") + .setParam("value", analysisBranch.getUuid()) + .execute(); + + assertTableContainsOnly(project.uuid(), branch.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, analysisBranch.getUuid()); + } + + @Test + public void set_branch_period_twice_to_analysis() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + SnapshotDto analysisMaster = db.components().insertSnapshot(project); + SnapshotDto analysisBranch = db.components().insertSnapshot(branch); + + logInAsProjectAdministrator(project); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "specific_analysis") + .setParam("branch", "branch") + .setParam("value", analysisBranch.getUuid()) + .execute(); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .setParam("branch", "branch") + .execute(); + + assertTableContainsOnly(project.uuid(), branch.uuid(), NewCodePeriodType.PREVIOUS_VERSION, null); + } + + private void assertTableContainsOnly(@Nullable String projectUuid, @Nullable String branchUuid, NewCodePeriodType type, @Nullable String value) { + assertThat(db.countRowsOfTable(dbSession, "new_code_periods")).isEqualTo(1); + assertThat(db.selectFirst(dbSession, "select project_uuid, branch_uuid, type, value from new_code_periods")) + .containsOnly(entry("PROJECT_UUID", projectUuid), entry("BRANCH_UUID", branchUuid), entry("TYPE", type.name()), entry("VALUE", value)); + } + + private void logInAsProjectAdministrator(ComponentDto project) { + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + } + + private void logInAsSystemAdministrator() { + userSession.logIn().setSystemAdministrator(); + } +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ShowActionTest.java new file mode 100644 index 00000000000..d57733d02da --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/ShowActionTest.java @@ -0,0 +1,247 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.newcodeperiod.ws; + +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.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodDbTester; +import org.sonar.db.newcodeperiod.NewCodePeriodDto; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.NewCodePeriods; +import org.sonarqube.ws.NewCodePeriods.ShowWSResponse; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ShowActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentDbTester componentDb = new ComponentDbTester(db); + private DbClient dbClient = db.getDbClient(); + private DbSession dbSession = db.getSession(); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); + private NewCodePeriodDbTester tester = new NewCodePeriodDbTester(db); + private ShowAction underTest = new ShowAction(dbClient, userSession, componentFinder, dao); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + + assertThat(definition.key()).isEqualTo("show"); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.since()).isEqualTo("8.0"); + assertThat(definition.isPost()).isFalse(); + + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("project", "branch"); + assertThat(definition.param("project").isRequired()).isFalse(); + assertThat(definition.param("branch").isRequired()).isFalse(); + } + + @Test + public void throw_IAE_if_branch_is_specified_without_project() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("If branch key is specified, project key needs to be specified too"); + + ws.newRequest() + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_NFE_if_project_not_found() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'unknown' not found"); + + ws.newRequest() + .setParam("project", "unknown") + .execute(); + } + + @Test + public void throw_NFE_if_branch_not_found() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component '" + project.getKey() + "' on branch 'unknown' not found"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_branch_is_a_SLB() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch").setBranchType(BranchType.SHORT)); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Not a long-living branch: 'branch'"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_FE_if_no_project_permission() { + ComponentDto project = componentDb.insertMainBranch(); + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + } + + @Test + public void show_global_setting() { + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.PREVIOUS_VERSION)); + + ShowWSResponse response = ws.newRequest() + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, "", "", NewCodePeriods.NewCodePeriodType.PREVIOUS_VERSION, "", false); + } + + @Test + public void show_project_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setType(NewCodePeriodType.NUMBER_OF_DAYS) + .setValue("4")); + + ShowWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, project.getKey(), "", NewCodePeriods.NewCodePeriodType.NUMBER_OF_DAYS, "4", false); + } + + @Test + public void show_branch_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setBranchUuid(branch.uuid()) + .setType(NewCodePeriodType.NUMBER_OF_DAYS) + .setValue("1")); + + ShowWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, project.getKey(), "branch", NewCodePeriods.NewCodePeriodType.NUMBER_OF_DAYS, "1", false); + } + + @Test + public void show_inherited_project_setting() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.PREVIOUS_VERSION)); + + ShowWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, project.getKey(), "", NewCodePeriods.NewCodePeriodType.PREVIOUS_VERSION, "", true); + } + + @Test + public void show_inherited_branch_setting_from_project() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + tester.insert(new NewCodePeriodDto() + .setProjectUuid(project.uuid()) + .setType(NewCodePeriodType.NUMBER_OF_DAYS) + .setValue("1")); + + ShowWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, project.getKey(), "branch", NewCodePeriods.NewCodePeriodType.NUMBER_OF_DAYS, "1", true); + } + + @Test + public void show_inherited_branch_setting_from_global() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + tester.insert(new NewCodePeriodDto().setType(NewCodePeriodType.NUMBER_OF_DAYS).setValue("3")); + + ShowWSResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .executeProtobuf(ShowWSResponse.class); + + assertResponse(response, project.getKey(), "branch", NewCodePeriods.NewCodePeriodType.NUMBER_OF_DAYS, "3", true); + } + + private void assertResponse(ShowWSResponse response, String projectKey, String branchKey, NewCodePeriods.NewCodePeriodType type, String value, boolean inherited) { + assertThat(response.getBranchKey()).isEqualTo(branchKey); + assertThat(response.getProjectKey()).isEqualTo(projectKey); + assertThat(response.getInherited()).isEqualTo(inherited); + assertThat(response.getValue()).isEqualTo(value); + assertThat(response.getType()).isEqualTo(type); + } + + private void logInAsProjectAdministrator(ComponentDto project) { + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/UnsetActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/UnsetActionTest.java new file mode 100644 index 00000000000..7475a38d2a5 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/UnsetActionTest.java @@ -0,0 +1,229 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.newcodeperiod.ws; + +import javax.annotation.Nullable; +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.api.web.UserRole; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDao; +import org.sonar.db.newcodeperiod.NewCodePeriodType; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class UnsetActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private ComponentDbTester componentDb = new ComponentDbTester(db); + private DbClient dbClient = db.getDbClient(); + private DbSession dbSession = db.getSession(); + private ComponentFinder componentFinder = TestComponentFinder.from(db); + private NewCodePeriodDao dao = new NewCodePeriodDao(System2.INSTANCE, UuidFactoryFast.getInstance()); + + private UnsetAction underTest = new UnsetAction(dbClient, userSession, componentFinder, dao); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = ws.getDef(); + + assertThat(definition.key()).isEqualTo("unset"); + assertThat(definition.isInternal()).isFalse(); + assertThat(definition.since()).isEqualTo("8.0"); + assertThat(definition.isPost()).isTrue(); + + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("project", "branch"); + assertThat(definition.param("project").isRequired()).isFalse(); + assertThat(definition.param("branch").isRequired()).isFalse(); + } + + // validation of project/branch + @Test + public void throw_IAE_if_branch_is_specified_without_project() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("If branch key is specified, project key needs to be specified too"); + + ws.newRequest() + .setParam("branch", "branch") + .execute(); + } + + @Test + public void throw_NFE_if_project_not_found() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'unknown' not found"); + + ws.newRequest() + .setParam("type", "previous_version") + .setParam("project", "unknown") + .execute(); + } + + @Test + public void throw_NFE_if_branch_not_found() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component '" + project.getKey() + "' on branch 'unknown' not found"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .setParam("branch", "unknown") + .execute(); + } + + @Test + public void throw_IAE_if_branch_is_a_SLB() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch").setBranchType(BranchType.SHORT)); + logInAsProjectAdministrator(project); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Not a long-living branch: 'branch'"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .setParam("branch", "branch") + .execute(); + } + + // permission + @Test + public void throw_NFE_if_no_project_permission() { + ComponentDto project = componentDb.insertMainBranch(); + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("type", "previous_version") + .execute(); + } + + @Test + public void throw_NFE_if_no_system_permission() { + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest() + .setParam("type", "previous_version") + .execute(); + } + + // success cases + @Test + public void delete_global_period() { + logInAsSystemAdministrator(); + ws.newRequest() + .execute(); + + assertTableEmpty(); + } + + @Test + public void delete_project_period() { + ComponentDto project = componentDb.insertMainBranch(); + logInAsProjectAdministrator(project); + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + + assertTableEmpty(); + } + + @Test + public void delete_project_period_twice() { + ComponentDto project1 = componentDb.insertMainBranch(); + ComponentDto project2 = componentDb.insertMainBranch(); + db.newCodePeriods().insert(project1.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid1"); + db.newCodePeriods().insert(project2.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid2"); + + logInAsProjectAdministrator(project1); + ws.newRequest() + .setParam("project", project1.getKey()) + .execute(); + assertTableContainsOnly(project2.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid2"); + + ws.newRequest() + .setParam("project", project1.getKey()) + .execute(); + + assertTableContainsOnly(project2.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid2"); + } + + @Test + public void delete_branch_period() { + ComponentDto project = componentDb.insertMainBranch(); + ComponentDto branch = componentDb.insertProjectBranch(project, b -> b.setKey("branch")); + + db.newCodePeriods().insert(project.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid1"); + db.newCodePeriods().insert(project.uuid(), branch.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid2"); + + logInAsProjectAdministrator(project); + + ws.newRequest() + .setParam("project", project.getKey()) + .setParam("branch", "branch") + .execute(); + + assertTableContainsOnly(project.uuid(), null, NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid1"); + } + + private void assertTableEmpty() { + assertThat(db.countRowsOfTable(dbSession, "new_code_periods")).isEqualTo(0); + } + + private void assertTableContainsOnly(@Nullable String projectUuid, @Nullable String branchUuid, NewCodePeriodType type, @Nullable String value) { + assertThat(db.countRowsOfTable(dbSession, "new_code_periods")).isEqualTo(1); + assertThat(db.selectFirst(dbSession, "select project_uuid, branch_uuid, type, value from new_code_periods")) + .containsOnly(entry("PROJECT_UUID", projectUuid), entry("BRANCH_UUID", branchUuid), entry("TYPE", type.name()), entry("VALUE", value)); + } + + private void logInAsProjectAdministrator(ComponentDto project) { + userSession.logIn().addProjectPermission(UserRole.ADMIN, project); + } + + private void logInAsSystemAdministrator() { + userSession.logIn().setSystemAdministrator(); + } +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java index 785ee7fa3bf..6043e4aa23e 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java @@ -96,8 +96,7 @@ public class SetActionTest { private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private SettingValidations validations = new SettingValidations(definitions, dbClient, i18n); private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - private SetAction underTest = new SetAction(definitions, dbClient, componentFinder, userSession, settingsUpdater, - settingsChangeNotifier, validations, new SettingsWsSupport(defaultOrganizationProvider, userSession)); + private SetAction underTest = new SetAction(definitions, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier, validations); private WsActionTester ws = new WsActionTester(underTest); |