aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-db
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-11-04 15:05:13 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-11-08 11:12:51 +0100
commitc654cda21f67a65da5528a56653ecae721484f04 (patch)
treef9c21b6b923d975eb197f493ddbacfc196f5a019 /sonar-db
parentb67b21e7324e78bab3876f460cfe426455b2d367 (diff)
downloadsonarqube-c654cda21f67a65da5528a56653ecae721484f04.tar.gz
sonarqube-c654cda21f67a65da5528a56653ecae721484f04.zip
SONAR-8089 Create new MeasureDao#selectTreeByQuery
Diffstat (limited to 'sonar-db')
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java1
-rw-r--r--sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java8
-rw-r--r--sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java3
-rw-r--r--sonar-db/src/main/java/org/sonar/db/measure/MeasureTreeQuery.java158
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml26
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml38
-rw-r--r--sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/component/ComponentTreeQueryTest.java55
-rw-r--r--sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java84
-rw-r--r--sonar-db/src/test/java/org/sonar/db/measure/MeasureTreeQueryTest.java123
13 files changed, 462 insertions, 42 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
index 62c4652b05d..16e4dab6eac 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
@@ -175,7 +175,7 @@ public class ComponentDao implements Dao {
return emptyList();
}
ComponentDto component = componentOpt.get();
- return mapper(dbSession).selectDescendants(query, query.getUuidPath(component));
+ return mapper(dbSession).selectDescendants(query, componentOpt.get().uuid(), query.getUuidPath(component));
}
public ComponentDto selectOrFailByKey(DbSession session, String key) {
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
index 7e41d5c97b4..6badff92945 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
@@ -64,7 +64,7 @@ public interface ComponentMapper {
List<ComponentDto> selectAncestors(@Param("query") ComponentTreeQuery query, @Param("baseUuidPathLike") String baseUuidPathLike);
- List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuidPath") String baseUuidPath);
+ List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuid") String baseUuid, @Param("baseUuidPath") String baseUuidPath);
/**
* Return all project (PRJ/TRK) uuids
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
index c8f47f6cd75..dff3bc31448 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
@@ -68,6 +68,7 @@ public class ComponentTreeQuery {
this.sqlSort = builder.sortFields != null ? sortFieldsToSqlSort(builder.sortFields, direction) : null;
}
+ @CheckForNull
public Collection<String> getQualifiers() {
return qualifiers;
}
diff --git a/sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java b/sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java
index 9deba33c76c..0daf18d49b1 100644
--- a/sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java
@@ -28,6 +28,7 @@ import java.util.Optional;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput;
@@ -103,6 +104,13 @@ public class MeasureDao implements Dao {
mapper(dbSession).selectByQueryOnSingleComponent(query, resultHandler);
}
+ public List<MeasureDto> selectTreeByQuery(DbSession dbSession, ComponentDto baseComponent, MeasureTreeQuery query) {
+ if (query.returnsEmpty()) {
+ return Collections.emptyList();
+ }
+ return mapper(dbSession).selectTreeByQuery(query, baseComponent.uuid(), query.getUuidPath(baseComponent));
+ }
+
public List<PastMeasureDto> selectPastMeasures(DbSession dbSession,
String componentUuid,
String analysisUuid,
diff --git a/sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java b/sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java
index 7b385815f20..978b8b0c47c 100644
--- a/sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java
@@ -38,6 +38,8 @@ public interface MeasureMapper {
void selectByQueryOnSingleComponent(@Param("query") MeasureQuery query, ResultHandler resultHandler);
+ List<MeasureDto> selectTreeByQuery(@Param("query") MeasureTreeQuery measureQuery, @Param("baseUuid") String baseUuid, @Param("baseUuidPath") String baseUuidPath);
+
List<PastMeasureDto> selectPastMeasures(@Param("componentUuid") String componentUuid, @Param("analysisUuid") String analysisUuid, @Param("metricIds") List<Integer> metricIds);
List<MeasureDto> selectProjectMeasuresOfDeveloper(@Param("developerId") long developerId, @Param("metricIds") Collection<Integer> metricIds);
diff --git a/sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java b/sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java
index 382c44f5313..ec557a7b746 100644
--- a/sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java
+++ b/sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java
@@ -29,6 +29,7 @@ import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
public class MeasureQuery {
+ @CheckForNull
private final String analysisUuid;
@CheckForNull
@@ -136,7 +137,7 @@ public class MeasureQuery {
return false;
}
MeasureQuery that = (MeasureQuery) o;
- return analysisUuid.equals(that.analysisUuid) &&
+ return Objects.equals(analysisUuid, that.analysisUuid) &&
Objects.equals(projectUuids, that.projectUuids) &&
Objects.equals(componentUuids, that.componentUuids) &&
Objects.equals(metricIds, that.metricIds) &&
diff --git a/sonar-db/src/main/java/org/sonar/db/measure/MeasureTreeQuery.java b/sonar-db/src/main/java/org/sonar/db/measure/MeasureTreeQuery.java
new file mode 100644
index 00000000000..8ccd5a6a85d
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/measure/MeasureTreeQuery.java
@@ -0,0 +1,158 @@
+/*
+ * 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.Collection;
+import java.util.Locale;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.WildcardPosition;
+import org.sonar.db.component.ComponentDto;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.db.DatabaseUtils.buildLikeValue;
+import static org.sonar.db.WildcardPosition.AFTER;
+
+public class MeasureTreeQuery {
+
+ public enum Strategy {
+ CHILDREN, LEAVES
+ }
+
+ @CheckForNull
+ private final String nameOrKeyQuery;
+ // SONAR-7681 a public implementation of List must be used in MyBatis - potential concurrency exceptions otherwise
+ @CheckForNull
+ private final Collection<String> qualifiers;
+ private final Strategy strategy;
+
+ @CheckForNull
+ private final Collection<Integer> metricIds;
+
+ @CheckForNull
+ private final Long personId;
+
+ private MeasureTreeQuery(Builder builder) {
+ this.nameOrKeyQuery = builder.nameOrKeyQuery;
+ this.qualifiers = builder.qualifiers == null ? null : newArrayList(builder.qualifiers);
+ this.strategy = requireNonNull(builder.strategy);
+ this.metricIds = builder.metricIds;
+ this.personId = builder.personId;
+ }
+
+ @CheckForNull
+ public String getNameOrKeyQuery() {
+ return nameOrKeyQuery;
+ }
+
+ @CheckForNull
+ public String getNameOrKeyQueryToSqlForResourceIndex() {
+ return nameOrKeyQuery == null ? null : buildLikeValue(nameOrKeyQuery, AFTER).toLowerCase(Locale.ENGLISH);
+ }
+
+ @CheckForNull
+ public Collection<String> getQualifiers() {
+ return qualifiers;
+ }
+
+ public Strategy getStrategy() {
+ return strategy;
+ }
+
+ @CheckForNull
+ public Collection<Integer> getMetricIds() {
+ return metricIds;
+ }
+
+ @CheckForNull
+ public Long getPersonId() {
+ return personId;
+ }
+
+ public String getUuidPath(ComponentDto component) {
+ switch (strategy) {
+ case CHILDREN:
+ return component.getUuidPath() + component.uuid() + ".";
+ case LEAVES:
+ return buildLikeValue(component.getUuidPath() + component.uuid() + ".", WildcardPosition.AFTER);
+ default:
+ throw new IllegalArgumentException("Unknown strategy : " + strategy);
+ }
+ }
+
+ public boolean returnsEmpty() {
+ return (metricIds != null && metricIds.isEmpty()) || (qualifiers != null && qualifiers.isEmpty());
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+
+ @CheckForNull
+ private String nameOrKeyQuery;
+ @CheckForNull
+ private Collection<String> qualifiers;
+ private Strategy strategy;
+
+ @CheckForNull
+ private Collection<Integer> metricIds;
+
+ @CheckForNull
+ private Long personId;
+
+ private Builder() {
+ }
+
+ public Builder setNameOrKeyQuery(@Nullable String nameOrKeyQuery) {
+ this.nameOrKeyQuery = nameOrKeyQuery;
+ return this;
+ }
+
+ public Builder setQualifiers(Collection<String> qualifiers) {
+ this.qualifiers = qualifiers;
+ return this;
+ }
+
+ public Builder setStrategy(Strategy strategy) {
+ this.strategy = requireNonNull(strategy);
+ return this;
+ }
+
+ /**
+ * All the measures are returned if parameter is {@code null}.
+ */
+ public Builder setMetricIds(@Nullable Collection<Integer> metricIds) {
+ this.metricIds = metricIds;
+ return this;
+ }
+
+ public Builder setPersonId(@Nullable Long personId) {
+ this.personId = personId;
+ return this;
+ }
+
+ public MeasureTreeQuery build() {
+ return new MeasureTreeQuery(this);
+ }
+ }
+}
diff --git a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
index 8a3aa4973a9..4ca89c19d30 100644
--- a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
@@ -334,23 +334,23 @@
<select id="selectDescendants" resultType="Component">
select
<include refid="componentColumns"/>
- <include refid="selectDescendantsQuery"/>
- </select>
-
- <sql id="selectDescendantsQuery">
from projects p
- inner join projects base on base.project_uuid = p.project_uuid and base.uuid = #{query.baseUuid}
+ <include refid="selectDescendantsJoins"/>
<where>
- <choose>
- <when test="query.getStrategy().name() == 'CHILDREN'">
- and p.uuid_path = #{baseUuidPath}
- </when>
- <otherwise>
- and p.uuid_path like #{baseUuidPath} ESCAPE '/'
- </otherwise>
- </choose>
<include refid="selectDescendantsFilters"/>
</where>
+ </select>
+
+ <sql id="selectDescendantsJoins">
+ inner join projects base on base.project_uuid = p.project_uuid and base.uuid = #{baseUuid}
+ <choose>
+ <when test="query.getStrategy().name() == 'CHILDREN'">
+ and p.uuid_path = #{baseUuidPath}
+ </when>
+ <otherwise>
+ and p.uuid_path like #{baseUuidPath} ESCAPE '/'
+ </otherwise>
+ </choose>
</sql>
<sql id="selectDescendantsFilters">
diff --git a/sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml b/sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
index 00534d151eb..61b1268b219 100644
--- a/sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
@@ -85,14 +85,48 @@
</if>
<choose>
<when test="query.getPersonId() != null">
- and person_id = #{query.personId}
+ and pm.person_id = #{query.personId}
</when>
<otherwise>
- and person_id is null
+ and pm.person_id is null
</otherwise>
</choose>
</sql>
+ <select id="selectTreeByQuery" parameterType="map" resultType="Measure">
+ select <include refid="measureColumns"/> from project_measures pm
+ inner join snapshots analysis on analysis.uuid = pm.analysis_uuid
+ inner join projects p on p.project_uuid=analysis.component_uuid and p.uuid=pm.component_uuid
+ <include refid="org.sonar.db.component.ComponentMapper.selectDescendantsJoins"/>
+ <where>
+ <include refid="selectTreeByQueryFilters"/>
+ </where>
+ -- Add measures of base component
+ union all
+ select <include refid="measureColumns"/> from project_measures pm
+ inner join snapshots analysis on analysis.uuid = pm.analysis_uuid
+ inner join projects p on p.project_uuid=analysis.component_uuid and p.uuid=pm.component_uuid and pm.component_uuid=#{baseUuid}
+ <where>
+ <include refid="selectTreeByQueryFilters"/>
+ </where>
+ </select>
+
+ <sql id="selectTreeByQueryFilters">
+ <if test="query.getMetricIds() != null">
+ and pm.metric_id in
+ <foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId}</foreach>
+ </if>
+ <choose>
+ <when test="query.getPersonId() != null">
+ and pm.person_id = #{query.personId}
+ </when>
+ <otherwise>
+ and pm.person_id is null
+ </otherwise>
+ </choose>
+ <include refid="org.sonar.db.component.ComponentMapper.selectDescendantsFilters"/>
+ </sql>
+
<select id="selectPastMeasures" parameterType="map" resultType="org.sonar.db.measure.PastMeasureDto">
select pm.id as id, pm.metric_id as metricId, pm.person_id as personId, pm.value as value
from project_measures pm
diff --git a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
index 70f3e206e23..a74b0460405 100644
--- a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
@@ -948,7 +948,7 @@ public class ComponentDaoTest {
}
@Test
- public void select_descendants_with_leaves_stragegy() {
+ public void select_descendants_with_leaves_strategy() {
ComponentDto project = newProjectDto(PROJECT_UUID);
componentDb.insertProjectAndSnapshot(project);
componentDb.insertComponent(newModuleDto("module-1-uuid", project));
diff --git a/sonar-db/src/test/java/org/sonar/db/component/ComponentTreeQueryTest.java b/sonar-db/src/test/java/org/sonar/db/component/ComponentTreeQueryTest.java
index 44795f230a0..405f6a5449d 100644
--- a/sonar-db/src/test/java/org/sonar/db/component/ComponentTreeQueryTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/component/ComponentTreeQueryTest.java
@@ -23,42 +23,67 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Collections.singletonList;
+import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN;
+import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES;
public class ComponentTreeQueryTest {
- private static final String AN_UUID = "u1";
-
+ private static final String BASE_UUID = "ABCD";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
- public void convert_sorts_in_sql_representation() {
- ComponentTreeQuery result = ComponentTreeQuery.builder()
- .setBaseUuid(AN_UUID)
- .setSortFields(newArrayList("name", "path", "qualifier"))
+ public void create_query() throws Exception {
+ ComponentTreeQuery query = ComponentTreeQuery.builder()
+ .setBaseUuid(BASE_UUID)
+ .setStrategy(CHILDREN)
+ .setQualifiers(asList("FIL", "DIR"))
+ .setNameOrKeyQuery("teSt")
.build();
- assertThat(result.getSqlSort()).isEqualTo("LOWER(p.name) ASC, p.name ASC, LOWER(p.path) ASC, p.path ASC, LOWER(p.qualifier) ASC, p.qualifier ASC");
+ assertThat(query.getBaseUuid()).isEqualTo(BASE_UUID);
+ assertThat(query.getStrategy()).isEqualTo(CHILDREN);
+ assertThat(query.getQualifiers()).containsOnly("FIL", "DIR");
+ assertThat(query.getNameOrKeyQuery()).isEqualTo("teSt");
}
@Test
- public void fail_if_no_base_uuid() {
- expectedException.expect(NullPointerException.class);
+ public void create_minimal_query() throws Exception {
+ ComponentTreeQuery query = ComponentTreeQuery.builder()
+ .setBaseUuid(BASE_UUID)
+ .setStrategy(CHILDREN)
+ .build();
+
+ assertThat(query.getBaseUuid()).isEqualTo(BASE_UUID);
+ assertThat(query.getStrategy()).isEqualTo(CHILDREN);
+ assertThat(query.getQualifiers()).isNull();
+ assertThat(query.getNameOrKeyQuery()).isNull();
+ }
+
+ @Test
+ public void test_getUuidPath() throws Exception {
+ assertThat(ComponentTreeQuery.builder().setBaseUuid(BASE_UUID).setStrategy(CHILDREN)
+ .build().getUuidPath(ComponentTesting.newProjectDto("PROJECT_UUID"))).isEqualTo(".PROJECT_UUID.");
+
+ assertThat(ComponentTreeQuery.builder().setBaseUuid(BASE_UUID).setStrategy(LEAVES)
+ .build().getUuidPath(ComponentTesting.newProjectDto("PROJECT_UUID"))).isEqualTo(".PROJECT/_UUID.%");
+ }
+ @Test
+ public void fail_when_no_base_uuid() throws Exception {
+ expectedException.expect(NullPointerException.class);
ComponentTreeQuery.builder()
- .setSortFields(singletonList("name"))
+ .setStrategy(CHILDREN)
.build();
}
@Test
- public void fail_if_no_sort() {
+ public void fail_when_no_strategy() throws Exception {
expectedException.expect(NullPointerException.class);
-
ComponentTreeQuery.builder()
- .setBaseUuid(AN_UUID)
+ .setBaseUuid(BASE_UUID)
.build();
}
}
diff --git a/sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java b/sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java
index af492d3666f..beddaf6c737 100644
--- a/sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java
@@ -27,21 +27,26 @@ import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactoryImpl;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.SnapshotTesting;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.resources.Qualifiers.FILE;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
+import static org.sonar.api.resources.Qualifiers.VIEW;
import static org.sonar.db.component.ComponentTesting.newDeveloper;
import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
+import static org.sonar.db.measure.MeasureTreeQuery.Strategy.CHILDREN;
+import static org.sonar.db.measure.MeasureTreeQuery.Strategy.LEAVES;
public class MeasureDaoTest {
@@ -51,10 +56,11 @@ public class MeasureDaoTest {
private static final long A_PERSON_ID = 444L;
private static final String LAST_ANALYSIS_UUID = "A1";
private static final String OTHER_ANALYSIS_UUID = "A2";
- public static final String PREVIOUS_ANALYSIS_UUID = "previous analysis UUID";
+ private static final String PREVIOUS_ANALYSIS_UUID = "previous analysis UUID";
@Rule
public ExpectedException expectedException = ExpectedException.none();
+
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@@ -106,7 +112,7 @@ public class MeasureDaoTest {
@Test
public void selectByQuery() {
ComponentDto project1 = db.components().insertProject();
- ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project1));
+ ComponentDto module = db.components().insertComponent(newModuleDto(project1));
db.components().insertComponent(newFileDto(module).setUuid("C1"));
db.components().insertComponent(newFileDto(module).setUuid("C2"));
insertAnalysis(LAST_ANALYSIS_UUID, project1.uuid(), true);
@@ -201,7 +207,7 @@ public class MeasureDaoTest {
@Test
public void selectByQuery_with_handler() {
ComponentDto project1 = db.components().insertProject();
- ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project1));
+ ComponentDto module = db.components().insertComponent(newModuleDto(project1));
db.components().insertComponent(newFileDto(module).setUuid("C1"));
db.components().insertComponent(newFileDto(module).setUuid("C2"));
insertAnalysis(LAST_ANALYSIS_UUID, project1.uuid(), true);
@@ -325,9 +331,9 @@ public class MeasureDaoTest {
long developerId = dev.getId();
assertThat(underTest.selectProjectMeasuresOfDeveloper(db.getSession(), developerId, allMetricIds)).isEmpty();
- String projectUuid = insertComponent(Scopes.PROJECT, Qualifiers.PROJECT, true);
- String viewUuid = insertComponent(Scopes.PROJECT, Qualifiers.VIEW, true);
- String disabledProjectUuid = insertComponent(Scopes.PROJECT, Qualifiers.PROJECT, false);
+ String projectUuid = insertComponent(Scopes.PROJECT, PROJECT, true);
+ String viewUuid = insertComponent(Scopes.PROJECT, VIEW, true);
+ String disabledProjectUuid = insertComponent(Scopes.PROJECT, PROJECT, false);
insertMeasure("M1", LAST_ANALYSIS_UUID, projectUuid, NCLOC_METRIC_ID);
insertMeasure("M2", LAST_ANALYSIS_UUID, projectUuid, COMPLEXITY_METRIC_ID);
insertMeasure("M3", LAST_ANALYSIS_UUID, projectUuid, COVERAGE_METRIC_ID);
@@ -355,6 +361,58 @@ public class MeasureDaoTest {
.containsOnly("M11", "M54");
}
+ @Test
+ public void select_tree_by_query() {
+ ComponentDto project = db.components().insertProject();
+ ComponentDto module1 = db.components().insertComponent(newModuleDto(project));
+ ComponentDto module2 = db.components().insertComponent(newModuleDto(project));
+ ComponentDto file1 = db.components().insertComponent(newFileDto(module1).setUuid("C1").setName("File One"));
+ db.components().insertComponent(newFileDto(module2).setUuid("C2").setName("File Two").setQualifier(UNIT_TEST_FILE));
+ insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true);
+ db.components().indexAllComponents();
+
+ // project
+ insertMeasure("PROJECT_M1", LAST_ANALYSIS_UUID, project.uuid(), NCLOC_METRIC_ID);
+ // module 1
+ insertMeasure("MODULE_M1", LAST_ANALYSIS_UUID, module1.uuid(), NCLOC_METRIC_ID);
+ // component C1
+ insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
+ insertMeasure("M3", LAST_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID);
+ insertMeasureOnPerson("M4", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, A_PERSON_ID);
+ // component C2
+ insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID);
+ db.commit();
+
+ // Children measures of project
+ verifyMeasures(project, MeasureTreeQuery.builder().setStrategy(CHILDREN), "PROJECT_M1", "MODULE_M1");
+
+ // Children measures of module 1
+ verifyMeasures(module1, MeasureTreeQuery.builder().setStrategy(CHILDREN), "M2", "M3", "MODULE_M1");
+
+ // Children measure on file => only measures from itself
+ verifyMeasures(file1, MeasureTreeQuery.builder().setStrategy(CHILDREN), "M2", "M3");
+
+ // Leaves measures of project
+ verifyMeasures(project, MeasureTreeQuery.builder().setStrategy(LEAVES), "PROJECT_M1", "MODULE_M1", "M2", "M3", "M6");
+
+ // Leaves measures of module 1
+ verifyMeasures(module1, MeasureTreeQuery.builder().setStrategy(LEAVES), "MODULE_M1", "M2", "M3");
+
+ // Leaves measures of project by metric ids
+ verifyMeasures(project, MeasureTreeQuery.builder().setMetricIds(asList(NCLOC_METRIC_ID)).setStrategy(LEAVES), "PROJECT_M1", "MODULE_M1", "M2",
+ "M6");
+
+ // Leaves measure on file
+ verifyMeasures(file1, MeasureTreeQuery.builder().setStrategy(LEAVES), "M2", "M3");
+
+ // Leaves measures of project matching name
+ verifyMeasures(project, MeasureTreeQuery.builder().setNameOrKeyQuery("OnE").setStrategy(LEAVES), "M2", "M3");
+
+ // Leaves measures of project matching qualifiers
+ verifyMeasures(project, MeasureTreeQuery.builder().setQualifiers(asList(FILE)).setStrategy(LEAVES), "M2", "M3");
+ verifyMeasures(project, MeasureTreeQuery.builder().setQualifiers(asList(FILE, UNIT_TEST_FILE)).setStrategy(LEAVES), "M2", "M3", "M6");
+ }
+
private Optional<MeasureDto> selectSingle(MeasureQuery.Builder query) {
return underTest.selectSingle(db.getSession(), query.build());
}
@@ -378,6 +436,16 @@ public class MeasureDaoTest {
assertThat(measures).isEmpty();
}
+ private void verifyMeasures(ComponentDto baseComponent, MeasureTreeQuery.Builder measureQuery, String... expectedIds) {
+ assertThat(underTest.selectTreeByQuery(db.getSession(), baseComponent, measureQuery.build()))
+ .extracting(MeasureDto::getData).containsOnly(expectedIds);
+ }
+
+ private void verifyZeroMeasures(ComponentDto baseComponent, MeasureTreeQuery.Builder measureQuery) {
+ assertThat(underTest.selectTreeByQuery(db.getSession(), baseComponent,
+ measureQuery.build())).isEmpty();
+ }
+
private List<MeasureDto> getMeasuresWithHandler(MeasureQuery.Builder query) {
List<MeasureDto> measures = new ArrayList<>();
underTest.selectByQuery(db.getSession(), query.build(), resultContext -> measures.add((MeasureDto) resultContext.getResultObject()));
diff --git a/sonar-db/src/test/java/org/sonar/db/measure/MeasureTreeQueryTest.java b/sonar-db/src/test/java/org/sonar/db/measure/MeasureTreeQueryTest.java
new file mode 100644
index 00000000000..9975ac99043
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/measure/MeasureTreeQueryTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.component.ComponentTesting;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.measure.MeasureTreeQuery.Strategy.CHILDREN;
+import static org.sonar.db.measure.MeasureTreeQuery.Strategy.LEAVES;
+
+public class MeasureTreeQueryTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void create_query() throws Exception {
+ MeasureTreeQuery query = MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .setQualifiers(asList("FIL", "DIR"))
+ .setNameOrKeyQuery("teSt")
+ .setMetricIds(asList(10, 11))
+ .setPersonId(100L)
+ .build();
+
+ assertThat(query.getStrategy()).isEqualTo(CHILDREN);
+ assertThat(query.getQualifiers()).containsOnly("FIL", "DIR");
+ assertThat(query.getNameOrKeyQuery()).isEqualTo("teSt");
+ assertThat(query.getMetricIds()).containsOnly(10, 11);
+ assertThat(query.getPersonId()).isEqualTo(100L);
+ }
+
+ @Test
+ public void create_minimal_query() throws Exception {
+ MeasureTreeQuery query = MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .build();
+
+ assertThat(query.getStrategy()).isEqualTo(CHILDREN);
+ assertThat(query.getQualifiers()).isNull();
+ assertThat(query.getNameOrKeyQuery()).isNull();
+ assertThat(query.getMetricIds()).isNull();
+ assertThat(query.getPersonId()).isNull();
+ }
+
+ @Test
+ public void test_getNameOrKeyQueryToSqlForResourceIndex() throws Exception {
+ assertThat(MeasureTreeQuery.builder()
+ .setNameOrKeyQuery("like-\\_%/-value")
+ .setStrategy(CHILDREN)
+ .build().getNameOrKeyQueryToSqlForResourceIndex()).isEqualTo("like-\\/_/%//-value%");
+
+ assertThat(MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .build().getNameOrKeyQueryToSqlForResourceIndex()).isNull();
+ }
+
+ @Test
+ public void test_getUuidPath() throws Exception {
+ assertThat(MeasureTreeQuery.builder().setStrategy(CHILDREN)
+ .build().getUuidPath(ComponentTesting.newProjectDto("PROJECT_UUID"))).isEqualTo(".PROJECT_UUID.");
+
+ assertThat(MeasureTreeQuery.builder().setStrategy(LEAVES)
+ .build().getUuidPath(ComponentTesting.newProjectDto("PROJECT_UUID"))).isEqualTo(".PROJECT/_UUID.%");
+ }
+
+ @Test
+ public void return_empty_when_metrics_is_empty() throws Exception {
+ assertThat(MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .setMetricIds(Collections.emptyList())
+ .build().returnsEmpty()).isTrue();
+
+ assertThat(MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .setMetricIds(null)
+ .build().returnsEmpty()).isFalse();
+ }
+
+ @Test
+ public void return_empty_when_qualifiers_is_empty() throws Exception {
+ assertThat(MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .setQualifiers(Collections.emptyList())
+ .build().returnsEmpty()).isTrue();
+
+ assertThat(MeasureTreeQuery.builder()
+ .setStrategy(CHILDREN)
+ .setQualifiers(asList("FIL", "DIR"))
+ .build().returnsEmpty()).isFalse();
+ }
+
+ @Test
+ public void fail_when_no_strategy() throws Exception {
+ expectedException.expect(NullPointerException.class);
+ MeasureTreeQuery.builder()
+ .build();
+ }
+
+}