*/
package org.sonar.server.qualitygate.ws;
+import com.google.common.base.Optional;
+import org.elasticsearch.common.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.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
import org.sonar.server.qualitygate.QualityGates;
import org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
public class DeselectAction implements QualityGatesWsAction {
private final QualityGates qualityGates;
+ private final DbClient dbClient;
+ private final ComponentFinder componentFinder;
- public DeselectAction(QualityGates qualityGates) {
+ public DeselectAction(QualityGates qualityGates, DbClient dbClient, ComponentFinder componentFinder) {
this.qualityGates = qualityGates;
+ this.dbClient = dbClient;
+ this.componentFinder = componentFinder;
}
@Override
.setHandler(this);
action.createParam(QualityGatesWsParameters.PARAM_GATE_ID)
- .setDescription("Quality Gate ID")
+ .setDescription("Quality Gate id")
.setRequired(true)
- .setExampleValue("1");
+ .setExampleValue("23");
action.createParam(PARAM_PROJECT_ID)
- .setDescription("Project ID")
- .setRequired(true)
- .setExampleValue("12");
+ .setDescription("Project id. Project id as an numeric value is deprecated since 6.1")
+ .setExampleValue(Uuids.UUID_EXAMPLE_01);
+
+ action.createParam(PARAM_PROJECT_KEY)
+ .setDescription("Project key")
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001)
+ .setSince("6.1");
}
@Override
public void handle(Request request, Response response) {
- qualityGates.dissociateProject(QualityGatesWs.parseId(request, QualityGatesWsParameters.PARAM_GATE_ID), QualityGatesWs.parseId(request, PARAM_PROJECT_ID));
+ ComponentDto project = getProject(request.param(PARAM_PROJECT_ID), request.param(PARAM_PROJECT_KEY));
+ qualityGates.dissociateProject(QualityGatesWs.parseId(request, QualityGatesWsParameters.PARAM_GATE_ID), project.getId());
response.noContent();
}
+ private ComponentDto getProject(@Nullable String projectId, @Nullable String projectKey) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ return selectProjectById(dbSession, projectId)
+ .or(() -> componentFinder.getByUuidOrKey(dbSession, projectId, projectKey, ComponentFinder.ParamNames.PROJECT_ID_AND_KEY));
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private Optional<ComponentDto> selectProjectById(DbSession dbSession, @Nullable String projectId) {
+ if (projectId == null) {
+ return Optional.absent();
+ }
+
+ try {
+ long dbId = Long.parseLong(projectId);
+ return dbClient.componentDao().selectById(dbSession, dbId);
+ } catch (NumberFormatException e) {
+ return Optional.absent();
+ }
+ }
+
}
package org.sonar.server.qualitygate.ws;
import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
import org.json.simple.JSONValue;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.sonar.api.i18n.I18n;
import org.sonar.api.measures.Metric;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Map;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-@RunWith(MockitoJUnitRunner.class)
public class AppActionTest {
- @Mock
- private QualityGates qGates;
-
- @Mock
- private Periods periods;
-
- @Mock
- private I18n i18n;
+ private QualityGates qGates = mock(QualityGates.class);
+ private Periods periods = mock(Periods.class);
+ private I18n i18n = mock(I18n.class);
- WsTester tester;
+ WsTester ws;
@Before
public void setUp() {
SelectAction selectAction = new SelectAction(mock(DbClient.class), mock(UserSessionRule.class), mock(ComponentFinder.class));
- tester = new WsTester(new QualityGatesWs(
+ ws = new WsTester(new QualityGatesWs(
new ListAction(qGates), new ShowAction(qGates), new SearchAction(mock(QgateProjectFinder.class)),
new CreateAction(qGates), 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), new AppAction(qGates)));
+ selectAction, new DeselectAction(qGates, mock(DbClient.class), mock(ComponentFinder.class)), new AppAction(qGates)));
}
@Test
when(metric.isHidden()).thenReturn(false);
when(qGates.gateMetrics()).thenReturn(ImmutableList.of(metric));
- String json = tester.newGetRequest("api/qualitygates", "app").execute().outputAsString();
+ String json = ws.newGetRequest("api/qualitygates", "app").execute().outputAsString();
Map responseJson = (Map) JSONValue.parse(json);
assertThat((Boolean) responseJson.get("edit")).isFalse();
--- /dev/null
+/*
+ * 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 org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.Settings;
+import org.sonar.api.measures.MetricFinder;
+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.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualitygate.QualityGates;
+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;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
+
+public class DeselectActionTest {
+
+ @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();
+ ComponentDbTester componentDb = new ComponentDbTester(db);
+
+ QualityGates qualityGates = new QualityGates(dbClient, mock(MetricFinder.class), userSession, mock(Settings.class));
+
+ WsActionTester ws;
+
+ DeselectAction underTest;
+
+ @Before
+ public void setUp() {
+ ComponentFinder componentFinder = new ComponentFinder(dbClient);
+ underTest = new DeselectAction(qualityGates, dbClient, componentFinder);
+ ws = new WsActionTester(underTest);
+
+ userSession.login("login").setGlobalPermissions(QUALITY_GATE_ADMIN);
+ }
+
+ @Test
+ public void deselect_by_id() throws Exception {
+ ComponentDto project = insertProject();
+ ComponentDto anotherProject = componentDb.insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ associateProjectToQualityGate(project.getId(), gateId);
+ associateProjectToQualityGate(anotherProject.getId(), gateId);
+
+ callById(gateId, project.getId());
+
+ assertDeselected(project.getId());
+ assertSelected(gateId, anotherProject.getId());
+ }
+
+ @Test
+ public void deselect_by_uuid() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ associateProjectToQualityGate(project.getId(), gateId);
+
+ callByUuid(gateId, project.uuid());
+
+ assertDeselected(project.getId());
+ }
+
+ @Test
+ public void deselect_by_key() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ associateProjectToQualityGate(project.getId(), gateId);
+
+ callByKey(gateId, project.getKey());
+
+ assertDeselected(project.getId());
+ }
+
+ @Test
+ public void project_admin() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ associateProjectToQualityGate(project.getId(), gateId);
+
+ userSession.login("login").addProjectUuidPermissions(UserRole.ADMIN, project.uuid());
+
+ callByKey(gateId, project.getKey());
+
+ assertDeselected(project.getId());
+ }
+
+ @Test
+ public void system_admin() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ associateProjectToQualityGate(project.getId(), gateId);
+
+ userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
+
+ callByKey(gateId, project.getKey());
+
+ assertDeselected(project.getId());
+ }
+
+ @Test
+ public void fail_when_no_quality_gate() throws Exception {
+ ComponentDto project = insertProject();
+
+ expectedException.expect(NotFoundException.class);
+
+ callByKey("1", project.getKey());
+ }
+
+ @Test
+ public void fail_when_no_project_id() throws Exception {
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+
+ expectedException.expect(NotFoundException.class);
+
+ callById(gateId, 1L);
+ }
+
+ @Test
+ public void fail_when_no_project_key() throws Exception {
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+
+ expectedException.expect(NotFoundException.class);
+
+ callByKey(gateId, "unknown");
+ }
+
+ @Test
+ public void fail_when_anonymous() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+ userSession.anonymous();
+
+ expectedException.expect(ForbiddenException.class);
+ callByKey(gateId, project.getKey());
+ }
+
+ @Test
+ public void fail_when_not_project_admin() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+
+ userSession.login("login").addProjectUuidPermissions(UserRole.ISSUE_ADMIN, project.uuid());
+
+ expectedException.expect(ForbiddenException.class);
+
+ callByKey(gateId, project.getKey());
+ }
+
+ @Test
+ public void fail_when_not_quality_gates_admin() throws Exception {
+ ComponentDto project = insertProject();
+ QualityGateDto gate = insertQualityGate();
+ String gateId = String.valueOf(gate.getId());
+
+ userSession.login("login").setGlobalPermissions(QUALITY_PROFILE_ADMIN);
+
+ expectedException.expect(ForbiddenException.class);
+
+ callByKey(gateId, project.getKey());
+ }
+
+ private ComponentDto insertProject() {
+ return componentDb.insertComponent(newProjectDto());
+ }
+
+ private QualityGateDto insertQualityGate() {
+ QualityGateDto gate = new QualityGateDto().setName("Custom");
+ dbClient.qualityGateDao().insert(dbSession, gate);
+ dbSession.commit();
+ return gate;
+ }
+
+ private void callByKey(String gateId, String projectKey) {
+ ws.newRequest()
+ .setParam("gateId", String.valueOf(gateId))
+ .setParam("projectKey", projectKey)
+ .execute();
+ }
+
+ private void callById(String gateId, Long projectId) {
+ ws.newRequest()
+ .setParam("gateId", String.valueOf(gateId))
+ .setParam("projectId", String.valueOf(projectId))
+ .execute();
+ }
+
+ private void callByUuid(String gateId, String projectUuid) {
+ ws.newRequest()
+ .setParam("gateId", String.valueOf(gateId))
+ .setParam("projectId", projectUuid)
+ .execute();
+ }
+
+ private void associateProjectToQualityGate(long projectId, String gateId) {
+ dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto()
+ .setResourceId(projectId)
+ .setValue(gateId)
+ .setKey(SONAR_QUALITYGATE_PROPERTY));
+ db.commit();
+ }
+
+ private void assertDeselected(long projectId) {
+ assertThat(dbClient.propertiesDao().selectProjectProperty(projectId, SONAR_QUALITYGATE_PROPERTY)).isNull();
+ }
+
+ private void assertSelected(String qGateId, long projectId) {
+ assertThat(dbClient.propertiesDao().selectProjectProperty(projectId, SONAR_QUALITYGATE_PROPERTY).getValue()).isEqualTo(qGateId);
+ }
+}