--- /dev/null
+/*
+ * 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.db.newcodeperiod;
+
+import java.time.LocalDate;
+
+public class NewCodePeriodParser {
+ public static LocalDate parseDate(String value) {
+ return LocalDate.parse(value);
+ }
+
+ public static int parseDays(String value) {
+ return Integer.parseInt(value);
+ }
+}
--- /dev/null
+/*
+ * 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.setting.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.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.newcodeperiod.NewCodePeriodDao;
+import org.sonar.server.user.UserSession;
+
+public class GetNewCodePeriodAction implements SettingsWsAction {
+ private final DbClient dbClient;
+ private final UserSession userSession;
+ private final NewCodePeriodDao newCodePeriodDao;
+
+ public GetNewCodePeriodAction(DbClient dbClient, UserSession userSession, NewCodePeriodDao newCodePeriodDao) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ this.newCodePeriodDao = newCodePeriodDao;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ context.createAction("get_new_code_period")
+ .setDescription("Updates the setting for the New Code Period.<br>" +
+ "Requires one of the following permissions: " +
+ "<ul>" +
+ "<li>'Administer System'</li>" +
+ "<li>'Administer' rights on the specified component</li>" +
+ "</ul>")
+ .setSince("8.0")
+ .setResponseExample(getClass().getResource("generate_secret_key-example.json"))
+ .setHandler(this);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ userSession.checkIsSystemAdministrator();
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ // TODO should it fall back branch->project->global?
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.setting.ws;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import java.util.Locale;
+import java.util.Set;
+import javax.annotation.Nullable;
+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.web.UserRole;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodDao;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodParser;
+import org.sonar.db.newcodeperiod.NewCodePeriodType;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.DATE;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS;
+import static org.sonar.server.component.ComponentFinder.ParamNames.PROJECT_ID_AND_KEY;
+
+public class SetNewCodePeriodAction implements SettingsWsAction {
+ private static final String PARAM_BRANCH = "branchKey";
+ private static final String PARAM_PROJECT = "projectKey";
+ private static final String PARAM_TYPE = "type";
+ private static final String PARAM_VALUE = "value";
+ private static final Set<NewCodePeriodType> OVERALL_TYPES = ImmutableSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS);
+ private static final Set<NewCodePeriodType> PROJECT_TYPES = ImmutableSet.of(DATE, PREVIOUS_VERSION, NUMBER_OF_DAYS);
+ private static final Set<NewCodePeriodType> BRANCH_TYPES = ImmutableSet.of(DATE, PREVIOUS_VERSION, NUMBER_OF_DAYS, SPECIFIC_ANALYSIS);
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+ private final ComponentFinder componentFinder;
+ private final NewCodePeriodDao newCodePeriodDao;
+
+ public SetNewCodePeriodAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, NewCodePeriodDao newCodePeriodDao) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ this.componentFinder = componentFinder;
+ this.newCodePeriodDao = newCodePeriodDao;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction("set_new_code_period")
+ .setDescription("Updates the setting for the New Code Period.<br>" +
+ "Requires one of the following permissions: " +
+ "<ul>" +
+ "<li>'Administer System'</li>" +
+ "<li>'Administer' rights on the specified component</li>" +
+ "</ul>")
+ .setSince("8.0")
+ .setResponseExample(getClass().getResource("generate_secret_key-example.json"))
+ .setHandler(this);
+
+ action.createParam(PARAM_PROJECT)
+ .setDescription("Project key");
+ action.createParam(PARAM_BRANCH)
+ .setDescription("Branch key");
+ action.createParam(PARAM_TYPE)
+ .setRequired(true)
+ .setDescription("Type");
+ action.createParam(PARAM_VALUE)
+ .setDescription("Value");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ String projectStr = request.getParam(PARAM_PROJECT).emptyAsNull().or(() -> null);
+ String branchStr = request.getParam(PARAM_BRANCH).emptyAsNull().or(() -> null);
+
+ if (projectStr == null && branchStr != null) {
+ throw new IllegalArgumentException("If branch key is specified, project key needs to be specified too");
+ }
+
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ String typeStr = request.mandatoryParam(PARAM_TYPE);
+ String valueStr = request.getParam(PARAM_VALUE).emptyAsNull().or(() -> null);
+ NewCodePeriodType type = validateType(typeStr, projectStr == null, branchStr != null);
+
+ NewCodePeriodDto dto = new NewCodePeriodDto();
+ dto.setType(type);
+
+ ComponentDto projectBranch = null;
+ if (projectStr != null) {
+ projectBranch = getProject(dbSession, projectStr, branchStr);
+ userSession.checkComponentPermission(UserRole.ADMIN, projectBranch);
+ dto.setProjectUuid(projectBranch.projectUuid());
+ } else {
+ userSession.checkIsSystemAdministrator();
+ }
+
+ setValue(dbSession, dto, type, projectBranch, branchStr, valueStr);
+
+ // TODO upsert?
+ newCodePeriodDao.insert(dbSession, dto);
+ }
+ }
+
+ private void setValue(DbSession dbSession, NewCodePeriodDto dto, NewCodePeriodType type, @Nullable ComponentDto projectBranch,
+ @Nullable String branch, @Nullable String value) {
+ switch (type) {
+ case PREVIOUS_VERSION:
+ Preconditions.checkArgument(value == null, "Unexpected value for type '%s'", type);
+ break;
+ case NUMBER_OF_DAYS:
+ requireValue(type, value);
+ try {
+ dto.setValue(Integer.toString(NewCodePeriodParser.parseDays(value)));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to parse number of days: " + value);
+ }
+ break;
+ case DATE:
+ requireValue(type, value);
+ try {
+ dto.setValue(NewCodePeriodParser.parseDate(value).toString());
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to parse date: " + value);
+ }
+ break;
+ case SPECIFIC_ANALYSIS:
+ requireValue(type, value);
+ SnapshotDto analysis = getAnalysis(dbSession, value, projectBranch, branch);
+ dto.setValue(analysis.getUuid());
+ break;
+ default:
+ throw new IllegalStateException("Unexpected type: " + type);
+ }
+ }
+
+ private void requireValue(NewCodePeriodType type, @Nullable String value) {
+ Preconditions.checkArgument(value != null, "New Code Period type '%s' requires a value", type);
+ }
+
+ private ComponentDto getProject(DbSession dbSession, String projectKey, @Nullable String branchKey) {
+ if (branchKey == null) {
+ return componentFinder.getByUuidOrKey(dbSession, null, projectKey, PROJECT_ID_AND_KEY);
+ }
+ ComponentDto project = componentFinder.getByKeyAndBranch(dbSession, projectKey, branchKey);
+
+ BranchDto branchDto = dbClient.branchDao().selectByUuid(dbSession, project.uuid())
+ .orElseThrow(() -> new NotFoundException(format("Branch '%s' is not found", branchKey)));
+
+ checkArgument(branchDto.getBranchType() == BranchType.LONG,
+ "Not a long-living branch: '%s'", branchKey);
+
+ return project;
+ }
+
+ private NewCodePeriodType validateType(String typeStr, boolean isOverall, boolean isBranch) {
+ NewCodePeriodType type;
+ try {
+ type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid type: " + typeStr);
+ }
+
+ if (isOverall) {
+ checkType("Overall setting", OVERALL_TYPES, type);
+ } else if (isBranch) {
+ checkType("Branches", BRANCH_TYPES, type);
+ } else {
+ checkType("Projects", PROJECT_TYPES, type);
+ }
+ return type;
+ }
+
+ private SnapshotDto getAnalysis(DbSession dbSession, String analysisUuid, ComponentDto projectBranch, @Nullable String branchKey) {
+ SnapshotDto snapshotDto = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid)
+ .orElseThrow(() -> new NotFoundException(format("Analysis '%s' is not found", analysisUuid)));
+ checkAnalysis(dbSession, projectBranch, branchKey, snapshotDto);
+ return snapshotDto;
+ }
+
+ private void checkAnalysis(DbSession dbSession, ComponentDto projectBranch, @Nullable String branchKey, SnapshotDto analysis) {
+ ComponentDto project = dbClient.componentDao().selectByUuid(dbSession, analysis.getComponentUuid()).orElse(null);
+
+ boolean analysisMatchesProjectBranch = project != null && projectBranch.uuid().equals(project.uuid());
+ if (branchKey != null) {
+ checkArgument(analysisMatchesProjectBranch,
+ "Analysis '%s' does not belong to branch '%s' of project '%s'",
+ analysis.getUuid(), branchKey, projectBranch.getKey());
+ } else {
+ checkArgument(analysisMatchesProjectBranch,
+ "Analysis '%s' does not belong to project '%s'",
+ analysis.getUuid(), projectBranch.getKey());
+ }
+ }
+
+ private static void checkType(String name, Set<NewCodePeriodType> validTypes, NewCodePeriodType type) {
+ if (!validTypes.contains(type)) {
+ throw new IllegalArgumentException(String.format("Invalid type '%s'. %s can only be set with types: %s", type, name, validTypes));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.setting.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.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.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.mockito.Mockito.mock;
+
+public class SetNewCodePeriodActionTest {
+ @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 = mock(NewCodePeriodDao.class);
+
+ private SetNewCodePeriodAction underTest = new SetNewCodePeriodAction(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_new_code_period");
+ assertThat(definition.isInternal()).isFalse();
+ //assertThat(definition.responseExampleAsString()).isNotEmpty();
+ assertThat(definition.since()).isEqualTo("8.0");
+ assertThat(definition.isPost()).isFalse();
+
+ assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("value", "type", "projectKey", "branchKey");
+ assertThat(definition.param("value").isRequired()).isFalse();
+ assertThat(definition.param("type").isRequired()).isTrue();
+ assertThat(definition.param("projectKey").isRequired()).isFalse();
+ assertThat(definition.param("branchKey").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 'DATE'. Overall setting can only be set with types: [PREVIOUS_VERSION, DAYS]");
+
+ ws.newRequest()
+ .setParam("type", "date")
+ .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 'ANALYSIS'. Projects can only be set with types: [DATE, PREVIOUS_VERSION, DAYS]");
+
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("type", "analysis")
+ .execute();
+ }
+
+ // validation of value
+ @Test
+ public void throw_IAE_if_no_value_for_date() {
+ ComponentDto project = componentDb.insertPublicProject();
+ logInAsProjectAdministrator(project);
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("New Code Period type 'DATE' requires a value");
+
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("type", "date")
+ .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 'DAYS' requires a value");
+
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("branchKey", "master")
+ .setParam("type", "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 'ANALYSIS' requires a value");
+
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("type", "analysis")
+ .setParam("branchKey", "master")
+ .execute();
+ }
+
+ @Test
+ public void throw_IAE_if_date_is_invalid() {
+ ComponentDto project = componentDb.insertMainBranch();
+ logInAsProjectAdministrator(project);
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Failed to parse date: unknown");
+
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("type", "date")
+ .setParam("branchKey", "master")
+ .setParam("value", "unknown")
+ .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("projectKey", project.getKey())
+ .setParam("type", "days")
+ .setParam("branchKey", "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("projectKey", project.getKey())
+ .setParam("type", "analysis")
+ .setParam("branchKey", "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("projectKey", project.getKey())
+ .setParam("type", "analysis")
+ .setParam("branchKey", "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("branchKey", "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("projectKey", "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("projectKey", project.getKey())
+ .setParam("type", "previous_version")
+ .setParam("branchKey", "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("projectKey", project.getKey())
+ .setParam("type", "previous_version")
+ .setParam("branchKey", "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("projectKey", 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();
+ // TODO
+
+ }
+
+ @Test
+ public void set_project_period_to_number_of_days() {
+ ComponentDto project = componentDb.insertMainBranch();
+ logInAsProjectAdministrator(project);
+ ws.newRequest()
+ .setParam("projectKey", project.getKey())
+ .setParam("type", "days")
+ .setParam("value", "5")
+ .execute();
+ // TODO
+
+ }
+
+ @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("projectKey", project.getKey())
+ .setParam("type", "analysis")
+ .setParam("branchKey", "branch")
+ .setParam("value", analysisBranch.getUuid())
+ .execute();
+ // TODO
+ }
+
+ private void logInAsProjectAdministrator(ComponentDto project) {
+ userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
+ }
+
+ private void logInAsSystemAdministrator() {
+ userSession.logIn().setSystemAdministrator();
+ }
+}