Browse Source

SONAR-10087 Use protobuf in api/qualitygates/show

Also take the opportunity to move business from QualityGates to ShowAction
tags/7.0-RC1
Julien Lancelot 6 years ago
parent
commit
90bd3b0beb

+ 5
- 1
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.db.qualitygate;

import java.util.Arrays;
import java.util.function.Consumer;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
@@ -72,12 +74,14 @@ public class QualityGateDbTester {
db.commit();
}

public QualityGateConditionDto addCondition(QualityGateDto qualityGate, MetricDto metric) {
@SafeVarargs
public final QualityGateConditionDto addCondition(QualityGateDto qualityGate, MetricDto metric, Consumer<QualityGateConditionDto>... dtoPopulators) {
QualityGateConditionDto condition = new QualityGateConditionDto().setQualityGateId(qualityGate.getId())
.setMetricId(metric.getId())
.setOperator("GT")
.setWarningThreshold(randomNumeric(10))
.setErrorThreshold(randomNumeric(10));
Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(condition));
dbClient.gateConditionDao().insert(condition, dbSession);
db.commit();
return condition;

+ 19
- 11
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java View File

@@ -21,14 +21,15 @@ package org.sonar.server.qualitygate;

import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.exceptions.NotFoundException;

import static org.apache.commons.lang.StringUtils.isBlank;
import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
import static org.sonar.server.ws.WsUtils.checkFound;

public class QualityGateFinder {

@@ -47,7 +48,7 @@ public class QualityGateFinder {
public Optional<QualityGateData> getQualityGate(DbSession dbSession, long componentId) {
Optional<Long> qualityGateId = dbClient.projectQgateAssociationDao().selectQGateIdByComponentId(dbSession, componentId);
if (qualityGateId.isPresent()) {
return Optional.of(new QualityGateData(selectOrFailById(dbSession, qualityGateId.get()), false));
return Optional.of(new QualityGateData(getById(dbSession, qualityGateId.get()), false));
} else {
QualityGateDto defaultQualityGate = getDefault(dbSession);
if (defaultQualityGate == null) {
@@ -57,21 +58,27 @@ public class QualityGateFinder {
}
}

public QualityGateDto getById(DbSession dbSession, long qualityGateId) {
return checkFound(dbClient.qualityGateDao().selectById(dbSession, qualityGateId), "No quality gate has been found for id %s", qualityGateId);
}

public QualityGateDto getByNameOrId(DbSession dbSession, @Nullable String name, @Nullable Long id) {
if (name != null) {
return checkFound(dbClient.qualityGateDao().selectByName(dbSession, name), "No quality gate has been found for name %s", name);
}
if (id != null) {
return getById(dbSession, id);
}
throw new IllegalArgumentException("No parameter has been set to identify a quality gate");
}

@CheckForNull
private QualityGateDto getDefault(DbSession dbSession) {
Long defaultId = getDefaultId(dbSession);
if (defaultId == null) {
return null;
}
return selectOrFailById(dbSession, defaultId);
}

private QualityGateDto selectOrFailById(DbSession dbSession, long qualityGateId) {
QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectById(dbSession, qualityGateId);
if (qualityGateDto == null) {
throw new NotFoundException(String.format("No quality gate has been found for id %s", qualityGateId));
}
return qualityGateDto;
return getById(dbSession, defaultId);
}

@CheckForNull
@@ -101,4 +108,5 @@ public class QualityGateFinder {
return isDefault;
}
}

}

+ 2
- 35
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java View File

@@ -26,8 +26,6 @@ import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -47,11 +45,10 @@ import static java.lang.String.format;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
import static org.sonar.server.util.Validation.CANT_BE_EMPTY_MESSAGE;
import static org.sonar.server.util.Validation.IS_ALREADY_USED_MESSAGE;
import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonar.server.ws.WsUtils.checkRequest;

/**
* Methods from this class should be moved to {@link QualityGateUpdater} and to new classes QualityGateFinder / QualityGateConditionsUpdater / etc.
* Methods from this class should be moved to {@link QualityGateUpdater} and to classes QualityGateFinder / QualityGateConditionsUpdater / etc.
* in order to have classes with clearer responsibilities and more easily testable (without having to use too much mocks)
*/
public class QualityGates {
@@ -61,29 +58,19 @@ public class QualityGates {
private final DbClient dbClient;
private final QualityGateDao dao;
private final QualityGateConditionDao conditionDao;
private final MetricFinder metricFinder;
private final PropertiesDao propertiesDao;
private final UserSession userSession;
private final DefaultOrganizationProvider organizationProvider;

public QualityGates(DbClient dbClient, MetricFinder metricFinder, UserSession userSession, DefaultOrganizationProvider organizationProvider) {
public QualityGates(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider organizationProvider) {
this.dbClient = dbClient;
this.dao = dbClient.qualityGateDao();
this.conditionDao = dbClient.gateConditionDao();
this.metricFinder = metricFinder;
this.propertiesDao = dbClient.propertiesDao();
this.userSession = userSession;
this.organizationProvider = organizationProvider;
}

public QualityGateDto get(Long qGateId) {
return getNonNullQgate(qGateId);
}

public QualityGateDto get(String qGateName) {
return getNonNullQgate(qGateName);
}

public QualityGateDto rename(long idToRename, String name) {
checkIsQualityGateAdministrator();
try (DbSession dbSession = dbClient.openSession(false)) {
@@ -161,20 +148,6 @@ public class QualityGates {
}
}

public Collection<QualityGateConditionDto> listConditions(long qGateId) {
try (DbSession dbSession = dbClient.openSession(false)) {
Collection<QualityGateConditionDto> conditionsForGate = conditionDao.selectForQualityGate(dbSession, qGateId);
for (QualityGateConditionDto condition : conditionsForGate) {
Metric metric = metricFinder.findById((int) condition.getMetricId());
if (metric == null) {
throw new IllegalStateException("Could not find metric with id " + condition.getMetricId());
}
condition.setMetricKey(metric.getKey());
}
return conditionsForGate;
}
}

public void dissociateProject(DbSession dbSession, ComponentDto project) {
checkProjectAdmin(project);
propertiesDao.deleteProjectProperty(SONAR_QUALITYGATE_PROPERTY, project.getId(), dbSession);
@@ -207,12 +180,6 @@ public class QualityGates {
return qGate;
}

private QualityGateDto getNonNullQgate(String name) {
try (DbSession dbSession = dbClient.openSession(false)) {
return checkFound(dao.selectByName(dbSession, name), "There is no quality gate with name=%s", name);
}
}

private void validateQualityGate(DbSession dbSession, @Nullable Long updatingQgateId, @Nullable String name) {
List<String> errors = new ArrayList<>();
if (Strings.isNullOrEmpty(name)) {

+ 0
- 18
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java View File

@@ -105,22 +105,4 @@ public class QualityGatesWs implements WebService {
.endObject();
}

static JsonWriter writeQualityGateCondition(QualityGateConditionDto condition, JsonWriter writer) {
writer.beginObject()
.prop(PARAM_ID, condition.getId())
.prop(PARAM_METRIC, condition.getMetricKey())
.prop(PARAM_OPERATOR, condition.getOperator());
if (condition.getWarningThreshold() != null) {
writer.prop(PARAM_WARNING, condition.getWarningThreshold());
}
if (condition.getErrorThreshold() != null) {
writer.prop(PARAM_ERROR, condition.getErrorThreshold());
}
if (condition.getPeriod() != null) {
writer.prop(PARAM_PERIOD, condition.getPeriod());
}
writer.endObject();
return writer;
}

}

+ 67
- 27
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java View File

@@ -21,25 +21,39 @@ package org.sonar.server.qualitygate.ws;

import com.google.common.io.Resources;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
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.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.qualitygate.QualityGates;
import org.sonar.server.qualitygate.QualityGateFinder;
import org.sonarqube.ws.Qualitygates.ShowWsResponse;

import static org.sonar.server.ws.WsUtils.checkRequest;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_NAME;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class ShowAction implements QualityGatesWsAction {

private final QualityGates qualityGates;
private final DbClient dbClient;
private final QualityGateFinder qualityGateFinder;

public ShowAction(QualityGates qualityGates) {
this.qualityGates = qualityGates;
public ShowAction(DbClient dbClient, QualityGateFinder qualityGateFinder) {
this.dbClient = dbClient;
this.qualityGateFinder = qualityGateFinder;
}

@Override
@@ -47,7 +61,7 @@ public class ShowAction implements QualityGatesWsAction {
WebService.NewAction action = controller.createAction("show")
.setDescription("Display the details of a quality gate")
.setSince("4.3")
.setResponseExample(Resources.getResource(this.getClass(), "example-show.json"))
.setResponseExample(Resources.getResource(this.getClass(), "show-example.json"))
.setHandler(this);

action.createParam(PARAM_ID)
@@ -61,30 +75,56 @@ public class ShowAction implements QualityGatesWsAction {

@Override
public void handle(Request request, Response response) {
Long qGateId = request.paramAsLong(PARAM_ID);
String qGateName = request.param(PARAM_NAME);
checkOneOfIdOrNamePresent(qGateId, qGateName);
Long id = request.paramAsLong(PARAM_ID);
String name = request.param(PARAM_NAME);
checkOneOfIdOrNamePresent(id, name);

QualityGateDto qGate = qGateId == null ? qualityGates.get(qGateName) : qualityGates.get(qGateId);
qGateId = qGate.getId();

try (JsonWriter writer = response.newJsonWriter()) {
writer.beginObject()
.prop(PARAM_ID, qGate.getId())
.prop(PARAM_NAME, qGate.getName());
Collection<QualityGateConditionDto> conditions = qualityGates.listConditions(qGateId);
if (!conditions.isEmpty()) {
writer.name("conditions").beginArray();
for (QualityGateConditionDto condition : conditions) {
QualityGatesWs.writeQualityGateCondition(condition, writer);
}
writer.endArray();
}
writer.endObject().close();
try (DbSession dbSession = dbClient.openSession(false)) {
QualityGateDto qualityGate = qualityGateFinder.getByNameOrId(dbSession, name, id);
Collection<QualityGateConditionDto> conditions = getConditions(dbSession, qualityGate);
Map<Integer, MetricDto> metricsById = getMetricsById(dbSession, conditions);
writeProtobuf(buildResponse(qualityGate, conditions, metricsById), request, response);
}
}

public Collection<QualityGateConditionDto> getConditions(DbSession dbSession, QualityGateDto qualityGate) {
return dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getId());
}

private Map<Integer, MetricDto> getMetricsById(DbSession dbSession, Collection<QualityGateConditionDto> conditions) {
Set<Integer> metricIds = conditions.stream().map(c -> (int) c.getMetricId()).collect(toSet());
return dbClient.metricDao().selectByIds(dbSession, metricIds).stream()
.filter(MetricDto::isEnabled)
.collect(uniqueIndex(MetricDto::getId));
}

private static ShowWsResponse buildResponse(QualityGateDto qualityGate, Collection<QualityGateConditionDto> conditions, Map<Integer, MetricDto> metricsById) {
return ShowWsResponse.newBuilder()
.setId(qualityGate.getId())
.setName(qualityGate.getName())
.addAllConditions(conditions.stream()
.map(toWsCondition(metricsById))
.collect(toList()))
.build();
}

private static Function<QualityGateConditionDto, ShowWsResponse.Condition> toWsCondition(Map<Integer, MetricDto> metricsById) {
return condition -> {
int metricId = (int) condition.getMetricId();
MetricDto metric = metricsById.get(metricId);
checkState(metric != null, "Could not find metric with id %s", metricId);
ShowWsResponse.Condition.Builder builder = ShowWsResponse.Condition.newBuilder()
.setId(condition.getId())
.setMetric(metric.getKey())
.setOp(condition.getOperator());
setNullable(condition.getPeriod(), builder::setPeriod);
setNullable(condition.getErrorThreshold(), builder::setError);
setNullable(condition.getWarningThreshold(), builder::setWarning);
return builder.build();
};
}

private static void checkOneOfIdOrNamePresent(@Nullable Long qGateId, @Nullable String qGateName) {
checkRequest(qGateId == null ^ qGateName == null, "Either '%s' or '%s' must be provided", PARAM_ID, PARAM_NAME);
checkArgument(qGateId == null ^ qGateName == null, "Either '%s' or '%s' must be provided", PARAM_ID, PARAM_NAME);
}
}

server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-show.json → server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json View File

@@ -11,7 +11,8 @@
{
"id": 10,
"metric": "critical_violations",
"op": "GT",
"period": 1,
"op": "LT",
"warning": "0"
}
]

+ 49
- 18
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateFinderTest.java View File

@@ -27,7 +27,6 @@ import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.exceptions.NotFoundException;

@@ -39,16 +38,16 @@ public class QualityGateFinderTest {
public ExpectedException expectedException = ExpectedException.none();

@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
public DbTester db = DbTester.create(System2.INSTANCE);

private DbSession dbSession = dbTester.getSession();
private DbSession dbSession = db.getSession();

private QualityGateFinder underTest = new QualityGateFinder(dbTester.getDbClient());
private QualityGateFinder underTest = new QualityGateFinder(db.getDbClient());

@Test
public void return_default_quality_gate_for_project() {
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
ComponentDto project = db.components().insertPrivateProject();
QualityGateDto dbQualityGate = db.qualityGates().createDefaultQualityGate("Sonar way");

Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());

@@ -59,10 +58,10 @@ public class QualityGateFinderTest {

@Test
public void return_project_quality_gate_over_default() {
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()));
dbTester.qualityGates().createDefaultQualityGate("Sonar way");
QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
ComponentDto project = db.components().insertPrivateProject();
db.qualityGates().createDefaultQualityGate("Sonar way");
QualityGateDto dbQualityGate = db.qualityGates().insertQualityGate("My team QG");
db.qualityGates().associateProjectToQualityGate(project, dbQualityGate);

Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());

@@ -73,7 +72,7 @@ public class QualityGateFinderTest {

@Test
public void return_nothing_when_no_default_qgate_and_no_qgate_defined_for_project() {
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
ComponentDto project = db.components().insertPrivateProject();

Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());

@@ -82,9 +81,9 @@ public class QualityGateFinderTest {

@Test
public void fail_when_default_qgate_defined_in_properties_does_not_exists() throws Exception {
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()));
QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
ComponentDto project = db.components().insertPrivateProject();
QualityGateDto dbQualityGate = db.qualityGates().createDefaultQualityGate("Sonar way");
db.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);

expectedException.expect(NotFoundException.class);
underTest.getQualityGate(dbSession, project.getId());
@@ -92,12 +91,44 @@ public class QualityGateFinderTest {

@Test
public void fail_when_project_qgate_defined_in_properties_does_not_exists() throws Exception {
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
ComponentDto project = db.components().insertPrivateProject();
QualityGateDto dbQualityGate = db.qualityGates().insertQualityGate("My team QG");
db.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
db.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);

expectedException.expect(NotFoundException.class);
underTest.getQualityGate(dbSession, project.getId());
}

@Test
public void get_by_name_or_id() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();

assertThat(underTest.getByNameOrId(db.getSession(), qualityGate.getName(), null)).isNotNull();
assertThat(underTest.getByNameOrId(db.getSession(), null, qualityGate.getId())).isNotNull();
}

@Test
public void fail_get_by_name_or_id_when_name_matches_nothing() {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("No quality gate has been found for name UNKNOWN");

underTest.getByNameOrId(db.getSession(), "UNKNOWN", null);
}

@Test
public void fail_get_by_name_or_id_when_id_matches_nothing() {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("No quality gate has been found for id 123");

underTest.getByNameOrId(db.getSession(), null, 123L);
}

@Test
public void fail_get_by_name_or_id_when_parameters_are_null() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("No parameter has been set to identify a quality gate");

underTest.getByNameOrId(db.getSession(), null, null);
}
}

+ 1
- 88
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java View File

@@ -22,7 +22,6 @@ package org.sonar.server.qualitygate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
@@ -30,10 +29,6 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metric.ValueType;
import org.sonar.api.measures.MetricFinder;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -80,7 +75,6 @@ public class QualityGatesTest {
private QualityGateConditionDao conditionDao = mock(QualityGateConditionDao.class);
private PropertiesDao propertiesDao = mock(PropertiesDao.class);
private ComponentDao componentDao = mock(ComponentDao.class);
private MetricFinder metricFinder = mock(MetricFinder.class);
private QualityGates underTest;

@Before
@@ -94,7 +88,7 @@ public class QualityGatesTest {
when(componentDao.selectOrFailById(eq(dbSession), anyLong())).thenReturn(
newPrivateProjectDto(OrganizationTesting.newOrganizationDto(), PROJECT_UUID).setId(1L).setDbKey(PROJECT_KEY));

underTest = new QualityGates(dbClient, metricFinder, userSession, organizationProvider);
underTest = new QualityGates(dbClient, userSession, organizationProvider);

userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_GATES, organizationProvider.get().getUuid());
}
@@ -106,31 +100,6 @@ public class QualityGatesTest {
assertThat(underTest.list()).isEqualTo(allQgates);
}

@Test
public void should_get_qgate_by_id() {
long id = QUALITY_GATE_ID;
final String name = "Golden";
QualityGateDto existing = new QualityGateDto().setId(id).setName(name);
when(dao.selectById(dbSession, id)).thenReturn(existing);
assertThat(underTest.get(id)).isEqualTo(existing);
verify(dao).selectById(dbSession, id);
}

@Test
public void should_get_qgate_by_name() {
long id = QUALITY_GATE_ID;
final String name = "Golden";
QualityGateDto existing = new QualityGateDto().setId(id).setName(name);
when(dao.selectByName(dbSession, name)).thenReturn(existing);
assertThat(underTest.get(name)).isEqualTo(existing);
verify(dao).selectByName(dbSession, name);
}

@Test(expected = NotFoundException.class)
public void should_fail_to_find_qgate_by_name() {
underTest.get("Does not exist");
}

@Test
public void should_rename_qgate() {
long id = QUALITY_GATE_ID;
@@ -246,45 +215,6 @@ public class QualityGatesTest {
assertThat(underTest.getDefault()).isNull();
}

@Test
public void should_list_conditions() {
long qGateId = QUALITY_GATE_ID;
long metric1Id = 1L;
String metric1Key = "polop";
long metric2Id = 2L;
String metric2Key = "palap";
QualityGateConditionDto cond1 = new QualityGateConditionDto().setMetricId(metric1Id);
QualityGateConditionDto cond2 = new QualityGateConditionDto().setMetricId(metric2Id);
Collection<QualityGateConditionDto> conditions = ImmutableList.of(cond1, cond2);
when(conditionDao.selectForQualityGate(dbSession, qGateId)).thenReturn(conditions);
Metric metric1 = mock(Metric.class);
when(metric1.getKey()).thenReturn(metric1Key);
when(metricFinder.findById((int) metric1Id)).thenReturn(metric1);
Metric metric2 = mock(Metric.class);
when(metric2.getKey()).thenReturn(metric2Key);
when(metricFinder.findById((int) metric2Id)).thenReturn(metric2);
assertThat(underTest.listConditions(qGateId)).isEqualTo(conditions);
Iterator<QualityGateConditionDto> iterator = conditions.iterator();
assertThat(iterator.next().getMetricKey()).isEqualTo(metric1Key);
assertThat(iterator.next().getMetricKey()).isEqualTo(metric2Key);
}

@Test(expected = IllegalStateException.class)
public void should_do_a_sanity_check_when_listing_conditions() {
long qGateId = QUALITY_GATE_ID;
long metric1Id = 1L;
String metric1Key = "polop";
long metric2Id = 2L;
QualityGateConditionDto cond1 = new QualityGateConditionDto().setMetricId(metric1Id);
QualityGateConditionDto cond2 = new QualityGateConditionDto().setMetricId(metric2Id);
Collection<QualityGateConditionDto> conditions = ImmutableList.of(cond1, cond2);
when(conditionDao.selectForQualityGate(dbSession, qGateId)).thenReturn(conditions);
Metric metric1 = mock(Metric.class);
when(metric1.getKey()).thenReturn(metric1Key);
when(metricFinder.findById((int) metric1Id)).thenReturn(metric1);
underTest.listConditions(qGateId);
}

@Test
public void should_copy_qgate() {
String name = "Atlantis";
@@ -310,21 +240,4 @@ public class QualityGatesTest {
verify(conditionDao, times(conditions.size())).insert(any(QualityGateConditionDto.class), eq(dbSession));
}

@Test
public void should_list_gate_metrics() {
Metric dataMetric = mock(Metric.class);
when(dataMetric.isDataType()).thenReturn(true);
Metric hiddenMetric = mock(Metric.class);
when(hiddenMetric.isHidden()).thenReturn(true);
Metric nullHiddenMetric = mock(Metric.class);
when(nullHiddenMetric.isHidden()).thenReturn(null);
Metric alertMetric = CoreMetrics.ALERT_STATUS;
Metric ratingMetric = mock(Metric.class);
when(ratingMetric.getType()).thenReturn(ValueType.RATING);
Metric classicMetric = mock(Metric.class);
when(classicMetric.getType()).thenReturn(ValueType.BOOL);
when(metricFinder.findAll()).thenReturn(ImmutableList.of(
dataMetric, hiddenMetric, nullHiddenMetric, alertMetric, ratingMetric, classicMetric));
}

}

+ 2
- 5
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DeselectActionTest.java View File

@@ -23,7 +23,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
@@ -47,7 +46,6 @@ import org.sonar.server.ws.WsActionTester;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;

@@ -63,7 +61,7 @@ public class DeselectActionTest {
private DbClient dbClient = db.getDbClient();
private DbSession dbSession = db.getSession();
private TestDefaultOrganizationProvider organizationProvider = TestDefaultOrganizationProvider.from(db);
private QualityGates qualityGates = new QualityGates(dbClient, mock(MetricFinder.class), userSession, organizationProvider);
private QualityGates qualityGates = new QualityGates(dbClient, userSession, organizationProvider);
private WsActionTester ws;
private ComponentDto project;
private QualityGateDto gate;
@@ -87,8 +85,7 @@ public class DeselectActionTest {
assertThat(def.isPost()).isTrue();
assertThat(def.since()).isEqualTo("4.3");
assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactly(
tuple("6.6", "The parameter 'gateId' was removed")
);
tuple("6.6", "The parameter 'gateId' was removed"));

assertThat(def.params()).extracting(WebService.Param::key)
.containsExactlyInAnyOrder("projectId", "projectKey");

+ 1
- 58
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java View File

@@ -33,7 +33,6 @@ import org.sonar.api.server.ws.WebService.Controller;
import org.sonar.db.DbClient;
import org.sonar.db.qualitygate.ProjectQgateAssociation;
import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
@@ -70,7 +69,6 @@ public class QualityGatesWsTest {

tester = new WsTester(new QualityGatesWs(
new ListAction(qGates),
new ShowAction(qGates),
new SearchAction(projectFinder),
new CreateAction(null, null, null, null),
new CopyAction(qGates),
@@ -90,7 +88,7 @@ public class QualityGatesWsTest {
assertThat(controller).isNotNull();
assertThat(controller.path()).isEqualTo("api/qualitygates");
assertThat(controller.description()).isNotEmpty();
assertThat(controller.actions()).hasSize(15);
assertThat(controller.actions()).hasSize(14);

Action list = controller.action("list");
assertThat(list).isNotNull();
@@ -99,14 +97,6 @@ public class QualityGatesWsTest {
assertThat(list.isPost()).isFalse();
assertThat(list.isInternal()).isFalse();

Action show = controller.action("show");
assertThat(show).isNotNull();
assertThat(show.handler()).isNotNull();
assertThat(show.since()).isEqualTo("4.3");
assertThat(show.isPost()).isFalse();
assertThat(show.param("id")).isNotNull();
assertThat(show.isInternal()).isFalse();

Action create = controller.action("create");
assertThat(create).isNotNull();
assertThat(create.handler()).isNotNull();
@@ -258,53 +248,6 @@ public class QualityGatesWsTest {
"{\"qualitygates\":[{\"id\":42,\"name\":\"Golden\"},{\"id\":43,\"name\":\"Star\"},{\"id\":666,\"name\":\"Ninth\"}],\"default\":42}");
}

@Test
public void show_empty() throws Exception {
long gateId = 12345L;
when(qGates.get(gateId)).thenReturn(new QualityGateDto().setId(gateId).setName("Golden"));
tester.newGetRequest("api/qualitygates", "show").setParam("id", Long.toString(gateId)).execute().assertJson(
"{\"id\":12345,\"name\":\"Golden\"}");
}

@Test
public void show_by_id_nominal() throws Exception {
long gateId = 12345L;
when(qGates.get(gateId)).thenReturn(new QualityGateDto().setId(gateId).setName("Golden"));
when(qGates.listConditions(gateId)).thenReturn(ImmutableList.of(
new QualityGateConditionDto().setId(1L).setMetricKey("ncloc").setOperator("GT").setErrorThreshold("10000"),
new QualityGateConditionDto().setId(2L).setMetricKey("new_coverage").setOperator("LT").setWarningThreshold("90").setPeriod(3)));
tester.newGetRequest("api/qualitygates", "show").setParam("id", Long.toString(gateId)).execute().assertJson(
"{\"id\":12345,\"name\":\"Golden\",\"conditions\":["
+ "{\"id\":1,\"metric\":\"ncloc\",\"op\":\"GT\",\"error\":\"10000\"},"
+ "{\"id\":2,\"metric\":\"new_coverage\",\"op\":\"LT\",\"warning\":\"90\",\"period\":3}"
+ "]}");
}

@Test
public void show_by_name_nominal() throws Exception {
long qGateId = 12345L;
String gateName = "Golden";
when(qGates.get(gateName)).thenReturn(new QualityGateDto().setId(qGateId).setName(gateName));
when(qGates.listConditions(qGateId)).thenReturn(ImmutableList.of(
new QualityGateConditionDto().setId(1L).setMetricKey("ncloc").setOperator("GT").setErrorThreshold("10000"),
new QualityGateConditionDto().setId(2L).setMetricKey("new_coverage").setOperator("LT").setWarningThreshold("90").setPeriod(3)));
tester.newGetRequest("api/qualitygates", "show").setParam("name", gateName).execute().assertJson(
"{\"id\":12345,\"name\":\"Golden\",\"conditions\":["
+ "{\"id\":1,\"metric\":\"ncloc\",\"op\":\"GT\",\"error\":\"10000\"},"
+ "{\"id\":2,\"metric\":\"new_coverage\",\"op\":\"LT\",\"warning\":\"90\",\"period\":3}"
+ "]}");
}

@Test(expected = BadRequestException.class)
public void show_without_parameters() throws Exception {
tester.newGetRequest("api/qualitygates", "show").execute();
}

@Test(expected = BadRequestException.class)
public void show_with_both_parameters() throws Exception {
tester.newGetRequest("api/qualitygates", "show").setParam("id", "12345").setParam("name", "Polop").execute();
}

@Test
public void search_with_query() throws Exception {
long gateId = 12345L;

+ 160
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java View File

@@ -0,0 +1,160 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.qualitygate.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.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.qualitygate.QualityGateFinder;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Qualitygates.ShowWsResponse;
import org.sonarqube.ws.Qualitygates.ShowWsResponse.Condition;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
import static org.sonar.test.JsonAssert.assertJson;

public class ShowActionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

private WsActionTester ws = new WsActionTester(new ShowAction(db.getDbClient(), new QualityGateFinder(db.getDbClient())));

@Test
public void verify_definition() {
WebService.Action action = ws.getDef();
assertThat(action.since()).isEqualTo("4.3");
assertThat(action.changelog()).isEmpty();
assertThat(action.params())
.extracting(Param::key, Param::isRequired)
.containsExactlyInAnyOrder(tuple("id", false), tuple("name", false));
}

@Test
public void json_example() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate("My Quality Gate");
MetricDto blockerViolationsMetric = db.measures().insertMetric(m -> m.setKey("blocker_violations"));
MetricDto criticalViolationsMetric = db.measures().insertMetric(m -> m.setKey("critical_violations"));
db.qualityGates().addCondition(qualityGate, blockerViolationsMetric, c -> c.setOperator("GT").setPeriod(null).setErrorThreshold("0").setWarningThreshold(null));
db.qualityGates().addCondition(qualityGate, criticalViolationsMetric, c -> c.setOperator("LT").setPeriod(1).setErrorThreshold(null).setWarningThreshold("0"));

String response = ws.newRequest()
.setParam("name", qualityGate.getName())
.execute()
.getInput();

assertJson(response).ignoreFields("id")
.isSimilarTo(getClass().getResource("show-example.json"));
}

@Test
public void show() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
MetricDto metric = db.measures().insertMetric();
QualityGateConditionDto condition1 = db.qualityGates().addCondition(qualityGate, metric, c -> c.setOperator("GT").setPeriod(null));
QualityGateConditionDto condition2 = db.qualityGates().addCondition(qualityGate, metric, c -> c.setOperator("LT").setPeriod(1));

ShowWsResponse response = ws.newRequest().setParam("name", qualityGate.getName())
.executeProtobuf(ShowWsResponse.class);

assertThat(response.getId()).isEqualTo(qualityGate.getId());
assertThat(response.getName()).isEqualTo(qualityGate.getName());
assertThat(response.getConditionsList()).hasSize(2);
assertThat(response.getConditionsList())
.extracting(Condition::getId, Condition::getMetric, Condition::hasPeriod, Condition::getPeriod, Condition::getOp, Condition::getError, Condition::getWarning)
.containsExactlyInAnyOrder(
tuple(condition1.getId(), metric.getKey(), false, 0, "GT", condition1.getErrorThreshold(), condition1.getWarningThreshold()),
tuple(condition2.getId(), metric.getKey(), true, 1, "LT", condition2.getErrorThreshold(), condition2.getWarningThreshold()));
}

@Test
public void show_by_id() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();

ShowWsResponse response = ws.newRequest().setParam("id", qualityGate.getId().toString())
.executeProtobuf(ShowWsResponse.class);

assertThat(response.getId()).isEqualTo(qualityGate.getId());
assertThat(response.getName()).isEqualTo(qualityGate.getName());
}

@Test
public void no_condition() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();

ShowWsResponse response = ws.newRequest().setParam("name", qualityGate.getName())
.executeProtobuf(ShowWsResponse.class);

assertThat(response.getId()).isEqualTo(qualityGate.getId());
assertThat(response.getName()).isEqualTo(qualityGate.getName());
assertThat(response.getConditionsList()).isEmpty();
}

@Test
public void fail_when_no_name_or_id() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Either 'id' or 'name' must be provided");

ws.newRequest().execute();
}

@Test
public void fail_when_both_name_or_id() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Either 'id' or 'name' must be provided");

ws.newRequest()
.setParam("name", qualityGate.getName())
.setParam("id", qualityGate.getId().toString())
.execute();
}

@Test
public void fail_when_condition_is_on_disabled_metric() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
MetricDto metric = db.measures().insertMetric();
db.qualityGates().addCondition(qualityGate, metric);
db.getDbClient().metricDao().disableCustomByKey(db.getSession(), metric.getKey());
db.commit();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(format("Could not find metric with id %s", metric.getId()));

ws.newRequest()
.setParam("name", qualityGate.getName())
.execute();
}
}

+ 16
- 0
sonar-ws/src/main/protobuf/ws-qualitygates.proto View File

@@ -118,5 +118,21 @@ message UpdateConditionResponse {
optional int32 period = 6;
}

// GET api/qualitygates/show
message ShowWsResponse {
optional int64 id = 1;
optional string name = 2;
repeated Condition conditions = 3;

message Condition {
optional int64 id = 1;
optional string metric = 2;
optional int32 period = 3;
optional string op = 4;
optional string warning = 5;
optional string error = 6;
}
}




Loading…
Cancel
Save