Ver código fonte

SONAR-8325 Improve MeasureDao#selectByQuery performance

It now accepts either a list of projects or a project with a list of components, but no more a list of components of any projects

It's no more possible to query a list of any components, because when doing that the performance are very bad (it would probably requires to add a column PROJECT_MEASURES.PROJECT_UUID)
tags/6.2-RC1
Julien Lancelot 7 anos atrás
pai
commit
85bd0e6065

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java Ver arquivo

@@ -209,8 +209,8 @@ public class ComponentTreeDataLoader {
Map<Integer, MetricDto> metricsById = Maps.uniqueIndex(metrics, MetricDtoFunctions.toId());
MeasureQuery measureQuery = MeasureQuery.builder()
.setPersonId(developerId)
.setComponentUuids(componentUuids)
.setMetricIds(metricsById.keySet())
.setComponentUuids(baseComponent.projectUuid(), componentUuids)
.setMetricIds(new ArrayList<>(metricsById.keySet()))
.build();
List<MeasureDto> measureDtos = dbClient.measureDao().selectByQuery(dbSession, measureQuery);


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java Ver arquivo

@@ -153,7 +153,7 @@ public class SearchAction implements MeasuresWsAction {

private List<MeasureDto> searchMeasures() {
return dbClient.measureDao().selectByQuery(dbSession, MeasureQuery.builder()
.setComponentUuids(projects.stream().map(ComponentDto::uuid).collect(toList()))
.setProjectUuids(projects.stream().map(ComponentDto::uuid).collect(toList()))
.setMetricIds(metrics.stream().map(MetricDto::getId).collect(toList()))
.build());
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsDataLoader.java Ver arquivo

@@ -62,7 +62,7 @@ public class SearchMyProjectsDataLoader {
List<SnapshotDto> snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids);
MetricDto gateStatusMetric = dbClient.metricDao().selectOrFailByKey(dbSession, CoreMetrics.ALERT_STATUS_KEY);
MeasureQuery measureQuery = MeasureQuery.builder()
.setComponentUuids(projectUuids)
.setProjectUuids(projectUuids)
.setMetricId(gateStatusMetric.getId())
.build();
List<MeasureDto> qualityGates = dbClient.measureDao().selectByQuery(dbSession, measureQuery);

+ 2
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java Ver arquivo

@@ -48,6 +48,7 @@ import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Collections.singletonList;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.ws.WsUtils.checkRequest;
@@ -162,7 +163,7 @@ public class ProjectStatusAction implements QualityGatesWsAction {

private Optional<String> getQualityGateDetailsMeasureData(DbSession dbSession, ComponentDto project) {
MeasureQuery measureQuery = MeasureQuery.builder()
.setComponentUuid(project.projectUuid())
.setProjectUuids(singletonList(project.projectUuid()))
.setMetricKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY)
.build();
List<MeasureDto> measures = dbClient.measureDao().selectByQuery(dbSession, measureQuery);

+ 30
- 11
sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java Ver arquivo

@@ -41,8 +41,11 @@ public class MeasureDao implements Dao {

/**
* Selects the measures of either the last analysis (when {@link MeasureQuery#analysisUuid} is {@code null}) or of the
* specified analysis (given by {@link MeasureQuery#analysisUuid}) for the component UUIDs specified in
* {@link MeasureQuery#componentUuids}.
* specified analysis (given by {@link MeasureQuery#analysisUuid}).
* The components can be specified either as :
* - A list of projects in {@link MeasureQuery#projectUuids}
* - A list of components in {@link MeasureQuery#componentUuids} with one mandatory project in {@link MeasureQuery#projectUuids}
* - One single component in {@link MeasureQuery#componentUuids}
* <p>
* In addition, this method returns measures which are not associated to any developer, unless one is specified in
* {@link MeasureQuery#personId}.
@@ -56,22 +59,29 @@ public class MeasureDao implements Dao {
if (query.returnsEmpty()) {
return Collections.emptyList();
}
if (query.getComponentUuids() == null) {
return mapper(dbSession).selectByQuery(query);
if (query.getComponentUuids() != null) {
return executeLargeInputs(
query.getComponentUuids(),
componentUuids -> {
MeasureQuery pageQuery = MeasureQuery.copyWithSubsetOfComponentUuids(query, componentUuids);
return mapper(dbSession).selectByQuery(pageQuery);
});
} else if (query.getProjectUuids() != null) {
return executeLargeInputs(
query.getProjectUuids(),
projectUuids -> {
MeasureQuery pageQuery = MeasureQuery.copyWithSubsetOfProjectUuids(query, projectUuids);
return mapper(dbSession).selectByQuery(pageQuery);
});
}
return executeLargeInputs(query.getComponentUuids(), componentUuids -> {
MeasureQuery pageQuery = MeasureQuery.copyWithSubsetOfComponentUuids(query, componentUuids);
return mapper(dbSession).selectByQuery(pageQuery);
});
return mapper(dbSession).selectByQuery(query);
}

public void selectByQuery(DbSession dbSession, MeasureQuery query, ResultHandler resultHandler) {
if (query.returnsEmpty()) {
return;
}
if (query.getComponentUuids() == null) {
mapper(dbSession).selectByQuery(query, resultHandler);
} else {
if (query.getComponentUuids() != null) {
executeLargeInputsWithoutOutput(
query.getComponentUuids(),
componentUuids -> {
@@ -79,7 +89,16 @@ public class MeasureDao implements Dao {
mapper(dbSession).selectByQuery(pageQuery, resultHandler);
return null;
});
} else if (query.getProjectUuids() != null) {
executeLargeInputsWithoutOutput(
query.getProjectUuids(),
projectUuids -> {
MeasureQuery pageQuery = MeasureQuery.copyWithSubsetOfProjectUuids(query, projectUuids);
mapper(dbSession).selectByQuery(pageQuery, resultHandler);
return null;
});
}
mapper(dbSession).selectByQuery(query, resultHandler);
}

public List<PastMeasureDto> selectPastMeasures(DbSession dbSession,

+ 87
- 26
sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java Ver arquivo

@@ -19,39 +19,50 @@
*/
package org.sonar.db.measure;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.singleton;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;

public class MeasureQuery {
private final String analysisUuid;

@CheckForNull
private final List<String> projectUuids;

@CheckForNull
private final List<String> componentUuids;

@CheckForNull
private final Collection<Integer> metricIds;
private final List<Integer> metricIds;

@CheckForNull
private final Collection<String> metricKeys;
private final List<String> metricKeys;

@CheckForNull
private final Long personId;

private MeasureQuery(Builder builder) {
this(builder.analysisUuid, builder.componentUuids, builder.metricIds, builder.metricKeys, builder.personId);
this(builder.analysisUuid, builder.projectUuids, builder.componentUuids, builder.metricIds, builder.metricKeys, builder.personId);
}

private MeasureQuery(@Nullable String analysisUuid,
List<String> componentUuids,
@Nullable Collection<Integer> metricIds,
@Nullable Collection<String> metricKeys,
@Nullable List<String> projectUuids,
@Nullable List<String> componentUuids,
@Nullable List<Integer> metricIds,
@Nullable List<String> metricKeys,
@Nullable Long personId) {
requireNonNull(componentUuids, "Component UUIDs must be set");
checkState(metricIds == null || metricKeys == null, "Metric IDs and keys must not be set both");
checkArgument(metricIds == null || metricKeys == null, "Metric IDs and keys must not be set both");
checkArgument(projectUuids != null || componentUuids != null, "At least one filter on component UUID is expected");
checkArgument(componentUuids == null || componentUuids.size() == 1 || (projectUuids != null && projectUuids.size() == 1),
"Component UUIDs can only be used when a single project UUID is set");

this.analysisUuid = analysisUuid;
this.projectUuids = projectUuids;
this.componentUuids = componentUuids;
this.metricIds = metricIds;
this.metricKeys = metricKeys;
@@ -62,17 +73,33 @@ public class MeasureQuery {
return analysisUuid;
}

@CheckForNull
public List<String> getProjectUuids() {
return projectUuids;
}

@CheckForNull
public String getProjectUuid() {
return isOnComponents() ? projectUuids.get(0) : null;
}

@CheckForNull
public List<String> getComponentUuids() {
return componentUuids;
}

@CheckForNull
public Collection<Integer> getMetricIds() {
public String getComponentUuid() {
return isOnSingleComponent() ? componentUuids.get(0) : null;
}

@CheckForNull
public List<Integer> getMetricIds() {
return metricIds;
}

@CheckForNull
public Collection<String> getMetricKeys() {
public List<String> getMetricKeys() {
return metricKeys;
}

@@ -82,11 +109,24 @@ public class MeasureQuery {
}

public boolean returnsEmpty() {
return componentUuids.isEmpty()
return (projectUuids != null && projectUuids.isEmpty())
|| (componentUuids != null && componentUuids.isEmpty())
|| (metricIds != null && metricIds.isEmpty())
|| (metricKeys != null && metricKeys.isEmpty());
}

public boolean isOnProjects() {
return projectUuids != null && componentUuids == null;
}

public boolean isOnComponents() {
return projectUuids != null && projectUuids.size() == 1 && componentUuids != null;
}

public boolean isOnSingleComponent() {
return projectUuids == null && componentUuids != null && componentUuids.size() == 1;
}

@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
@@ -97,10 +137,11 @@ public class MeasureQuery {
}
MeasureQuery that = (MeasureQuery) o;
return Objects.equals(analysisUuid, that.analysisUuid) &&
Objects.equals(componentUuids, that.componentUuids) &&
Objects.equals(metricIds, that.metricIds) &&
Objects.equals(metricKeys, that.metricKeys) &&
Objects.equals(personId, that.personId);
Objects.equals(projectUuids, that.projectUuids) &&
Objects.equals(componentUuids, that.componentUuids) &&
Objects.equals(metricIds, that.metricIds) &&
Objects.equals(metricKeys, that.metricKeys) &&
Objects.equals(personId, that.personId);
}

@Override
@@ -112,15 +153,20 @@ public class MeasureQuery {
return new Builder();
}

static MeasureQuery copyWithSubsetOfProjectUuids(MeasureQuery query, List<String> projectUuids) {
return new MeasureQuery(query.analysisUuid, projectUuids, query.componentUuids, query.metricIds, query.metricKeys, query.personId);
}

static MeasureQuery copyWithSubsetOfComponentUuids(MeasureQuery query, List<String> componentUuids) {
return new MeasureQuery(query.analysisUuid, componentUuids, query.metricIds, query.metricKeys, query.personId);
return new MeasureQuery(query.analysisUuid, query.projectUuids, componentUuids, query.metricIds, query.metricKeys, query.personId);
}

public static final class Builder {
private String analysisUuid;
private List<String> projectUuids;
private List<String> componentUuids;
private Collection<Integer> metricIds;
private Collection<String> metricKeys;
private List<Integer> metricIds;
private List<String> metricKeys;
private Long personId;

private Builder() {
@@ -132,11 +178,26 @@ public class MeasureQuery {
return this;
}

public Builder setComponentUuids(List<String> componentUuids) {
/**
* List of projects
*/
public Builder setProjectUuids(@Nullable List<String> projectUuids) {
this.projectUuids = projectUuids;
return this;
}

/**
* List of components of a project
*/
public Builder setComponentUuids(String projectUuid, List<String> componentUuids) {
setProjectUuids(singletonList(requireNonNull(projectUuid)));
this.componentUuids = componentUuids;
return this;
}

/**
* Single component
*/
public Builder setComponentUuid(String componentUuid) {
this.componentUuids = singletonList(componentUuid);
return this;
@@ -145,26 +206,26 @@ public class MeasureQuery {
/**
* All the measures are returned if parameter is {@code null}.
*/
public Builder setMetricIds(@Nullable Collection<Integer> metricIds) {
public Builder setMetricIds(@Nullable List<Integer> metricIds) {
this.metricIds = metricIds;
return this;
}

public Builder setMetricId(int metricId) {
this.metricIds = singleton(metricId);
this.metricIds = singletonList(metricId);
return this;
}

/**
* All the measures are returned if parameter is {@code null}.
*/
public Builder setMetricKeys(@Nullable Collection<String> s) {
public Builder setMetricKeys(@Nullable List<String> s) {
this.metricKeys = s;
return this;
}

public Builder setMetricKey(String s) {
this.metricKeys = singleton(s);
this.metricKeys = singletonList(s);
return this;
}


+ 47
- 33
sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml Ver arquivo

@@ -29,41 +29,55 @@
select
<include refid="measureColumns"/>
from
project_measures pm
inner join projects p on p.uuid=pm.component_uuid
inner join snapshots analysis on analysis.component_uuid = p.project_uuid and analysis.uuid = pm.analysis_uuid
<if test="query.getMetricKeys() != null">
inner join metrics m on m.id = pm.metric_id
</if>
project_measures pm
inner join snapshots analysis on analysis.uuid = pm.analysis_uuid
<if test="query.isOnComponents()">
inner join projects p on p.project_uuid=analysis.component_uuid and p.uuid=pm.component_uuid
and p.project_uuid=#{query.projectUuid}
and p.uuid in
<foreach item="componentUuid" collection="query.getComponentUuids()" open="(" separator="," close=")">
#{componentUuid}
</foreach>
</if>
<if test="query.isOnSingleComponent()">
inner join projects p on p.project_uuid=analysis.component_uuid and p.uuid=pm.component_uuid
and p.uuid=#{query.componentUuid}
</if>
<if test="query.getMetricKeys() != null">
inner join metrics m on m.id = pm.metric_id
</if>
where
<if test="query.getAnalysisUuid() == null">
analysis.islast=${_true}
</if>
<if test="query.getAnalysisUuid() != null">
analysis.uuid = #{query.analysisUuid}
</if>
and p.uuid in
<foreach item="componentUuid" collection="query.getComponentUuids()" open="(" separator="," close=")">
#{componentUuid}
<if test="query.getAnalysisUuid() == null">
analysis.islast=${_true}
</if>
<if test="query.getAnalysisUuid() != null">
analysis.uuid = #{query.analysisUuid}
</if>
<if test="query.isOnProjects()">
and analysis.component_uuid=pm.component_uuid
and analysis.component_uuid in
<foreach item="projectUuid" collection="query.getProjectUuids()" open="(" separator="," close=")">
#{projectUuid}
</foreach>
<if test="query.getMetricIds() != null">
and pm.metric_id in
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId}</foreach>
</if>
<if test="query.getMetricKeys() != null">
and m.name in
<foreach item="metricKey" collection="query.getMetricKeys()" open="(" separator="," close=")">
#{metricKey}
</foreach>
</if>
<choose>
<when test="query.getPersonId() != null">
and person_id = #{query.personId}
</when>
<otherwise>
and person_id is null
</otherwise>
</choose>
</if>
<if test="query.getMetricIds() != null">
and pm.metric_id in
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId}</foreach>
</if>
<if test="query.getMetricKeys() != null">
and m.name in
<foreach item="metricKey" collection="query.getMetricKeys()" open="(" separator="," close=")">
#{metricKey}
</foreach>
</if>
<choose>
<when test="query.getPersonId() != null">
and person_id = #{query.personId}
</when>
<otherwise>
and person_id is null
</otherwise>
</choose>
</select>

<select id="selectPastMeasures" parameterType="map" resultType="org.sonar.db.measure.PastMeasureDto">

+ 68
- 18
sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java Ver arquivo

@@ -105,12 +105,24 @@ public class MeasureDaoTest {

@Test
public void selectByQuery() {
ComponentDto project = db.components().insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
ComponentDto project1 = db.components().insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project1));
db.components().insertComponent(newFileDto(module).setUuid("C1"));
db.components().insertComponent(newFileDto(module).setUuid("C2"));
insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true);
insertAnalysis(OTHER_ANALYSIS_UUID, project.uuid(), false);
insertAnalysis(LAST_ANALYSIS_UUID, project1.uuid(), true);
insertAnalysis(OTHER_ANALYSIS_UUID, project1.uuid(), false);

String project2LastAnalysisUuid = "P2_LAST_ANALYSIS";
ComponentDto project2 = db.components().insertProject();
insertAnalysis(project2LastAnalysisUuid, project2.uuid(), true);

// project 1
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID);
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), COVERAGE_METRIC_ID);
insertMeasure("P1_M3", OTHER_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID);
// project 2
insertMeasure("P2_M1", project2LastAnalysisUuid, project2.uuid(), NCLOC_METRIC_ID);
insertMeasure("P2_M2", project2LastAnalysisUuid, project2.uuid(), COVERAGE_METRIC_ID);
// component C1
insertMeasure("M1", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
@@ -121,8 +133,10 @@ public class MeasureDaoTest {
insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID);
db.commit();

verifyZeroMeasures(MeasureQuery.builder().setComponentUuids(emptyList()));
verifyZeroMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), emptyList()));
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("MISSING_COMPONENT"));
verifyZeroMeasures(MeasureQuery.builder().setProjectUuids(emptyList()));
verifyZeroMeasures(MeasureQuery.builder().setProjectUuids(singletonList("MISSING_COMPONENT")));

// all measures of component C1 of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1"), "M2", "M3");
@@ -153,11 +167,11 @@ public class MeasureDaoTest {
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID));

// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")), "M2", "M3", "M6");
verifyMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")), "M2", "M3", "M6");
// ncloc measures of components C1, C2 and C3 (which does not exist) of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
verifyMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3", "M6");
verifyMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3", "M6");

// measures of missing developer of component C1 of last analysis
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setPersonId(123L));
@@ -172,15 +186,38 @@ public class MeasureDaoTest {
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setPersonId(A_PERSON_ID));
// developer measures of component C1 of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setPersonId(A_PERSON_ID), "M4");

// projects measures of last analysis
verifyMeasures(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID), "P1_M1");
verifyMeasures(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid())).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)),
"P1_M1", "P2_M1", "P2_M2", "P2_M2");
verifyMeasures(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid(), "UNKNOWN")).setMetricId(NCLOC_METRIC_ID), "P1_M1", "P2_M1");

// projects measures of none last analysis
verifyMeasures(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(OTHER_ANALYSIS_UUID), "P1_M3");
verifyMeasures(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(OTHER_ANALYSIS_UUID), "P1_M3");
}

@Test
public void selectByQuery_with_handler() {
ComponentDto project = db.components().insertProject();
db.components().insertComponent(newFileDto(project).setUuid("C1"));
db.components().insertComponent(newFileDto(project).setUuid("C2"));
insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true);
insertAnalysis(OTHER_ANALYSIS_UUID, project.uuid(), false);
ComponentDto project1 = db.components().insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project1));
db.components().insertComponent(newFileDto(module).setUuid("C1"));
db.components().insertComponent(newFileDto(module).setUuid("C2"));
insertAnalysis(LAST_ANALYSIS_UUID, project1.uuid(), true);
insertAnalysis(OTHER_ANALYSIS_UUID, project1.uuid(), false);

String project2LastAnalysisUuid = "P2_LAST_ANALYSIS";
ComponentDto project2 = db.components().insertProject();
insertAnalysis(project2LastAnalysisUuid, project2.uuid(), true);

// project 1
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID);
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), COVERAGE_METRIC_ID);
insertMeasure("P1_M3", OTHER_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID);
// project 2
insertMeasure("P2_M1", project2LastAnalysisUuid, project2.uuid(), NCLOC_METRIC_ID);
insertMeasure("P2_M2", project2LastAnalysisUuid, project2.uuid(), COVERAGE_METRIC_ID);
// component C1
insertMeasure("M1", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
@@ -191,8 +228,10 @@ public class MeasureDaoTest {
insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID);
db.commit();

verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(emptyList()));
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(project1.uuid(), emptyList()));
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("MISSING_COMPONENT"));
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(emptyList()));
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(singletonList("MISSING_COMPONENT")));

// all measures of component C1 of last analysis
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("C1"), "M2", "M3");
@@ -224,11 +263,11 @@ public class MeasureDaoTest {
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID));

// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")), "M2", "M3", "M6");
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")), "M2", "M3", "M6");
// ncloc measures of components C1, C2 and C3 (which does not exist) of non last analysis
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis by UUID
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3", "M6");
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3", "M6");

// measures of missing developer of component C1 of last analysis
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("C1").setPersonId(123L));
@@ -243,6 +282,17 @@ public class MeasureDaoTest {
verifyZeroMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setPersonId(A_PERSON_ID));
// developer measures of component C1 of last analysis by UUID
verifyMeasuresWithHandler(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setPersonId(A_PERSON_ID), "M4");

// projects measures of last analysis
verifyMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID), "P1_M1");
verifyMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid())).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)),
"P1_M1", "P2_M1", "P2_M2", "P2_M2");
verifyMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid(), "UNKNOWN")).setMetricId(NCLOC_METRIC_ID), "P1_M1", "P2_M1");

// projects measures of none last analysis
verifyMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(OTHER_ANALYSIS_UUID), "P1_M3");
verifyMeasuresWithHandler(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(OTHER_ANALYSIS_UUID),
"P1_M3");
}

@Test
@@ -254,7 +304,7 @@ public class MeasureDaoTest {
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", COMPLEXITY_METRIC_ID);
db.commit();

assertThat(selectSingle(MeasureQuery.builder().setComponentUuids(emptyList()))).isNotPresent();
assertThat(selectSingle(MeasureQuery.builder().setComponentUuids(project.uuid(), emptyList()))).isNotPresent();
assertThat(selectSingle(MeasureQuery.builder().setComponentUuid("MISSING_COMPONENT"))).isNotPresent();

// select a single measure

+ 140
- 0
sonar-db/src/test/java/org/sonar/db/measure/MeasureQueryTest.java Ver arquivo

@@ -0,0 +1,140 @@
/*
* 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.db.measure;

import java.util.Collections;
import org.assertj.core.api.Java6Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

public class MeasureQueryTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void create_query_from_projects() throws Exception {
MeasureQuery query = MeasureQuery.builder().setProjectUuids(asList("PROJECT_1", "PROJECT_2")).build();

assertThat(query.getProjectUuids()).containsOnly("PROJECT_1", "PROJECT_2");
assertThat(query.isOnProjects()).isTrue();
assertThat(query.isOnComponents()).isFalse();
assertThat(query.isOnSingleComponent()).isFalse();
}

@Test
public void create_query_from_project_and_components() throws Exception {
MeasureQuery query = MeasureQuery.builder().setComponentUuids("PROJECT_1", asList("FILE_1", "FILE_2")).build();

assertThat(query.getProjectUuids()).containsOnly("PROJECT_1");
assertThat(query.getProjectUuid()).isEqualTo("PROJECT_1");
assertThat(query.getComponentUuids()).containsOnly("FILE_1", "FILE_2");
assertThat(query.isOnProjects()).isFalse();
assertThat(query.isOnComponents()).isTrue();
assertThat(query.isOnSingleComponent()).isFalse();
}

@Test
public void create_query_from_single_component_uuid() throws Exception {
MeasureQuery query = MeasureQuery.builder().setComponentUuid("FILE_1").build();

assertThat(query.getComponentUuids()).containsOnly("FILE_1");
assertThat(query.getComponentUuid()).isEqualTo("FILE_1");
assertThat(query.isOnProjects()).isFalse();
assertThat(query.isOnComponents()).isFalse();
assertThat(query.isOnSingleComponent()).isTrue();
}

@Test
public void create_query_from_metric_ids() throws Exception {
MeasureQuery query = MeasureQuery.builder().setProjectUuids(asList("PROJECT_1", "PROJECT_2")).setMetricIds(asList(10, 11)).build();

assertThat(query.getMetricIds()).containsOnly(10, 11);
assertThat(query.getMetricKeys()).isNull();
}

@Test
public void create_query_from_metric_keys() throws Exception {
MeasureQuery query = MeasureQuery.builder().setProjectUuids(asList("PROJECT_1", "PROJECT_2")).setMetricKeys(asList("M1", "M2")).build();

assertThat(query.getMetricKeys()).containsOnly("M1", "M2");
assertThat(query.getMetricIds()).isNull();
}

@Test
public void create_query_from_person_id() throws Exception {
MeasureQuery query = MeasureQuery.builder().setProjectUuids(asList("PROJECT_1", "PROJECT_2")).setPersonId(100L).build();

assertThat(query.getPersonId()).isEqualTo(100L);
}

@Test
public void return_empty_when_metrics_are_empty() throws Exception {
Java6Assertions.assertThat(MeasureQuery.builder()
.setProjectUuids(asList("PROJECT_1", "PROJECT_2"))
.setMetricKeys(Collections.emptyList())
.build().returnsEmpty()).isTrue();

Java6Assertions.assertThat(MeasureQuery.builder()
.setProjectUuids(asList("PROJECT_1", "PROJECT_2"))
.setMetricIds(Collections.emptyList())
.build().returnsEmpty()).isTrue();
}

@Test
public void return_empty_when_projects_are_empty() throws Exception {
Java6Assertions.assertThat(MeasureQuery.builder()
.setProjectUuids(Collections.emptyList())
.build().returnsEmpty()).isTrue();
}

@Test
public void return_empty_when_components_are_empty() throws Exception {
Java6Assertions.assertThat(MeasureQuery.builder()
.setComponentUuids("PROJECT", Collections.emptyList())
.build().returnsEmpty()).isTrue();
}

@Test
public void fail_when_no_component_uuid_filter() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At least one filter on component UUID is expected");
MeasureQuery.builder().build();
}

@Test
public void fail_when_component_uuids_without_project_uuid() throws Exception {
expectedException.expect(NullPointerException.class);
MeasureQuery.builder().setComponentUuids(null, asList("FILE_1", "FILE_2")).build();
}

@Test
public void fail_when_using_metric_ids_and_metric_keys() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Metric IDs and keys must not be set both");
MeasureQuery.builder().setMetricIds(asList(10, 11)).setMetricKeys(asList("M1", "M2")).setProjectUuids(asList("PROJECT_1", "PROJECT_2")).build();
}

}

Carregando…
Cancelar
Salvar