@@ -115,7 +115,7 @@ public class ComputeEngineContainerImplTest { | |||
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( | |||
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION | |||
+ 26 // level 1 | |||
+ 51 // content of DaoModule | |||
+ 52 // content of DaoModule | |||
+ 3 // content of EsSearchModule | |||
+ 67 // content of CorePropertyDefinitions | |||
+ 1 // StopFlagContainer |
@@ -69,6 +69,7 @@ public final class SqTables { | |||
"internal_properties", | |||
"issues", | |||
"issue_changes", | |||
"live_measures", | |||
"manual_measures", | |||
"metrics", | |||
"notifications", |
@@ -284,6 +284,23 @@ CREATE INDEX "DUPLICATIONS_INDEX_HASH" ON "DUPLICATIONS_INDEX" ("HASH"); | |||
CREATE INDEX "DUPLICATION_ANALYSIS_COMPONENT" ON "DUPLICATIONS_INDEX" ("ANALYSIS_UUID", "COMPONENT_UUID"); | |||
CREATE TABLE "LIVE_MEASURES" ( | |||
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"METRIC_ID" INTEGER NOT NULL, | |||
"VALUE" DOUBLE, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"VARIATION" DOUBLE, | |||
"MEASURE_DATA" BINARY, | |||
"UPDATE_MARKER" VARCHAR(40), | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL | |||
); | |||
CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES" ("PROJECT_UUID"); | |||
CREATE UNIQUE INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES" ("COMPONENT_UUID", "METRIC_ID"); | |||
CREATE TABLE "PROJECT_MEASURES" ( | |||
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"VALUE" DOUBLE, | |||
@@ -304,7 +321,6 @@ CREATE TABLE "PROJECT_MEASURES" ( | |||
); | |||
CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID"); | |||
CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID"); | |||
CREATE INDEX "MEASURES_PERSON" ON "PROJECT_MEASURES" ("PERSON_ID"); | |||
CREATE TABLE "INTERNAL_PROPERTIES" ( |
@@ -39,6 +39,7 @@ import org.sonar.db.es.EsQueueDao; | |||
import org.sonar.db.event.EventDao; | |||
import org.sonar.db.issue.IssueChangeDao; | |||
import org.sonar.db.issue.IssueDao; | |||
import org.sonar.db.measure.LiveMeasureDao; | |||
import org.sonar.db.measure.MeasureDao; | |||
import org.sonar.db.measure.custom.CustomMeasureDao; | |||
import org.sonar.db.metric.MetricDao; | |||
@@ -92,6 +93,7 @@ public class DaoModule extends Module { | |||
ComponentDao.class, | |||
ComponentKeyUpdaterDao.class, | |||
ComponentLinkDao.class, | |||
LiveMeasureDao.class, | |||
CustomMeasureDao.class, | |||
DefaultQProfileDao.class, | |||
DuplicationDao.class, |
@@ -37,6 +37,7 @@ import org.sonar.db.es.EsQueueDao; | |||
import org.sonar.db.event.EventDao; | |||
import org.sonar.db.issue.IssueChangeDao; | |||
import org.sonar.db.issue.IssueDao; | |||
import org.sonar.db.measure.LiveMeasureDao; | |||
import org.sonar.db.measure.MeasureDao; | |||
import org.sonar.db.measure.custom.CustomMeasureDao; | |||
import org.sonar.db.metric.MetricDao; | |||
@@ -130,6 +131,7 @@ public class DbClient { | |||
private final AnalysisPropertiesDao analysisPropertiesDao; | |||
private final QProfileEditUsersDao qProfileEditUsersDao; | |||
private final QProfileEditGroupsDao qProfileEditGroupsDao; | |||
private final LiveMeasureDao liveMeasureDao; | |||
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) { | |||
this.database = database; | |||
@@ -191,6 +193,7 @@ public class DbClient { | |||
analysisPropertiesDao = getDao(map, AnalysisPropertiesDao.class); | |||
qProfileEditUsersDao = getDao(map, QProfileEditUsersDao.class); | |||
qProfileEditGroupsDao = getDao(map, QProfileEditGroupsDao.class); | |||
liveMeasureDao = getDao(map, LiveMeasureDao.class); | |||
} | |||
public DbSession openSession(boolean batch) { | |||
@@ -405,6 +408,10 @@ public class DbClient { | |||
return qProfileEditGroupsDao; | |||
} | |||
public LiveMeasureDao liveMeasureDao() { | |||
return liveMeasureDao; | |||
} | |||
protected <K extends Dao> K getDao(Map<Class, Dao> map, Class<K> clazz) { | |||
return (K) map.get(clazz); | |||
} |
@@ -62,6 +62,7 @@ import org.sonar.db.issue.IssueChangeMapper; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.issue.IssueMapper; | |||
import org.sonar.db.issue.ShortBranchIssueDto; | |||
import org.sonar.db.measure.LiveMeasureMapper; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureMapper; | |||
import org.sonar.db.measure.custom.CustomMeasureDto; | |||
@@ -207,6 +208,7 @@ public class MyBatis implements Startable { | |||
ComponentKeyUpdaterMapper.class, | |||
ComponentLinkMapper.class, | |||
ComponentMapper.class, | |||
LiveMeasureMapper.class, | |||
CustomMeasureMapper.class, | |||
DefaultQProfileMapper.class, | |||
DuplicationMapper.class, |
@@ -138,7 +138,6 @@ public class ComponentDto { | |||
private String moduleUuid; | |||
private String moduleUuidPath; | |||
private String copyComponentUuid; | |||
private String developerUuid; | |||
private String scope; | |||
private String qualifier; | |||
private String path; | |||
@@ -401,16 +400,6 @@ public class ComponentDto { | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getDeveloperUuid() { | |||
return developerUuid; | |||
} | |||
public ComponentDto setDeveloperUuid(@Nullable String developerUuid) { | |||
this.developerUuid = developerUuid; | |||
return this; | |||
} | |||
public Date getCreatedAt() { | |||
return createdAt; | |||
} | |||
@@ -488,7 +477,6 @@ public class ComponentDto { | |||
.append("rootUuid", rootUuid) | |||
.append("mainBranchProjectUuid", mainBranchProjectUuid) | |||
.append("copyComponentUuid", copyComponentUuid) | |||
.append("developerUuid", developerUuid) | |||
.append("path", path) | |||
.append("deprecatedKey", deprecatedKey) | |||
.append("name", name) | |||
@@ -513,7 +501,6 @@ public class ComponentDto { | |||
copy.moduleUuid = moduleUuid; | |||
copy.moduleUuidPath = moduleUuidPath; | |||
copy.copyComponentUuid = copyComponentUuid; | |||
copy.developerUuid = developerUuid; | |||
copy.scope = scope; | |||
copy.qualifier = qualifier; | |||
copy.path = path; |
@@ -45,7 +45,6 @@ public class ResourceDto { | |||
private String description; | |||
private String language; | |||
private String copyComponentUuid; | |||
private String developerUuid; | |||
private Date createdAt; | |||
public Long getId() { | |||
@@ -202,16 +201,6 @@ public class ResourceDto { | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getDeveloperUuid() { | |||
return developerUuid; | |||
} | |||
public ResourceDto setDeveloperUuid(@Nullable String developerUuid) { | |||
this.developerUuid = developerUuid; | |||
return this; | |||
} | |||
public Date getCreatedAt() { | |||
return createdAt; | |||
} |
@@ -0,0 +1,100 @@ | |||
/* | |||
* 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.db.measure; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.apache.ibatis.session.ResultHandler; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import static java.util.Collections.singletonList; | |||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
public class LiveMeasureDao implements Dao { | |||
private final System2 system2; | |||
public LiveMeasureDao(System2 system2) { | |||
this.system2 = system2; | |||
} | |||
public List<LiveMeasureDto> selectByComponentUuids(DbSession dbSession, Collection<String> largeComponentUuids, Collection<Integer> metricIds) { | |||
if (largeComponentUuids.isEmpty() || metricIds.isEmpty()) { | |||
return Collections.emptyList(); | |||
} | |||
return executeLargeInputs( | |||
largeComponentUuids, | |||
componentUuids -> mapper(dbSession).selectByComponentUuidsAndMetricIds(componentUuids, metricIds)); | |||
} | |||
public List<LiveMeasureDto> selectByComponentUuidsAndMetricKeys(DbSession dbSession, Collection<String> largeComponentUuids, Collection<String> metricKeys) { | |||
if (largeComponentUuids.isEmpty() || metricKeys.isEmpty()) { | |||
return Collections.emptyList(); | |||
} | |||
return executeLargeInputs( | |||
largeComponentUuids, | |||
componentUuids -> mapper(dbSession).selectByComponentUuidsAndMetricKeys(componentUuids, metricKeys)); | |||
} | |||
public Optional<LiveMeasureDto> selectMeasure(DbSession dbSession, String componentUuid, String metricKey) { | |||
List<LiveMeasureDto> measures = selectByComponentUuidsAndMetricKeys(dbSession, singletonList(componentUuid), singletonList(metricKey)); | |||
// couple of columns [component_uuid, metric_id] is unique. List can't have more than 1 item. | |||
if (measures.size() == 1) { | |||
return Optional.of(measures.get(0)); | |||
} | |||
return Optional.empty(); | |||
} | |||
public void selectTreeByQuery(DbSession dbSession, ComponentDto baseComponent, MeasureTreeQuery query, ResultHandler<LiveMeasureDto> resultHandler) { | |||
if (query.returnsEmpty()) { | |||
return; | |||
} | |||
mapper(dbSession).selectTreeByQuery(query, baseComponent.uuid(), query.getUuidPath(baseComponent), resultHandler); | |||
} | |||
public void insert(DbSession dbSession, LiveMeasureDto dto) { | |||
mapper(dbSession).insert(dto, Uuids.create(), null, system2.now()); | |||
} | |||
public void insertOrUpdate(DbSession dbSession, LiveMeasureDto dto, @Nullable String marker) { | |||
LiveMeasureMapper mapper = mapper(dbSession); | |||
long now = system2.now(); | |||
if (mapper.update(dto, marker, now) == 0) { | |||
mapper.insert(dto, Uuids.create(), marker, now); | |||
} | |||
} | |||
public void deleteByProjectUuidExcludingMarker(DbSession dbSession, String projectUuid, String marker) { | |||
mapper(dbSession).deleteByProjectUuidExcludingMarker(projectUuid, marker); | |||
} | |||
private static LiveMeasureMapper mapper(DbSession dbSession) { | |||
return dbSession.getMapper(LiveMeasureMapper.class); | |||
} | |||
} |
@@ -0,0 +1,141 @@ | |||
/* | |||
* 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.db.measure; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Arrays; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
public class LiveMeasureDto { | |||
private static final int MAX_TEXT_VALUE_LENGTH = 4000; | |||
private String componentUuid; | |||
private String projectUuid; | |||
private int metricId; | |||
@Nullable | |||
private Double value; | |||
@Nullable | |||
private String textValue; | |||
@Nullable | |||
private byte[] data; | |||
@Nullable | |||
private Double variation; | |||
public String getComponentUuid() { | |||
return componentUuid; | |||
} | |||
public LiveMeasureDto setComponentUuid(String s) { | |||
this.componentUuid = s; | |||
return this; | |||
} | |||
public String getProjectUuid() { | |||
return projectUuid; | |||
} | |||
public LiveMeasureDto setProjectUuid(String s) { | |||
this.projectUuid = s; | |||
return this; | |||
} | |||
public int getMetricId() { | |||
return metricId; | |||
} | |||
public LiveMeasureDto setMetricId(int i) { | |||
this.metricId = i; | |||
return this; | |||
} | |||
@CheckForNull | |||
public Double getValue() { | |||
return value; | |||
} | |||
public LiveMeasureDto setValue(@Nullable Double value) { | |||
this.value = value; | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getTextValue() { | |||
return textValue; | |||
} | |||
@CheckForNull | |||
public byte[] getData() { | |||
return data; | |||
} | |||
@CheckForNull | |||
public String getDataAsString() { | |||
if (data != null) { | |||
return new String(data, StandardCharsets.UTF_8); | |||
} | |||
return textValue; | |||
} | |||
public LiveMeasureDto setData(@Nullable String data) { | |||
if (data == null) { | |||
this.textValue = null; | |||
this.data = null; | |||
} else if (data.length() > MAX_TEXT_VALUE_LENGTH) { | |||
this.textValue = null; | |||
this.data = data.getBytes(StandardCharsets.UTF_8); | |||
} else { | |||
this.textValue = data; | |||
this.data = null; | |||
} | |||
return this; | |||
} | |||
public LiveMeasureDto setData(@Nullable byte[] data) { | |||
this.textValue = null; | |||
this.data = data; | |||
return this; | |||
} | |||
@CheckForNull | |||
public Double getVariation() { | |||
return variation; | |||
} | |||
public LiveMeasureDto setVariation(@Nullable Double variation) { | |||
this.variation = variation; | |||
return this; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("LiveMeasureDto{"); | |||
sb.append("componentUuid='").append(componentUuid).append('\''); | |||
sb.append(", projectUuid='").append(projectUuid).append('\''); | |||
sb.append(", metricId=").append(metricId); | |||
sb.append(", value=").append(value); | |||
sb.append(", variation=").append(variation); | |||
sb.append(", textValue='").append(textValue).append('\''); | |||
sb.append(", data=").append(Arrays.toString(data)); | |||
sb.append('}'); | |||
return sb.toString(); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* 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.db.measure; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import javax.annotation.Nullable; | |||
import org.apache.ibatis.annotations.Param; | |||
import org.apache.ibatis.session.ResultHandler; | |||
public interface LiveMeasureMapper { | |||
List<LiveMeasureDto> selectByComponentUuidsAndMetricIds( | |||
@Param("componentUuids") List<String> componentUuids, | |||
@Param("metricIds") Collection<Integer> metricIds); | |||
List<LiveMeasureDto> selectByComponentUuidsAndMetricKeys( | |||
@Param("componentUuids") List<String> componentUuids, | |||
@Param("metricKeys") Collection<String> metricKeys); | |||
void selectTreeByQuery( | |||
@Param("query") MeasureTreeQuery measureQuery, | |||
@Param("baseUuid") String baseUuid, | |||
@Param("baseUuidPath") String baseUuidPath, | |||
ResultHandler<LiveMeasureDto> resultHandler); | |||
void insert( | |||
@Param("dto") LiveMeasureDto dto, | |||
@Param("uuid") String uuid, | |||
@Nullable @Param("marker") String marker, | |||
@Param("now") long now); | |||
int update( | |||
@Param("dto") LiveMeasureDto dto, | |||
@Nullable @Param("marker") String marker, | |||
@Param("now") long now); | |||
void deleteByProjectUuidExcludingMarker( | |||
@Param("projectUuid") String projectUuid, | |||
@Param("marker") String marker); | |||
} |
@@ -19,24 +19,24 @@ | |||
*/ | |||
package org.sonar.db.measure; | |||
import com.google.common.collect.Iterables; | |||
import com.google.common.collect.Lists; | |||
import java.util.Collection; | |||
import java.util.List; | |||
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 java.util.Collections.emptyList; | |||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
public class MeasureDao implements Dao { | |||
public Optional<MeasureDto> selectSingle(DbSession dbSession, MeasureQuery query) { | |||
List<MeasureDto> measures = selectByQuery(dbSession, query); | |||
return Optional.ofNullable(Iterables.getOnlyElement(measures, null)); | |||
public Optional<MeasureDto> selectLastMeasure(DbSession dbSession, String componentUuid, String metricKey) { | |||
return Optional.ofNullable(mapper(dbSession).selectLastMeasure(componentUuid, metricKey)); | |||
} | |||
public Optional<MeasureDto> selectMeasure(DbSession dbSession, String analysisUuid, String componentUuid, String metricKey) { | |||
return Optional.ofNullable(mapper(dbSession).selectMeasure(analysisUuid, componentUuid, metricKey)); | |||
} | |||
/** | |||
@@ -47,10 +47,6 @@ public class MeasureDao implements Dao { | |||
* - 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}. | |||
* </p> | |||
* <p> | |||
* Returned measure can optionally be filtered metric (either by specifying {@link MeasureQuery#metricIds} | |||
* or {@link MeasureQuery#metricKeys}). | |||
* </p> | |||
@@ -78,13 +74,6 @@ public class MeasureDao implements Dao { | |||
return mapper(dbSession).selectByQueryOnSingleComponent(query); | |||
} | |||
public void selectTreeByQuery(DbSession dbSession, ComponentDto baseComponent, MeasureTreeQuery query, ResultHandler<MeasureDto> resultHandler) { | |||
if (query.returnsEmpty()) { | |||
return; | |||
} | |||
mapper(dbSession).selectTreeByQuery(query, baseComponent.uuid(), query.getUuidPath(baseComponent), resultHandler); | |||
} | |||
public List<PastMeasureDto> selectPastMeasures(DbSession dbSession, String componentUuid, String analysisUuid, Collection<Integer> metricIds) { | |||
if (metricIds.isEmpty()) { | |||
return emptyList(); | |||
@@ -107,19 +96,6 @@ public class MeasureDao implements Dao { | |||
return mapper(dbSession).selectPastMeasuresOnSeveralAnalyses(query); | |||
} | |||
/** | |||
* Used by developer cockpit. | |||
*/ | |||
public List<MeasureDto> selectProjectMeasuresOfDeveloper(DbSession dbSession, long developerId, Collection<Integer> metricIds) { | |||
return executeLargeInputs( | |||
metricIds, | |||
ids -> mapper(dbSession).selectProjectMeasuresOfDeveloper(developerId, metricIds)); | |||
} | |||
public List<MeasureDto> selectByComponentsAndMetrics(DbSession dbSession, Collection<String> componentUuids, Collection<Integer> metricIds) { | |||
return executeLargeInputs(componentUuids, partitionComponentUuids -> mapper(dbSession).selectByComponentsAndMetrics(partitionComponentUuids, metricIds)); | |||
} | |||
public void insert(DbSession session, MeasureDto measureDto) { | |||
mapper(session).insert(measureDto); | |||
} |
@@ -36,7 +36,6 @@ public class MeasureDto { | |||
private String componentUuid; | |||
private String analysisUuid; | |||
private int metricId; | |||
private Long developerId; | |||
@CheckForNull | |||
public Double getValue() { | |||
@@ -128,16 +127,6 @@ public class MeasureDto { | |||
return this; | |||
} | |||
@CheckForNull | |||
public Long getDeveloperId() { | |||
return developerId; | |||
} | |||
public MeasureDto setDeveloperId(@Nullable Long developerId) { | |||
this.developerId = developerId; | |||
return this; | |||
} | |||
@Override | |||
public String toString() { | |||
return MoreObjects.toStringHelper(this) | |||
@@ -150,7 +139,6 @@ public class MeasureDto { | |||
.add("componentUuid", componentUuid) | |||
.add("analysisUuid", analysisUuid) | |||
.add("metricId", metricId) | |||
.add("developerId", developerId) | |||
.toString(); | |||
} | |||
} |
@@ -19,31 +19,35 @@ | |||
*/ | |||
package org.sonar.db.measure; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import org.apache.ibatis.annotations.Param; | |||
import org.apache.ibatis.session.ResultHandler; | |||
public interface MeasureMapper { | |||
@CheckForNull | |||
MeasureDto selectLastMeasure( | |||
@Param("componentUuid") String componentUuid, | |||
@Param("metricKey") String metricKey | |||
); | |||
@CheckForNull | |||
MeasureDto selectMeasure( | |||
@Param("analysisUuid") String analysisUuid, | |||
@Param("componentUuid") String componentUuid, | |||
@Param("metricKey") String metricKey | |||
); | |||
List<MeasureDto> selectByQueryOnProjects(@Param("query") MeasureQuery query); | |||
List<MeasureDto> selectByQueryOnComponents(@Param("query") MeasureQuery query); | |||
List<MeasureDto> selectByQueryOnSingleComponent(@Param("query") MeasureQuery query); | |||
void selectTreeByQuery(@Param("query") MeasureTreeQuery measureQuery, @Param("baseUuid") String baseUuid, @Param("baseUuidPath") String baseUuidPath, | |||
ResultHandler<MeasureDto> resultHandler); | |||
List<PastMeasureDto> selectPastMeasuresOnSingleAnalysis(@Param("componentUuid") String componentUuid, @Param("analysisUuid") String analysisUuid, | |||
@Param("metricIds") List<Integer> metricIds); | |||
List<MeasureDto> selectPastMeasuresOnSeveralAnalyses(@Param("query") PastMeasureQuery query); | |||
List<MeasureDto> selectProjectMeasuresOfDeveloper(@Param("developerId") long developerId, @Param("metricIds") Collection<Integer> metricIds); | |||
List<MeasureDto> selectByComponentsAndMetrics(@Param("componentUuids") List<String> componentUuids, @Param("metricIds") Collection<Integer> metricIds); | |||
void insert(MeasureDto measureDto); | |||
} |
@@ -44,19 +44,15 @@ public class MeasureQuery { | |||
@CheckForNull | |||
private final Collection<String> metricKeys; | |||
@CheckForNull | |||
private final Long personId; | |||
private MeasureQuery(Builder builder) { | |||
this(builder.analysisUuid, builder.projectUuids, builder.componentUuids, builder.metricIds, builder.metricKeys, builder.personId); | |||
this(builder.analysisUuid, builder.projectUuids, builder.componentUuids, builder.metricIds, builder.metricKeys); | |||
} | |||
private MeasureQuery(@Nullable String analysisUuid, | |||
@Nullable Collection<String> projectUuids, | |||
@Nullable Collection<String> componentUuids, | |||
@Nullable Collection<Integer> metricIds, | |||
@Nullable Collection<String> metricKeys, | |||
@Nullable Long personId) { | |||
@Nullable Collection<String> metricKeys) { | |||
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), | |||
@@ -67,7 +63,6 @@ public class MeasureQuery { | |||
this.componentUuids = componentUuids; | |||
this.metricIds = metricIds; | |||
this.metricKeys = metricKeys; | |||
this.personId = personId; | |||
} | |||
public String getAnalysisUuid() { | |||
@@ -104,11 +99,6 @@ public class MeasureQuery { | |||
return metricKeys; | |||
} | |||
@CheckForNull | |||
public Long getPersonId() { | |||
return personId; | |||
} | |||
public boolean returnsEmpty() { | |||
return (projectUuids != null && projectUuids.isEmpty()) | |||
|| (componentUuids != null && componentUuids.isEmpty()) | |||
@@ -141,13 +131,12 @@ public class MeasureQuery { | |||
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); | |||
Objects.equals(metricKeys, that.metricKeys); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(analysisUuid, componentUuids, metricIds, metricKeys, personId); | |||
return Objects.hash(analysisUuid, componentUuids, metricIds, metricKeys); | |||
} | |||
public static Builder builder() { | |||
@@ -155,11 +144,11 @@ public class MeasureQuery { | |||
} | |||
static MeasureQuery copyWithSubsetOfProjectUuids(MeasureQuery query, Collection<String> projectUuids) { | |||
return new MeasureQuery(query.analysisUuid, projectUuids, query.componentUuids, query.metricIds, query.metricKeys, query.personId); | |||
return new MeasureQuery(query.analysisUuid, projectUuids, query.componentUuids, query.metricIds, query.metricKeys); | |||
} | |||
static MeasureQuery copyWithSubsetOfComponentUuids(MeasureQuery query, Collection<String> componentUuids) { | |||
return new MeasureQuery(query.analysisUuid, query.projectUuids, componentUuids, query.metricIds, query.metricKeys, query.personId); | |||
return new MeasureQuery(query.analysisUuid, query.projectUuids, componentUuids, query.metricIds, query.metricKeys); | |||
} | |||
public static final class Builder { | |||
@@ -168,7 +157,6 @@ public class MeasureQuery { | |||
private Collection<String> componentUuids; | |||
private Collection<Integer> metricIds; | |||
private Collection<String> metricKeys; | |||
private Long personId; | |||
private Builder() { | |||
// see MeasureQuery#builder() | |||
@@ -230,11 +218,6 @@ public class MeasureQuery { | |||
return this; | |||
} | |||
public Builder setPersonId(@Nullable Long l) { | |||
this.personId = l; | |||
return this; | |||
} | |||
public MeasureQuery build() { | |||
return new MeasureQuery(this); | |||
} |
@@ -47,15 +47,11 @@ public class MeasureTreeQuery { | |||
@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 | |||
@@ -85,11 +81,6 @@ public class MeasureTreeQuery { | |||
return metricIds; | |||
} | |||
@CheckForNull | |||
public Long getPersonId() { | |||
return personId; | |||
} | |||
public String getUuidPath(ComponentDto component) { | |||
switch (strategy) { | |||
case CHILDREN: | |||
@@ -120,9 +111,6 @@ public class MeasureTreeQuery { | |||
@CheckForNull | |||
private Collection<Integer> metricIds; | |||
@CheckForNull | |||
private Long personId; | |||
private Builder() { | |||
} | |||
@@ -149,11 +137,6 @@ public class MeasureTreeQuery { | |||
return this; | |||
} | |||
public Builder setPersonId(@Nullable Long personId) { | |||
this.personId = personId; | |||
return this; | |||
} | |||
public MeasureTreeQuery build() { | |||
return new MeasureTreeQuery(this); | |||
} |
@@ -31,9 +31,6 @@ public class PastMeasureDto { | |||
@CheckForNull | |||
private Double value; | |||
@CheckForNull | |||
private Long personId; | |||
public double getValue() { | |||
requireNonNull(value); | |||
return value; | |||
@@ -56,15 +53,4 @@ public class PastMeasureDto { | |||
this.metricId = i; | |||
return this; | |||
} | |||
@CheckForNull | |||
public Long getPersonId() { | |||
return personId; | |||
} | |||
PastMeasureDto setPersonId(@Nullable Long l) { | |||
this.personId = l; | |||
return this; | |||
} | |||
} |
@@ -69,24 +69,23 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
CoreMetrics.NEW_LINES_KEY, | |||
CoreMetrics.NEW_RELIABILITY_RATING_KEY); | |||
private static final String SQL_PROJECTS = "SELECT p.organization_uuid, p.uuid, p.kee, p.name, s.uuid, s.created_at, p.tags " + | |||
private static final String SQL_PROJECTS = "SELECT p.organization_uuid, p.uuid, p.kee, p.name, s.created_at, p.tags " + | |||
"FROM projects p " + | |||
"LEFT OUTER JOIN snapshots s ON s.component_uuid=p.uuid AND s.islast=? " + | |||
"WHERE p.enabled=? AND p.scope=? AND p.qualifier=? and p.main_branch_project_uuid is null "; | |||
private static final String PROJECT_FILTER = " AND p.uuid=?"; | |||
private static final String SQL_MEASURES = "SELECT m.name, pm.value, pm.variation_value_1, pm.text_value FROM project_measures pm " + | |||
private static final String SQL_MEASURES = "SELECT m.name, pm.value, pm.variation, pm.text_value FROM live_measures pm " + | |||
"INNER JOIN metrics m ON m.id = pm.metric_id " + | |||
"WHERE pm.component_uuid = ? AND pm.analysis_uuid = ? " + | |||
"WHERE pm.component_uuid = ? " + | |||
"AND m.name IN ({metricNames}) " + | |||
"AND (pm.value IS NOT NULL OR pm.variation_value_1 IS NOT NULL OR pm.text_value IS NOT NULL) " + | |||
"AND pm.person_id IS NULL " + | |||
"AND (pm.value IS NOT NULL OR pm.variation IS NOT NULL OR pm.text_value IS NOT NULL) " + | |||
"AND m.enabled = ? "; | |||
private static final boolean ENABLED = true; | |||
private static final int FIELD_METRIC_NAME = 1; | |||
private static final int FIELD_MEASURE_VALUE = 2; | |||
private static final int FIELD_MEASURE_VARIATION_VALUE_1 = 3; | |||
private static final int FIELD_MEASURE_VARIATION = 3; | |||
private static final int FIELD_MEASURE_TEXT_VALUE = 4; | |||
private final PreparedStatement measuresStatement; | |||
@@ -116,10 +115,9 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
String uuid = rs.getString(2); | |||
String key = rs.getString(3); | |||
String name = rs.getString(4); | |||
String analysisUuid = DatabaseUtils.getString(rs, 5); | |||
Long analysisDate = DatabaseUtils.getLong(rs, 6); | |||
List<String> tags = readDbTags(DatabaseUtils.getString(rs, 7)); | |||
Project project = new Project(orgUuid, uuid, key, name, tags, analysisUuid, analysisDate); | |||
Long analysisDate = DatabaseUtils.getLong(rs, 5); | |||
List<String> tags = readDbTags(DatabaseUtils.getString(rs, 6)); | |||
Project project = new Project(orgUuid, uuid, key, name, tags, analysisDate); | |||
projects.add(project); | |||
} | |||
return projects; | |||
@@ -165,20 +163,16 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
return null; | |||
} | |||
Project project = projects.next(); | |||
Measures measures = selectMeasures(project.getUuid(), project.getAnalysisUuid()); | |||
Measures measures = selectMeasures(project.getUuid()); | |||
return new ProjectMeasures(project, measures); | |||
} | |||
private Measures selectMeasures(String projectUuid, @Nullable String analysisUuid) { | |||
private Measures selectMeasures(String projectUuid) { | |||
Measures measures = new Measures(); | |||
if (analysisUuid == null) { | |||
return measures; | |||
} | |||
ResultSet rs = null; | |||
try { | |||
AtomicInteger index = new AtomicInteger(1); | |||
measuresStatement.setString(index.getAndIncrement(), projectUuid); | |||
measuresStatement.setString(index.getAndIncrement(), analysisUuid); | |||
METRIC_KEYS.forEach(DatabaseUtils.setStrings(measuresStatement, index::getAndIncrement)); | |||
measuresStatement.setBoolean(index.getAndIncrement(), ENABLED); | |||
rs = measuresStatement.executeQuery(); | |||
@@ -187,7 +181,7 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
} | |||
return measures; | |||
} catch (Exception e) { | |||
throw new IllegalStateException(String.format("Fail to execute request to select measures of project %s, analysis %s", projectUuid, analysisUuid), e); | |||
throw new IllegalStateException(String.format("Fail to execute request to select measures of project %s", projectUuid), e); | |||
} finally { | |||
DatabaseUtils.closeQuietly(rs); | |||
} | |||
@@ -195,7 +189,7 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
private static void readMeasure(ResultSet rs, Measures measures) throws SQLException { | |||
String metricKey = rs.getString(FIELD_METRIC_NAME); | |||
Optional<Double> value = metricKey.startsWith("new_") ? getDouble(rs, FIELD_MEASURE_VARIATION_VALUE_1) : getDouble(rs, FIELD_MEASURE_VALUE); | |||
Optional<Double> value = metricKey.startsWith("new_") ? getDouble(rs, FIELD_MEASURE_VARIATION) : getDouble(rs, FIELD_MEASURE_VALUE); | |||
if (value.isPresent()) { | |||
measures.addNumericMeasure(metricKey, value.get()); | |||
return; | |||
@@ -239,17 +233,15 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
private final String uuid; | |||
private final String key; | |||
private final String name; | |||
private final String analysisUuid; | |||
private final Long analysisDate; | |||
private final List<String> tags; | |||
public Project(String organizationUuid, String uuid, String key, String name, List<String> tags, @Nullable String analysisUuid, @Nullable Long analysisDate) { | |||
public Project(String organizationUuid, String uuid, String key, String name, List<String> tags, @Nullable Long analysisDate) { | |||
this.organizationUuid = organizationUuid; | |||
this.uuid = uuid; | |||
this.key = key; | |||
this.name = name; | |||
this.tags = tags; | |||
this.analysisUuid = analysisUuid; | |||
this.analysisDate = analysisDate; | |||
} | |||
@@ -273,11 +265,6 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea | |||
return tags; | |||
} | |||
@CheckForNull | |||
public String getAnalysisUuid() { | |||
return analysisUuid; | |||
} | |||
@CheckForNull | |||
public Long getAnalysisDate() { | |||
return analysisDate; |
@@ -21,13 +21,11 @@ package org.sonar.db.purge; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Lists; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
import org.sonar.db.DbSession; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static java.util.Arrays.asList; | |||
class PurgeCommands { | |||
private static final int MAX_SNAPSHOTS_PER_QUERY = 1000; | |||
@@ -56,14 +54,14 @@ class PurgeCommands { | |||
return purgeMapper.selectAnalysisIdsAndUuids(query); | |||
} | |||
void deleteAnalyses(String rootUuid) { | |||
void deleteAnalyses(String rootComponentUuid) { | |||
profiler.start("deleteAnalyses (events)"); | |||
purgeMapper.deleteEventsByComponentUuid(rootUuid); | |||
purgeMapper.deleteEventsByComponentUuid(rootComponentUuid); | |||
session.commit(); | |||
profiler.stop(); | |||
List<List<String>> analysisUuidsPartitions = Lists.partition(IdUuidPairs.uuids(purgeMapper.selectAnalysisIdsAndUuids(new PurgeSnapshotQuery().setComponentUuid(rootUuid))), | |||
MAX_SNAPSHOTS_PER_QUERY); | |||
List<List<String>> analysisUuidsPartitions = Lists.partition(IdUuidPairs.uuids( | |||
purgeMapper.selectAnalysisIdsAndUuids(new PurgeSnapshotQuery().setComponentUuid(rootComponentUuid))), MAX_SNAPSHOTS_PER_QUERY); | |||
deleteAnalysisDuplications(analysisUuidsPartitions); | |||
@@ -84,9 +82,10 @@ class PurgeCommands { | |||
} | |||
void deleteAnalyses(PurgeSnapshotQuery... queries) { | |||
List<IdUuidPair> snapshotIds = from(asList(queries)) | |||
.transformAndConcat(purgeMapper::selectAnalysisIdsAndUuids) | |||
.toList(); | |||
List<IdUuidPair> snapshotIds = Arrays.stream(queries) | |||
.flatMap(q -> purgeMapper.selectAnalysisIdsAndUuids(q).stream()) | |||
.collect(Collectors.toList()); | |||
deleteAnalyses(snapshotIds); | |||
} | |||
@@ -124,9 +123,11 @@ class PurgeCommands { | |||
profiler.start("deleteSnapshotWastedMeasures (project_measures)"); | |||
List<Long> metricIdsWithoutHistoricalData = purgeMapper.selectMetricIdsWithoutHistoricalData(); | |||
analysisUuidsPartitions | |||
.forEach(analysisUuidsPartition -> purgeMapper.deleteAnalysisWastedMeasures(analysisUuidsPartition, metricIdsWithoutHistoricalData)); | |||
session.commit(); | |||
if (!metricIdsWithoutHistoricalData.isEmpty()) { | |||
analysisUuidsPartitions | |||
.forEach(analysisUuidsPartition -> purgeMapper.deleteAnalysisWastedMeasures(analysisUuidsPartition, metricIdsWithoutHistoricalData)); | |||
session.commit(); | |||
} | |||
profiler.stop(); | |||
profiler.start("updatePurgeStatusToOne (snapshots)"); | |||
@@ -272,4 +273,11 @@ class PurgeCommands { | |||
session.commit(); | |||
profiler.stop(); | |||
} | |||
void deleteLiveMeasures(String rootUuid) { | |||
profiler.start("deleteLiveMeasures (live_measures)"); | |||
purgeMapper.deleteLiveMeasuresByProjectUuid(rootUuid); | |||
session.commit(); | |||
profiler.stop(); | |||
} | |||
} |
@@ -49,12 +49,12 @@ public class PurgeConfiguration { | |||
this.maxAgeInDaysOfInactiveShortLivingBranches = maxAgeInDaysOfInactiveShortLivingBranches; | |||
} | |||
public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, IdUuidPair idUuidPair, Collection<String> disabledComponentUuids) { | |||
public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, IdUuidPair rootId, Collection<String> disabledComponentUuids) { | |||
String[] scopes = new String[] {Scopes.FILE}; | |||
if (config.getBoolean(PurgeConstants.PROPERTY_CLEAN_DIRECTORY).orElse(false)) { | |||
scopes = new String[] {Scopes.DIRECTORY, Scopes.FILE}; | |||
} | |||
return new PurgeConfiguration(idUuidPair, scopes, config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES).get(), | |||
return new PurgeConfiguration(rootId, scopes, config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES).get(), | |||
config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_INACTIVE_SHORT_LIVING_BRANCHES), System2.INSTANCE, disabledComponentUuids); | |||
} | |||
@@ -204,6 +204,7 @@ public class PurgeDao implements Dao { | |||
commands.deleteCeQueue(rootUuid); | |||
commands.deleteWebhookDeliveries(rootUuid); | |||
commands.deleteBranch(rootUuid); | |||
commands.deleteLiveMeasures(rootUuid); | |||
} | |||
/** |
@@ -97,4 +97,6 @@ public interface PurgeMapper { | |||
void deleteWebhookDeliveriesByProjectUuid(@Param("projectUuid") String projectUuid); | |||
void deleteBranchByUuid(@Param("uuid") String uuid); | |||
void deleteLiveMeasuresByProjectUuid(@Param("projectUuid") String projectUuid); | |||
} |
@@ -24,7 +24,6 @@ | |||
p.path as path, | |||
p.enabled as enabled, | |||
p.copy_component_uuid as copyComponentUuid, | |||
p.developer_uuid as developerUuid, | |||
p.private as isPrivate, | |||
p.created_at as createdAt | |||
</sql> | |||
@@ -512,7 +511,6 @@ | |||
root_uuid, | |||
path, | |||
copy_component_uuid, | |||
developer_uuid, | |||
enabled, | |||
created_at, | |||
b_changed, | |||
@@ -548,7 +546,6 @@ | |||
#{rootUuid,jdbcType=VARCHAR}, | |||
#{path,jdbcType=VARCHAR}, | |||
#{copyComponentUuid,jdbcType=VARCHAR}, | |||
#{developerUuid,jdbcType=VARCHAR}, | |||
#{enabled,jdbcType=BOOLEAN}, | |||
#{createdAt,jdbcType=TIMESTAMP}, | |||
${_false}, |
@@ -0,0 +1,110 @@ | |||
<?xml version="1.0" encoding="UTF-8" ?> | |||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> | |||
<mapper namespace="org.sonar.db.measure.LiveMeasureMapper"> | |||
<sql id="columns"> | |||
lm.component_uuid as componentUuid, | |||
lm.project_uuid as projectUuid, | |||
lm.metric_id as metricId, | |||
lm.value as value, | |||
lm.text_value as textValue, | |||
lm.measure_data as data, | |||
lm.variation as variation | |||
</sql> | |||
<select id="selectByComponentUuidsAndMetricIds" parameterType="map" resultType="org.sonar.db.measure.LiveMeasureDto"> | |||
select <include refid="columns"/> from live_measures lm | |||
where | |||
lm.metric_id in <foreach item="metricId" collection="metricIds" open="(" separator="," close=")">#{metricId, jdbcType=INTEGER}</foreach> | |||
and lm.component_uuid in | |||
<foreach item="componentUuid" collection="componentUuids" open="(" separator="," close=")"> | |||
#{componentUuid, jdbcType=VARCHAR} | |||
</foreach> | |||
</select> | |||
<select id="selectByComponentUuidsAndMetricKeys" parameterType="map" resultType="org.sonar.db.measure.LiveMeasureDto"> | |||
select <include refid="columns"/> from live_measures lm | |||
inner join metrics m on m.id = lm.metric_id | |||
where | |||
m.name in <foreach item="metricKey" collection="metricKeys" open="(" separator="," close=")">#{metricKey, jdbcType=VARCHAR}</foreach> | |||
and lm.component_uuid in | |||
<foreach item="componentUuid" collection="componentUuids" open="(" separator="," close=")"> | |||
#{componentUuid, jdbcType=VARCHAR} | |||
</foreach> | |||
</select> | |||
<insert id="insert" parameterType="map" useGeneratedKeys="false"> | |||
insert into live_measures ( | |||
uuid, | |||
component_uuid, | |||
project_uuid, | |||
metric_id, | |||
value, | |||
text_value, | |||
variation, | |||
measure_data, | |||
update_marker, | |||
created_at, | |||
updated_at | |||
) values ( | |||
#{uuid, jdbcType=VARCHAR}, | |||
#{dto.componentUuid, jdbcType=VARCHAR}, | |||
#{dto.projectUuid, jdbcType=VARCHAR}, | |||
#{dto.metricId, jdbcType=INTEGER}, | |||
#{dto.value, jdbcType=DOUBLE}, | |||
#{dto.textValue, jdbcType=VARCHAR}, | |||
#{dto.variation, jdbcType=DOUBLE}, | |||
#{dto.data, jdbcType=BINARY}, | |||
#{marker, jdbcType=VARCHAR}, | |||
#{now, jdbcType=BIGINT}, | |||
#{now, jdbcType=BIGINT} | |||
) | |||
</insert> | |||
<update id="update" parameterType="map"> | |||
update live_measures set | |||
value = #{dto.value, jdbcType=DOUBLE}, | |||
variation = #{dto.variation, jdbcType=DOUBLE}, | |||
text_value = #{dto.textValue, jdbcType=VARCHAR}, | |||
measure_data = #{dto.data, jdbcType=BINARY}, | |||
update_marker = #{marker, jdbcType=VARCHAR}, | |||
updated_at = #{now, jdbcType=BIGINT} | |||
where | |||
component_uuid = #{dto.componentUuid, jdbcType=VARCHAR} | |||
and metric_id = #{dto.metricId, jdbcType=INTEGER} | |||
</update> | |||
<delete id="deleteByProjectUuidExcludingMarker" parameterType="map"> | |||
delete from live_measures | |||
where | |||
project_uuid = #{projectUuid, jdbcType=VARCHAR} and | |||
(update_marker != #{marker, jdbcType=VARCHAR} or update_marker is null) | |||
</delete> | |||
<select id="selectTreeByQuery" parameterType="map" resultType="org.sonar.db.measure.LiveMeasureDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||
select <include refid="columns"/> from live_measures lm | |||
inner join projects p on p.uuid = lm.component_uuid | |||
<!-- TODO do we really need another join on projects ? Using lm.project_uuid should be enough --> | |||
<include refid="org.sonar.db.component.ComponentMapper.selectDescendantsJoins"/> | |||
<where> | |||
<if test="query.getMetricIds() != null"> | |||
lm.metric_id in | |||
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId,jdbcType=INTEGER}</foreach> | |||
</if> | |||
<include refid="org.sonar.db.component.ComponentMapper.selectDescendantsFilters"/> | |||
</where> | |||
-- Add measures of base component | |||
union all | |||
select <include refid="columns"/> from live_measures lm | |||
inner join projects p on p.uuid = lm.component_uuid and lm.component_uuid = #{baseUuid, jdbcType=VARCHAR} | |||
<where> | |||
<if test="query.getMetricIds() != null"> | |||
lm.metric_id in | |||
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId,jdbcType=INTEGER}</foreach> | |||
</if> | |||
<include refid="org.sonar.db.component.ComponentMapper.selectDescendantsFilters"/> | |||
</where> | |||
</select> | |||
</mapper> |
@@ -5,7 +5,6 @@ | |||
<sql id="measureColumns"> | |||
pm.metric_id as metricId, | |||
pm.person_id as developerId, | |||
pm.component_uuid as componentUuid, | |||
pm.analysis_uuid as analysisUuid, | |||
pm.value as value, | |||
@@ -16,10 +15,27 @@ | |||
pm.variation_value_1 as variation | |||
</sql> | |||
<sql id="extendedMeasureColumns"> | |||
<include refid="measureColumns"/>, | |||
metric.name as metricKey | |||
</sql> | |||
<select id="selectLastMeasure" parameterType="map" resultType="Measure"> | |||
select <include refid="measureColumns"/> | |||
from project_measures pm | |||
inner join metrics m on m.id = pm.metric_id | |||
inner join snapshots s on s.uuid = pm.analysis_uuid | |||
where | |||
pm.component_uuid = #{componentUuid,jdbcType=VARCHAR} and | |||
m.name = #{metricKey,jdbcType=VARCHAR} and | |||
s.islast= ${_true} | |||
</select> | |||
<select id="selectMeasure" parameterType="map" resultType="Measure"> | |||
select <include refid="measureColumns"/> | |||
from project_measures pm | |||
inner join metrics m on m.id = pm.metric_id | |||
inner join snapshots s on s.uuid = pm.analysis_uuid | |||
where | |||
pm.component_uuid = #{componentUuid,jdbcType=VARCHAR} and | |||
m.name = #{metricKey,jdbcType=VARCHAR} and | |||
s.uuid = #{analysisUuid,jdbcType=VARCHAR} | |||
</select> | |||
<select id="selectByQueryOnProjects" parameterType="map" resultType="Measure"> | |||
select <include refid="measureColumns"/> from project_measures pm | |||
@@ -79,60 +95,16 @@ | |||
#{metricKey,jdbcType=VARCHAR} | |||
</foreach> | |||
</if> | |||
<choose> | |||
<when test="query.getPersonId() != null"> | |||
and pm.person_id = #{query.personId,jdbcType=BIGINT} | |||
</when> | |||
<otherwise> | |||
and pm.person_id is null | |||
</otherwise> | |||
</choose> | |||
</sql> | |||
<select id="selectTreeByQuery" parameterType="map" resultType="Measure" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||
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"> | |||
and analysis.islast=${_true} | |||
<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,jdbcType=BIGINT} | |||
</when> | |||
<otherwise> | |||
and pm.person_id is null | |||
</otherwise> | |||
</choose> | |||
<include refid="org.sonar.db.component.ComponentMapper.selectDescendantsFilters"/> | |||
</sql> | |||
<select id="selectPastMeasuresOnSingleAnalysis" 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 | |||
select pm.id as id, pm.metric_id as metricId, pm.value as value | |||
from project_measures pm | |||
inner join snapshots analysis on analysis.uuid = pm.analysis_uuid | |||
where | |||
pm.component_uuid = #{componentUuid,jdbcType=VARCHAR} | |||
and analysis.uuid = #{analysisUuid,jdbcType=VARCHAR} | |||
and pm.metric_id in <foreach item="metricId" collection="metricIds" open="(" separator="," close=")">#{metricId}</foreach> | |||
and pm.person_id is null | |||
</select> | |||
<select id="selectPastMeasuresOnSeveralAnalyses" parameterType="map" resultType="Measure"> | |||
@@ -148,40 +120,9 @@ | |||
and analysis.created_at<#{query.to, jdbcType=BIGINT} | |||
</if> | |||
and pm.metric_id in <foreach item="metricId" collection="query.metricIds" open="(" separator="," close=")">#{metricId, jdbcType=VARCHAR}</foreach> | |||
and pm.person_id is null | |||
and analysis.status=#{query.status, jdbcType=VARCHAR} | |||
</select> | |||
<select id="selectProjectMeasuresOfDeveloper" parameterType="map" resultType="Measure"> | |||
SELECT | |||
<include refid="measureColumns"/> | |||
from | |||
project_measures pm, snapshots s, projects p | |||
where | |||
pm.person_id=#{developerId,jdbcType=BIGINT} | |||
and pm.metric_id in | |||
<foreach item="metricId" collection="metricIds" open="(" separator="," close=")"> | |||
#{metricId} | |||
</foreach> | |||
and s.uuid=pm.analysis_uuid | |||
and s.islast=${_true} | |||
and p.uuid=pm.component_uuid | |||
and p.scope='PRJ' | |||
and p.qualifier='TRK' | |||
</select> | |||
<select id="selectByComponentsAndMetrics" parameterType="map" resultType="Measure"> | |||
select <include refid="measureColumns"/> | |||
from project_measures pm | |||
inner join snapshots analysis on analysis.uuid = pm.analysis_uuid and analysis.islast=${_true} | |||
inner join projects p on p.project_uuid=analysis.component_uuid and p.uuid=pm.component_uuid | |||
<where> | |||
and p.uuid in <foreach item="componentUuid" collection="componentUuids" open="(" separator="," close=")">#{componentUuid,jdbcType=VARCHAR}</foreach> | |||
and pm.metric_id in <foreach item="metricId" collection="metricIds" open="(" separator="," close=")">#{metricId,jdbcType=INTEGER}</foreach> | |||
and pm.person_id is null | |||
</where> | |||
</select> | |||
<insert id="insert" parameterType="Measure" useGeneratedKeys="false"> | |||
insert into project_measures ( | |||
value, | |||
@@ -191,7 +132,6 @@ | |||
text_value, | |||
alert_status, | |||
alert_text, | |||
person_id, | |||
variation_value_1, | |||
measure_data) | |||
VALUES ( | |||
@@ -202,7 +142,6 @@ | |||
#{textValue, jdbcType=VARCHAR}, | |||
#{alertStatus, jdbcType=VARCHAR}, | |||
#{alertText, jdbcType=VARCHAR}, | |||
#{developerId, jdbcType=INTEGER}, | |||
#{variation, jdbcType=DOUBLE}, | |||
#{dataValue, jdbcType=BINARY} | |||
) |
@@ -151,14 +151,10 @@ | |||
<foreach collection="analysisUuids" open="(" close=")" item="analysisUuid" separator=","> | |||
#{analysisUuid} | |||
</foreach> | |||
and (person_id is not null | |||
<if test="metricIds.size()>0"> | |||
or metric_id in | |||
<foreach collection="metricIds" open="(" item="metricId" separator="," close=")"> | |||
#{metricId} | |||
</foreach> | |||
</if> | |||
) | |||
and metric_id in | |||
<foreach collection="metricIds" open="(" item="metricId" separator="," close=")"> | |||
#{metricId,jdbcType=INTEGER} | |||
</foreach> | |||
</where> | |||
</delete> | |||
@@ -332,5 +328,8 @@ | |||
delete from project_branches where uuid=#{uuid,jdbcType=VARCHAR} | |||
</delete> | |||
<delete id="deleteLiveMeasuresByProjectUuid"> | |||
delete from live_measures where project_uuid = #{projectUuid,jdbcType=VARCHAR} | |||
</delete> | |||
</mapper> | |||
@@ -30,6 +30,6 @@ public class DaoModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new DaoModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 51); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 52); | |||
} | |||
} |
@@ -111,7 +111,6 @@ public class ComponentDaoTest { | |||
assertThat(result.scope()).isEqualTo("PRJ"); | |||
assertThat(result.language()).isNull(); | |||
assertThat(result.getCopyResourceUuid()).isNull(); | |||
assertThat(result.getDeveloperUuid()).isNull(); | |||
assertThat(result.isPrivate()).isTrue(); | |||
assertThat(underTest.selectByUuid(dbSession, "UNKNOWN")).isAbsent(); |
@@ -42,8 +42,7 @@ public class ComponentDtoTest { | |||
.setDescription("desc") | |||
.setPath("src/org/struts/RequestContext.java") | |||
.setCopyComponentUuid("uuid_5") | |||
.setRootUuid("uuid_3") | |||
.setDeveloperUuid("uuid_6"); | |||
.setRootUuid("uuid_3"); | |||
assertThat(componentDto.getId()).isEqualTo(1L); | |||
assertThat(componentDto.getDbKey()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java"); | |||
@@ -58,7 +57,6 @@ public class ComponentDtoTest { | |||
assertThat(componentDto.description()).isEqualTo("desc"); | |||
assertThat(componentDto.getRootUuid()).isEqualTo("uuid_3"); | |||
assertThat(componentDto.getCopyResourceUuid()).isEqualTo("uuid_5"); | |||
assertThat(componentDto.getDeveloperUuid()).isEqualTo("uuid_6"); | |||
assertThat(componentDto.isPrivate()).isFalse(); | |||
} | |||
@@ -0,0 +1,146 @@ | |||
/* | |||
* 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.db.measure; | |||
import java.util.List; | |||
import org.assertj.core.groups.Tuple; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.metric.MetricDto; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.measure.MeasureTesting.newLiveMeasure; | |||
public class LiveMeasureDaoTest { | |||
private static final int A_METRIC_ID = 42; | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private LiveMeasureDao underTest = db.getDbClient().liveMeasureDao(); | |||
@Test | |||
public void test_selectByComponentUuids() { | |||
LiveMeasureDto measure1 = newLiveMeasure().setMetricId(A_METRIC_ID); | |||
LiveMeasureDto measure2 = newLiveMeasure().setMetricId(A_METRIC_ID); | |||
underTest.insert(db.getSession(), measure1); | |||
underTest.insert(db.getSession(), measure2); | |||
List<LiveMeasureDto> selected = underTest.selectByComponentUuids(db.getSession(), asList(measure1.getComponentUuid(), measure2.getComponentUuid()), singletonList(A_METRIC_ID)); | |||
assertThat(selected) | |||
.extracting(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getProjectUuid, LiveMeasureDto::getMetricId, LiveMeasureDto::getValue, LiveMeasureDto::getDataAsString) | |||
.containsExactlyInAnyOrder( | |||
Tuple.tuple(measure1.getComponentUuid(), measure1.getProjectUuid(), measure1.getMetricId(), measure1.getValue(), measure1.getDataAsString()), | |||
Tuple.tuple(measure2.getComponentUuid(), measure2.getProjectUuid(), measure2.getMetricId(), measure2.getValue(), measure2.getDataAsString())); | |||
} | |||
@Test | |||
public void selectByComponentUuids_returns_empty_list_if_metric_does_not_match() { | |||
LiveMeasureDto measure = newLiveMeasure().setMetricId(10); | |||
underTest.insert(db.getSession(), measure); | |||
List<LiveMeasureDto> selected = underTest.selectByComponentUuids(db.getSession(), singletonList(measure.getComponentUuid()), singletonList(222)); | |||
assertThat(selected).isEmpty(); | |||
} | |||
@Test | |||
public void selectByComponentUuids_returns_empty_list_if_component_does_not_match() { | |||
LiveMeasureDto measure = newLiveMeasure(); | |||
underTest.insert(db.getSession(), measure); | |||
List<LiveMeasureDto> selected = underTest.selectByComponentUuids(db.getSession(), singletonList("_missing_"), singletonList(measure.getMetricId())); | |||
assertThat(selected).isEmpty(); | |||
} | |||
@Test | |||
public void test_selectMeasure() { | |||
MetricDto metric = db.measures().insertMetric(); | |||
LiveMeasureDto stored = newLiveMeasure().setMetricId(metric.getId()); | |||
underTest.insert(db.getSession(), stored); | |||
// metric exists but not component | |||
assertThat(underTest.selectMeasure(db.getSession(), "_missing_", metric.getKey())).isEmpty(); | |||
// component exists but not metric | |||
assertThat(underTest.selectMeasure(db.getSession(), stored.getComponentUuid(), "_missing_")).isEmpty(); | |||
// component and metric don't match | |||
assertThat(underTest.selectMeasure(db.getSession(), "_missing_", "_missing_")).isEmpty(); | |||
// matches | |||
assertThat(underTest.selectMeasure(db.getSession(), stored.getComponentUuid(), metric.getKey()).get()) | |||
.isEqualToComparingFieldByField(stored); | |||
} | |||
@Test | |||
public void test_insertOrUpdate() { | |||
// insert | |||
LiveMeasureDto dto = newLiveMeasure(); | |||
underTest.insertOrUpdate(db.getSession(), dto, "foo"); | |||
verifyPersisted(dto); | |||
verifyTableSize(1); | |||
// update | |||
dto.setValue(dto.getValue() + 1); | |||
dto.setVariation(dto.getVariation() + 10); | |||
dto.setData(dto.getDataAsString() + "_new"); | |||
underTest.insertOrUpdate(db.getSession(), dto, "foo"); | |||
verifyPersisted(dto); | |||
verifyTableSize(1); | |||
} | |||
@Test | |||
public void deleteByProjectUuidExcludingMarker() { | |||
LiveMeasureDto measure1 = newLiveMeasure().setProjectUuid("P1"); | |||
LiveMeasureDto measure2 = newLiveMeasure().setProjectUuid("P1"); | |||
LiveMeasureDto measure3DifferentMarker = newLiveMeasure().setProjectUuid("P1"); | |||
LiveMeasureDto measure4NoMarker = newLiveMeasure().setProjectUuid("P1"); | |||
LiveMeasureDto measure5OtherProject = newLiveMeasure().setProjectUuid("P2"); | |||
underTest.insertOrUpdate(db.getSession(), measure1, "foo"); | |||
underTest.insertOrUpdate(db.getSession(), measure2, "foo"); | |||
underTest.insertOrUpdate(db.getSession(), measure3DifferentMarker, "bar"); | |||
underTest.insertOrUpdate(db.getSession(), measure4NoMarker, null); | |||
underTest.insertOrUpdate(db.getSession(), measure5OtherProject, "foo"); | |||
underTest.deleteByProjectUuidExcludingMarker(db.getSession(), "P1", "foo"); | |||
verifyTableSize(3); | |||
verifyPersisted(measure1); | |||
verifyPersisted(measure2); | |||
verifyPersisted(measure5OtherProject); | |||
} | |||
private void verifyTableSize(int expectedSize) { | |||
assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(expectedSize); | |||
} | |||
private void verifyPersisted(LiveMeasureDto dto) { | |||
List<LiveMeasureDto> selected = underTest.selectByComponentUuids(db.getSession(), singletonList(dto.getComponentUuid()), singletonList(dto.getMetricId())); | |||
assertThat(selected).hasSize(1); | |||
assertThat(selected.get(0)).isEqualToComparingFieldByField(dto); | |||
} | |||
} |
@@ -19,45 +19,34 @@ | |||
*/ | |||
package org.sonar.db.measure; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactoryImpl; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.component.SnapshotTesting; | |||
import org.sonar.db.metric.MetricDto; | |||
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.UNIT_TEST_FILE; | |||
import static org.sonar.api.utils.DateUtils.parseDate; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.db.measure.MeasureTreeQuery.Strategy.CHILDREN; | |||
import static org.sonar.db.measure.MeasureTreeQuery.Strategy.LEAVES; | |||
public class MeasureDaoTest { | |||
private static final int COVERAGE_METRIC_ID = 10; | |||
private static final int COMPLEXITY_METRIC_ID = 11; | |||
private static final int NCLOC_METRIC_ID = 12; | |||
private static final long A_PERSON_ID = 444L; | |||
private static final String LAST_ANALYSIS_UUID = "A1"; | |||
private static final String OTHER_ANALYSIS_UUID = "A2"; | |||
private static final String PREVIOUS_ANALYSIS_UUID = "previous analysis UUID"; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@@ -70,37 +59,48 @@ public class MeasureDaoTest { | |||
private MeasureDao underTest = db.getDbClient().measureDao(); | |||
@Test | |||
public void test_inserted_and_selected_columns() { | |||
public void test_selectLastMeasure() { | |||
MetricDto metric = db.measures().insertMetric(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true); | |||
db.components().insertComponent(newFileDto(project).setUuid("C4")); | |||
MeasureDto inserted = new MeasureDto() | |||
.setAnalysisUuid(LAST_ANALYSIS_UUID) | |||
.setMetricId(2) | |||
.setDeveloperId(3L) | |||
.setComponentUuid("C4") | |||
.setValue(5.0d) | |||
.setData("data") | |||
.setVariation(1d) | |||
.setAlertStatus("alert") | |||
.setAlertText("alert-text"); | |||
underTest.insert(db.getSession(), inserted); | |||
db.commit(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
SnapshotDto lastAnalysis = insertAnalysis(project.uuid(), true); | |||
SnapshotDto pastAnalysis = insertAnalysis(project.uuid(), false); | |||
MeasureDto pastMeasure = MeasureTesting.newMeasureDto(metric, file, pastAnalysis); | |||
MeasureDto lastMeasure = MeasureTesting.newMeasureDto(metric, file, lastAnalysis); | |||
underTest.insert(db.getSession(), pastMeasure); | |||
underTest.insert(db.getSession(), lastMeasure); | |||
MeasureDto selected = underTest.selectLastMeasure(db.getSession(), file.uuid(), metric.getKey()).get(); | |||
assertThat(selected).isEqualToComparingFieldByField(lastMeasure); | |||
assertThat(underTest.selectLastMeasure(dbSession, "_missing_", metric.getKey())).isEmpty(); | |||
assertThat(underTest.selectLastMeasure(dbSession, file.uuid(), "_missing_")).isEmpty(); | |||
assertThat(underTest.selectLastMeasure(dbSession, "_missing_", "_missing_")).isEmpty(); | |||
} | |||
@Test | |||
public void test_selectMeasure() { | |||
MetricDto metric = db.measures().insertMetric(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
SnapshotDto lastAnalysis = insertAnalysis(project.uuid(), true); | |||
SnapshotDto pastAnalysis = insertAnalysis(project.uuid(), false); | |||
MeasureDto pastMeasure = MeasureTesting.newMeasureDto(metric, file, pastAnalysis); | |||
MeasureDto lastMeasure = MeasureTesting.newMeasureDto(metric, file, lastAnalysis); | |||
underTest.insert(db.getSession(), pastMeasure); | |||
underTest.insert(db.getSession(), lastMeasure); | |||
assertThat(underTest.selectMeasure(db.getSession(), lastAnalysis.getUuid(), file.uuid(), metric.getKey()).get()) | |||
.isEqualToComparingFieldByField(lastMeasure); | |||
assertThat(underTest.selectMeasure(db.getSession(), pastAnalysis.getUuid(), file.uuid(), metric.getKey()).get()) | |||
.isEqualToComparingFieldByField(pastMeasure); | |||
MeasureDto selected = underTest.selectSingle(db.getSession(), MeasureQuery.builder() | |||
.setComponentUuid(inserted.getComponentUuid()) | |||
.setPersonId(inserted.getDeveloperId()) | |||
.build()).get(); | |||
assertThat(selected.getAnalysisUuid()).isEqualTo(inserted.getAnalysisUuid()); | |||
assertThat(selected.getMetricId()).isEqualTo(inserted.getMetricId()); | |||
assertThat(selected.getDeveloperId()).isEqualTo(inserted.getDeveloperId()); | |||
assertThat(selected.getComponentUuid()).isEqualTo(inserted.getComponentUuid()); | |||
assertThat(selected.getValue()).isEqualTo(inserted.getValue()); | |||
assertThat(selected.getData()).isEqualTo(inserted.getData()); | |||
assertThat(selected.getVariation()).isEqualTo(inserted.getVariation()); | |||
assertThat(selected.getAlertStatus()).isEqualTo(inserted.getAlertStatus()); | |||
assertThat(selected.getAlertText()).isEqualTo(inserted.getAlertText()); | |||
assertThat(underTest.selectMeasure(db.getSession(), "_missing_", file.uuid(), metric.getKey())).isEmpty(); | |||
assertThat(underTest.selectMeasure(db.getSession(), pastAnalysis.getUuid(), "_missing_", metric.getKey())).isEmpty(); | |||
assertThat(underTest.selectMeasure(db.getSession(), pastAnalysis.getUuid(), file.uuid(), "_missing_")).isEmpty(); | |||
} | |||
@Test | |||
@@ -109,28 +109,25 @@ public class MeasureDaoTest { | |||
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); | |||
insertAnalysis(OTHER_ANALYSIS_UUID, project1.uuid(), false); | |||
SnapshotDto lastAnalysis = insertAnalysis(project1.uuid(), true); | |||
SnapshotDto pastAnalysis = insertAnalysis(project1.uuid(), false); | |||
String project2LastAnalysisUuid = "P2_LAST_ANALYSIS"; | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
insertAnalysis(project2LastAnalysisUuid, project2.uuid(), true); | |||
SnapshotDto project2LastAnalysis = insertAnalysis(project2.uuid(), true); | |||
// project 1 | |||
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("P1_M2", LAST_ANALYSIS_UUID, project1.uuid(), COVERAGE_METRIC_ID); | |||
insertMeasure("P1_M3", OTHER_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("P1_M1", lastAnalysis.getUuid(), project1.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("P1_M2", lastAnalysis.getUuid(), project1.uuid(), COVERAGE_METRIC_ID); | |||
insertMeasure("P1_M3", pastAnalysis.getUuid(), 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); | |||
insertMeasure("P2_M1", project2LastAnalysis.getUuid(), project2.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("P2_M2", project2LastAnalysis.getUuid(), 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); | |||
insertMeasure("M3", LAST_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID); | |||
insertMeasureOnPerson("M4", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, A_PERSON_ID); | |||
insertMeasureOnPerson("M5", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, 123L); | |||
insertMeasure("M1", pastAnalysis.getUuid(), "C1", NCLOC_METRIC_ID); | |||
insertMeasure("M2", lastAnalysis.getUuid(), "C1", NCLOC_METRIC_ID); | |||
insertMeasure("M3", lastAnalysis.getUuid(), "C1", COVERAGE_METRIC_ID); | |||
// component C2 | |||
insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID); | |||
insertMeasure("M6", lastAnalysis.getUuid(), "C2", NCLOC_METRIC_ID); | |||
db.commit(); | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), emptyList())); | |||
@@ -141,51 +138,37 @@ public class MeasureDaoTest { | |||
// all measures of component C1 of last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1"), "M2", "M3"); | |||
// all measures of component C1 of non last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(pastAnalysis.getUuid()), "M1"); | |||
// all measures of component C1 of last analysis by UUID | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(lastAnalysis.getUuid()), "M2", "M3"); | |||
// ncloc measure of component C1 of last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricId(NCLOC_METRIC_ID), "M2"); | |||
// ncloc measure of component C1 of non last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricId(NCLOC_METRIC_ID), "M1"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(pastAnalysis.getUuid()).setMetricId(NCLOC_METRIC_ID), "M1"); | |||
// ncloc measure of component C1 of last analysis by UUID | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(NCLOC_METRIC_ID), "M2"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(lastAnalysis.getUuid()).setMetricId(NCLOC_METRIC_ID), "M2"); | |||
// multiple measures of component C1 of last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M2", "M3"); | |||
// multiple measures of component C1 of non last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M1"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(pastAnalysis.getUuid()).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M1"); | |||
// multiple measures of component C1 of last analysis by UUID | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M2", "M3"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(lastAnalysis.getUuid()).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M2", "M3"); | |||
// missing measure of component C1 of last analysis | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricId(COMPLEXITY_METRIC_ID)); | |||
// missing measure of component C1 of non last analysis | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID)); | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(pastAnalysis.getUuid()).setMetricId(COMPLEXITY_METRIC_ID)); | |||
// missing measure of component C1 of last analysis by UUID | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID)); | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(lastAnalysis.getUuid()).setMetricId(COMPLEXITY_METRIC_ID)); | |||
// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis | |||
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(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(pastAnalysis.getUuid()), "M1"); | |||
// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis by UUID | |||
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)); | |||
// measures of missing developer of component C1 of non last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setPersonId(123L), "M5"); | |||
// measures of missing developer of component C1 of last analysis by UUID | |||
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setPersonId(123L)); | |||
// developer measures of component C1 of last analysis | |||
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setPersonId(A_PERSON_ID), "M4"); | |||
// developer measures of component C1 of non last analysis | |||
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"); | |||
verifyMeasures(MeasureQuery.builder().setComponentUuids(project1.uuid(), asList("C1", "C2", "C3")).setAnalysisUuid(lastAnalysis.getUuid()), "M2", "M3", "M6"); | |||
// projects measures of last analysis | |||
verifyMeasures(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID), "P1_M1"); | |||
@@ -194,113 +177,8 @@ public class MeasureDaoTest { | |||
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 selectSingle() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.components().insertComponent(newFileDto(project).setUuid("C1")); | |||
insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true); | |||
insertMeasure("M1", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID); | |||
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", COMPLEXITY_METRIC_ID); | |||
db.commit(); | |||
assertThat(selectSingle(MeasureQuery.builder().setComponentUuids(project.uuid(), emptyList()))).isNotPresent(); | |||
assertThat(selectSingle(MeasureQuery.builder().setComponentUuid("MISSING_COMPONENT"))).isNotPresent(); | |||
// select a single measure | |||
assertThat(selectSingle(MeasureQuery.builder().setComponentUuid("C1").setMetricId(NCLOC_METRIC_ID))).isPresent(); | |||
// select multiple measures -> fail | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("expected one element"); | |||
selectSingle(MeasureQuery.builder().setComponentUuid("C1")); | |||
} | |||
@Test | |||
public void select_tree_by_query() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
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); | |||
// 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"); | |||
} | |||
@Test | |||
public void select_tree_by_query_use_only_latest_analysis() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file1 = db.components().insertComponent(newFileDto(project).setUuid("C1").setName("File One")); | |||
db.components().insertComponent(newFileDto(project).setUuid("C2").setName("File Two").setQualifier(UNIT_TEST_FILE)); | |||
insertAnalysis(LAST_ANALYSIS_UUID, project.uuid(), true); | |||
insertAnalysis(OTHER_ANALYSIS_UUID, project.uuid(), false); | |||
// project | |||
insertMeasure("PROJECT_M1", LAST_ANALYSIS_UUID, project.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("PROJECT_M2", OTHER_ANALYSIS_UUID, project.uuid(), NCLOC_METRIC_ID); | |||
// component C1 | |||
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID); | |||
insertMeasure("M3", LAST_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID); | |||
insertMeasure("M4", OTHER_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID); | |||
// component C2 | |||
insertMeasure("M5", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID); | |||
insertMeasure("M6", OTHER_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID); | |||
db.commit(); | |||
// Children measures of project | |||
verifyMeasures(project, MeasureTreeQuery.builder().setStrategy(CHILDREN), "PROJECT_M1", "M2", "M3", "M5"); | |||
// 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", "M2", "M3", "M5"); | |||
// Leaves measure on file | |||
verifyMeasures(file1, MeasureTreeQuery.builder().setStrategy(LEAVES), "M2", "M3"); | |||
verifyMeasures(MeasureQuery.builder().setProjectUuids(singletonList(project1.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(pastAnalysis.getUuid()), "P1_M3"); | |||
verifyMeasures(MeasureQuery.builder().setProjectUuids(asList(project1.uuid(), project2.uuid())).setMetricId(NCLOC_METRIC_ID).setAnalysisUuid(pastAnalysis.getUuid()), "P1_M3"); | |||
} | |||
@Test | |||
@@ -309,14 +187,14 @@ public class MeasureDaoTest { | |||
long lastAnalysisDate = parseDate("2017-01-25").getTime(); | |||
long previousAnalysisDate = lastAnalysisDate - 10_000_000_000L; | |||
long oldAnalysisDate = lastAnalysisDate - 100_000_000_000L; | |||
dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setUuid(LAST_ANALYSIS_UUID).setCreatedAt(lastAnalysisDate)); | |||
dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setUuid(OTHER_ANALYSIS_UUID).setCreatedAt(previousAnalysisDate).setLast(false)); | |||
dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setUuid("OLD_ANALYSIS_UUID").setCreatedAt(oldAnalysisDate).setLast(false)); | |||
SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(lastAnalysisDate)); | |||
SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(previousAnalysisDate).setLast(false)); | |||
dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(oldAnalysisDate).setLast(false)); | |||
db.commit(); | |||
// project | |||
insertMeasure("PROJECT_M1", LAST_ANALYSIS_UUID, project.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("PROJECT_M2", OTHER_ANALYSIS_UUID, project.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("PROJECT_M1", lastAnalysis.getUuid(), project.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("PROJECT_M2", pastAnalysis.getUuid(), project.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("PROJECT_M3", "OLD_ANALYSIS_UUID", project.uuid(), NCLOC_METRIC_ID); | |||
db.commit(); | |||
@@ -327,58 +205,6 @@ public class MeasureDaoTest { | |||
assertThat(result).hasSize(2).extracting(MeasureDto::getData).containsOnly("PROJECT_M1", "PROJECT_M2"); | |||
} | |||
@Test | |||
public void selectByComponentsAndMetrics() { | |||
ComponentDto project1 = db.components().insertPrivateProject(db.getDefaultOrganization(), "P1"); | |||
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); | |||
insertAnalysis(OTHER_ANALYSIS_UUID, project1.uuid(), false); | |||
String project2LastAnalysisUuid = "P2_LAST_ANALYSIS"; | |||
ComponentDto project2 = db.components().insertPrivateProject(db.getDefaultOrganization(), "P2"); | |||
insertAnalysis(project2LastAnalysisUuid, project2.uuid(), true); | |||
// project 1 | |||
insertMeasure("P1_M1", LAST_ANALYSIS_UUID, project1.uuid(), NCLOC_METRIC_ID); | |||
insertMeasure("P1_M2", 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); | |||
insertMeasure("M3", LAST_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID); | |||
insertMeasureOnPerson("M4", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, A_PERSON_ID); | |||
insertMeasureOnPerson("M5", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, 123L); | |||
// component C2 | |||
insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID); | |||
db.commit(); | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), Collections.emptyList(), Collections.emptyList())).isEmpty(); | |||
// Measures of component C1 | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), singletonList("C1"), singletonList(NCLOC_METRIC_ID))).extracting(MeasureDto::getData).containsOnly("M2"); | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), singletonList("C1"), asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID))).extracting(MeasureDto::getData) | |||
.containsOnly("M2", "M3"); | |||
// ncloc measures of components C1, C2 | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), asList("C1", "C2"), asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID))).extracting(MeasureDto::getData) | |||
.containsOnly("M2", "M3", "M6"); | |||
// projects measures of last analysis | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), singletonList("P1"), singletonList(NCLOC_METRIC_ID))).extracting(MeasureDto::getData) | |||
.containsOnly("P1_M1"); | |||
assertThat(underTest.selectByComponentsAndMetrics(db.getSession(), asList("P1", "P2"), asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID))).extracting(MeasureDto::getData) | |||
.containsOnly("P1_M1", "P1_M2", "P2_M1", "P2_M2"); | |||
} | |||
private Optional<MeasureDto> selectSingle(MeasureQuery.Builder query) { | |||
return underTest.selectSingle(db.getSession(), query.build()); | |||
} | |||
private void verifyMeasures(MeasureQuery.Builder query, String... expectedIds) { | |||
List<MeasureDto> measures = underTest.selectByQuery(db.getSession(), query.build()); | |||
assertThat(measures).extracting(MeasureDto::getData).containsOnly(expectedIds); | |||
@@ -388,63 +214,22 @@ public class MeasureDaoTest { | |||
assertThat(underTest.selectByQuery(db.getSession(), query.build())).isEmpty(); | |||
} | |||
private void verifyMeasures(ComponentDto baseComponent, MeasureTreeQuery.Builder measureQuery, String... expectedIds) { | |||
List<MeasureDto> measures = new ArrayList<>(); | |||
underTest.selectTreeByQuery(db.getSession(), baseComponent, measureQuery.build(), result -> measures.add(result.getResultObject())); | |||
assertThat(measures).extracting(MeasureDto::getData).containsOnly(expectedIds); | |||
} | |||
private void insertMeasure(String id, String analysisUuid, String componentUuid, int metricId) { | |||
insertMeasure(id, analysisUuid, componentUuid, null, metricId); | |||
} | |||
private void insertMeasure(String id, String analysisUuid, String componentUuid, @Nullable Long developerId, int metricId) { | |||
MeasureDto measure = MeasureTesting.newMeasure() | |||
.setAnalysisUuid(analysisUuid) | |||
.setComponentUuid(componentUuid) | |||
.setMetricId(metricId) | |||
// as ids can't be forced when inserting measures, the field "data" | |||
// is used to store a virtual id. It is used then in assertions. | |||
.setData(id) | |||
.setDeveloperId(developerId); | |||
db.getDbClient().measureDao().insert(db.getSession(), measure); | |||
} | |||
private String insertComponent(String scope, String qualifier, boolean enabled) { | |||
String uuid = UuidFactoryImpl.INSTANCE.create(); | |||
ComponentDto componentDto = new ComponentDto() | |||
.setOrganizationUuid("org1") | |||
.setUuid(uuid) | |||
.setScope(scope) | |||
.setQualifier(qualifier) | |||
.setProjectUuid("don't care") | |||
.setRootUuid("don't care") | |||
.setUuidPath("don't care") | |||
.setDbKey("kee_" + uuid) | |||
.setEnabled(enabled); | |||
db.getDbClient().componentDao().insert(db.getSession(), componentDto); | |||
return uuid; | |||
} | |||
private void insertMeasureOnPerson(String id, String analysisUuid, String componentUuid, int metricId, long personId) { | |||
MeasureDto measure = MeasureTesting.newMeasure() | |||
.setAnalysisUuid(analysisUuid) | |||
.setComponentUuid(componentUuid) | |||
.setMetricId(metricId) | |||
.setDeveloperId(personId) | |||
// as ids can't be forced when inserting measures, the field "data" | |||
// is used to store a virtual id. It is used then in assertions. | |||
.setData(id); | |||
db.getDbClient().measureDao().insert(db.getSession(), measure); | |||
} | |||
private SnapshotDto insertAnalysis(String uuid, String projectUuid, boolean isLast) { | |||
private SnapshotDto insertAnalysis(String projectUuid, boolean isLast) { | |||
return db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newSnapshot() | |||
.setUuid(uuid) | |||
.setUuid(Uuids.createFast()) | |||
.setComponentUuid(projectUuid) | |||
.setLast(isLast)); | |||
} | |||
// TODO test selectPastMeasures | |||
} |
@@ -28,16 +28,15 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import static org.sonar.db.measure.MeasureTesting.newLiveMeasure; | |||
import static org.sonar.db.measure.MeasureTesting.newMeasureDto; | |||
import static org.sonar.db.metric.MetricTesting.newMetricDto; | |||
public class MeasureDbTester { | |||
private final DbTester db; | |||
private final DbClient dbClient; | |||
private final DbSession dbSession; | |||
public MeasureDbTester(DbTester db) { | |||
this.db = db; | |||
this.dbClient = db.getDbClient(); | |||
this.dbSession = db.getSession(); | |||
} | |||
@@ -51,6 +50,15 @@ public class MeasureDbTester { | |||
return measureDto; | |||
} | |||
@SafeVarargs | |||
public final LiveMeasureDto insertLiveMeasure(ComponentDto component, MetricDto metric, Consumer<LiveMeasureDto>... consumers){ | |||
LiveMeasureDto dto = newLiveMeasure(component, metric); | |||
Arrays.stream(consumers).forEach(c -> c.accept(dto)); | |||
dbClient.liveMeasureDao().insert(dbSession, dto); | |||
dbSession.commit(); | |||
return dto; | |||
} | |||
@SafeVarargs | |||
public final MetricDto insertMetric(Consumer<MetricDto>... consumers){ | |||
MetricDto metricDto = newMetricDto(); |
@@ -81,13 +81,6 @@ public class MeasureQueryTest { | |||
assertThat(query.getMetricIds()).isNull(); | |||
} | |||
@Test | |||
public void create_query_from_person_id() { | |||
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() { | |||
assertThat(MeasureQuery.builder() |
@@ -50,10 +50,29 @@ public class MeasureTesting { | |||
.setMetricId(cursor++) | |||
.setComponentUuid(String.valueOf(cursor++)) | |||
.setAnalysisUuid(String.valueOf(cursor++)) | |||
.setDeveloperId(null) | |||
.setData(String.valueOf(cursor++)) | |||
.setAlertStatus(String.valueOf(cursor++)) | |||
.setAlertText(String.valueOf(cursor++)) | |||
.setValue((double)cursor++); | |||
.setValue((double) cursor++); | |||
} | |||
public static LiveMeasureDto newLiveMeasure() { | |||
return new LiveMeasureDto() | |||
.setMetricId(cursor++) | |||
.setComponentUuid(String.valueOf(cursor++)) | |||
.setProjectUuid(String.valueOf(cursor++)) | |||
.setData(String.valueOf(cursor++)) | |||
.setValue((double) cursor++) | |||
.setVariation((double) cursor++); | |||
} | |||
public static LiveMeasureDto newLiveMeasure(ComponentDto component, MetricDto metric) { | |||
return new LiveMeasureDto() | |||
.setMetricId(metric.getId()) | |||
.setComponentUuid(component.uuid()) | |||
.setProjectUuid(component.projectUuid()) | |||
.setData(String.valueOf(cursor++)) | |||
.setValue((double) cursor++) | |||
.setVariation((double) cursor++); | |||
} | |||
} |
@@ -43,14 +43,12 @@ public class MeasureTreeQueryTest { | |||
.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 | |||
@@ -63,7 +61,6 @@ public class MeasureTreeQueryTest { | |||
assertThat(query.getQualifiers()).isNull(); | |||
assertThat(query.getNameOrKeyQuery()).isNull(); | |||
assertThat(query.getMetricIds()).isNull(); | |||
assertThat(query.getPersonId()).isNull(); | |||
} | |||
@Test |
@@ -29,26 +29,22 @@ public class PastMeasureDtoTest { | |||
public void test_getter_and_setter() throws Exception { | |||
PastMeasureDto dto = new PastMeasureDto() | |||
.setValue(1d) | |||
.setMetricId(2) | |||
.setPersonId(5L); | |||
.setMetricId(2); | |||
assertThat(dto.hasValue()).isTrue(); | |||
assertThat(dto.getValue()).isEqualTo(1d); | |||
assertThat(dto.getMetricId()).isEqualTo(2); | |||
assertThat(dto.getPersonId()).isEqualTo(5L); | |||
} | |||
@Test | |||
public void test_has_value() throws Exception { | |||
PastMeasureDto measureWithValue = new PastMeasureDto() | |||
.setValue(1d) | |||
.setMetricId(2) | |||
.setPersonId(5L); | |||
.setMetricId(2); | |||
assertThat(measureWithValue.hasValue()).isTrue(); | |||
PastMeasureDto measureWithoutValue = new PastMeasureDto() | |||
.setMetricId(2) | |||
.setPersonId(5L); | |||
.setMetricId(2); | |||
assertThat(measureWithoutValue.hasValue()).isFalse(); | |||
} | |||
@@ -25,7 +25,6 @@ import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
@@ -35,7 +34,6 @@ import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.ProjectMeasuresIndexerIterator.ProjectMeasures; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -48,7 +46,6 @@ import static org.sonar.api.measures.Metric.ValueType.DISTRIB; | |||
import static org.sonar.api.measures.Metric.ValueType.INT; | |||
import static org.sonar.api.measures.Metric.ValueType.LEVEL; | |||
import static org.sonar.api.measures.Metric.ValueType.STRING; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
@@ -64,12 +61,13 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void return_project_measure() { | |||
MetricDto metric1 = insertIntMetric("ncloc"); | |||
MetricDto metric2 = insertIntMetric("coverage"); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setDbKey("Project-Key").setName("Project Name").setTagsString("platform,java"); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasure(project, analysis, metric1, 10d); | |||
insertMeasure(project, analysis, metric2, 20d); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization, p -> p.setDbKey("Project-Key").setName("Project Name").setTagsString("platform,java")); | |||
SnapshotDto analysis = dbTester.components().insertSnapshot(project); | |||
MetricDto metric1 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("ncloc")); | |||
MetricDto metric2 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("coverage")); | |||
dbTester.measures().insertLiveMeasure(project, metric1, m -> m.setValue(10d)); | |||
dbTester.measures().insertLiveMeasure(project, metric2, m -> m.setValue(20d)); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -81,15 +79,15 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
assertThat(doc.getProject().getName()).isEqualTo("Project Name"); | |||
assertThat(doc.getProject().getTags()).containsExactly("platform", "java"); | |||
assertThat(doc.getProject().getAnalysisDate()).isNotNull().isEqualTo(analysis.getCreatedAt()); | |||
assertThat(doc.getMeasures().getNumericMeasures()).containsOnly(entry("ncloc", 10d), entry("coverage", 20d)); | |||
assertThat(doc.getMeasures().getNumericMeasures()).containsOnly(entry(metric1.getKey(), 10d), entry(metric2.getKey(), 20d)); | |||
} | |||
@Test | |||
public void return_project_measure_having_leak() throws Exception { | |||
MetricDto metric = insertIntMetric("new_lines"); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasureOnLeak(project, analysis, metric, 10d); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization, p -> p.setDbKey("Project-Key").setName("Project Name").setTagsString("platform,java")); | |||
MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("new_lines")); | |||
dbTester.measures().insertLiveMeasure(project, metric, m -> m.setVariation(10d)); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -98,34 +96,40 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void return_quality_gate_status_measure() throws Exception { | |||
MetricDto metric = insertMetric("alert_status", LEVEL); | |||
insertProjectAndMeasure("project1", metric, WARN.name()); | |||
insertProjectAndMeasure("project2", metric, OK.name()); | |||
insertProjectAndMeasure("project3", metric, ERROR.name()); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project1 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project2 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project3 = dbTester.components().insertPrivateProject(organization); | |||
MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(LEVEL.name()).setKey("alert_status")); | |||
dbTester.measures().insertLiveMeasure(project1, metric, m -> m.setValue(null).setData(WARN.name())); | |||
dbTester.measures().insertLiveMeasure(project2, metric, m -> m.setValue(null).setData(OK.name())); | |||
dbTester.measures().insertLiveMeasure(project3, metric, m -> m.setValue(null).setData(ERROR.name())); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
assertThat(docsById.get("project1").getMeasures().getQualityGateStatus()).isEqualTo("WARN"); | |||
assertThat(docsById.get("project2").getMeasures().getQualityGateStatus()).isEqualTo("OK"); | |||
assertThat(docsById.get("project3").getMeasures().getQualityGateStatus()).isEqualTo("ERROR"); | |||
assertThat(docsById.get(project1.uuid()).getMeasures().getQualityGateStatus()).isEqualTo("WARN"); | |||
assertThat(docsById.get(project2.uuid()).getMeasures().getQualityGateStatus()).isEqualTo("OK"); | |||
assertThat(docsById.get(project3.uuid()).getMeasures().getQualityGateStatus()).isEqualTo("ERROR"); | |||
} | |||
@Test | |||
public void does_not_fail_when_quality_gate_has_no_value() throws Exception { | |||
MetricDto metric = insertMetric("alert_status", LEVEL); | |||
insertProjectAndMeasure("project", metric, null); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(LEVEL.name()).setKey("alert_status")); | |||
dbTester.measures().insertLiveMeasure(project, metric, m -> m.setValue(null).setVariation(null).setData((String) null)); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
assertThat(docsById.get("project").getMeasures().getNumericMeasures()).isEmpty(); | |||
assertThat(docsById.get(project.uuid()).getMeasures().getNumericMeasures()).isEmpty(); | |||
} | |||
@Test | |||
public void return_language_distribution_measure() throws Exception { | |||
MetricDto metric = insertMetric("ncloc_language_distribution", DATA); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasure(project, analysis, metric, "<null>=2;java=6;xoo=18"); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(DATA.name()).setKey("ncloc_language_distribution")); | |||
dbTester.measures().insertLiveMeasure(project, metric, m -> m.setValue(null).setData("<null>=2;java=6;xoo=18")); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -135,14 +139,14 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void does_not_return_none_numeric_metrics() throws Exception { | |||
MetricDto dataMetric = insertMetric("data", DATA); | |||
MetricDto distribMetric = insertMetric("distrib", DISTRIB); | |||
MetricDto stringMetric = insertMetric("string", STRING); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasure(project, analysis, dataMetric, "dat"); | |||
insertMeasure(project, analysis, distribMetric, "dis"); | |||
insertMeasure(project, analysis, stringMetric, "str"); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MetricDto dataMetric = dbTester.measures().insertMetric(m -> m.setValueType(DATA.name()).setKey("data")); | |||
MetricDto distribMetric = dbTester.measures().insertMetric(m -> m.setValueType(DISTRIB.name()).setKey("distrib")); | |||
MetricDto stringMetric = dbTester.measures().insertMetric(m -> m.setValueType(STRING.name()).setKey("string")); | |||
dbTester.measures().insertLiveMeasure(project, dataMetric, m -> m.setData("dat")); | |||
dbTester.measures().insertLiveMeasure(project, distribMetric, m -> m.setData("dis")); | |||
dbTester.measures().insertLiveMeasure(project, stringMetric, m -> m.setData("str")); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -151,10 +155,10 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void does_not_return_disabled_metrics() throws Exception { | |||
MetricDto disabledMetric = insertMetric("disabled", false, false, INT); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasure(project, analysis, disabledMetric, 10d); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MetricDto disabledMetric = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setEnabled(false).setHidden(false).setKey("disabled")); | |||
dbTester.measures().insertLiveMeasure(project, disabledMetric, m -> m.setValue(10d)); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -163,29 +167,28 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void ignore_measure_that_does_not_have_value() throws Exception { | |||
MetricDto metric1 = insertIntMetric("coverage"); | |||
MetricDto metric2 = insertIntMetric("ncloc"); | |||
MetricDto leakMetric = insertIntMetric("new_lines"); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
MetricDto metric1 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("coverage")); | |||
MetricDto metric2 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("ncloc")); | |||
MetricDto leakMetric = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("new_lines")); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MeasureDto withValue = insertMeasure(project, analysis, metric1, 10d); | |||
MeasureDto withLeakValue = insertMeasure(project, analysis, leakMetric, null, 20d); | |||
MeasureDto withoutValue = insertMeasure(project, analysis, metric2, null, null); | |||
dbTester.measures().insertLiveMeasure(project, metric1, m -> m.setValue(10d)); | |||
dbTester.measures().insertLiveMeasure(project, leakMetric, m -> m.setValue(null).setVariation(20d)); | |||
dbTester.measures().insertLiveMeasure(project, metric2, m -> m.setValue(null).setVariation(null)); | |||
Map<String, Double> numericMeasures = createResultSetAndReturnDocsById().get(project.uuid()).getMeasures().getNumericMeasures(); | |||
assertThat(numericMeasures).containsOnly(entry("coverage", 10d), entry("new_lines", 20d)); | |||
assertThat(numericMeasures).containsOnly(entry(metric1.getKey(), 10d), entry(leakMetric.getKey(), 20d)); | |||
} | |||
@Test | |||
public void ignore_numeric_measure_that_has_text_value_but_not_numeric_value() throws Exception { | |||
MetricDto metric1 = insertIntMetric("coverage"); | |||
MetricDto metric2 = insertIntMetric("ncloc"); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
MeasureDto withNumericValue = insertMeasure(project, analysis, metric1, 10d); | |||
MeasureDto withTextValue = insertMeasure(project, analysis, metric2, "foo"); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
MetricDto metric1 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("coverage")); | |||
MetricDto metric2 = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("ncloc")); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
dbTester.measures().insertLiveMeasure(project, metric1, m -> m.setValue(10d).setData((String) null)); | |||
dbTester.measures().insertLiveMeasure(project, metric2, m -> m.setValue(null).setData("foo")); | |||
Map<String, Double> numericMeasures = createResultSetAndReturnDocsById().get(project.uuid()).getMeasures().getNumericMeasures(); | |||
assertThat(numericMeasures).containsOnly(entry("coverage", 10d)); | |||
@@ -193,9 +196,13 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void return_many_project_measures() { | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project1 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project2 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project3 = dbTester.components().insertPrivateProject(organization); | |||
dbTester.components().insertSnapshot(project1); | |||
dbTester.components().insertSnapshot(project2); | |||
dbTester.components().insertSnapshot(project3); | |||
assertThat(createResultSetAndReturnDocsById()).hasSize(3); | |||
} | |||
@@ -215,42 +222,47 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void does_not_return_non_active_projects() throws Exception { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
// Disabled project | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setEnabled(false)); | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)); | |||
// Disabled project with analysis | |||
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setEnabled(false)); | |||
ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)); | |||
dbClient.snapshotDao().insert(dbSession, newAnalysis(project)); | |||
// A view | |||
dbTester.components().insertProjectAndSnapshot(newView(dbTester.getDefaultOrganization())); | |||
dbTester.components().insertProjectAndSnapshot(newView(organization)); | |||
dbSession.commit(); | |||
assertResultSetIsEmpty(); | |||
assertThat(createResultSetAndReturnDocsById()).isEmpty(); | |||
} | |||
@Test | |||
public void return_only_docs_from_given_project() throws Exception { | |||
OrganizationDto organizationDto = dbTester.organizations().insert(); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(organizationDto); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto)); | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto)); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project1 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project2 = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto project3 = dbTester.components().insertPrivateProject(organization); | |||
SnapshotDto analysis1 = dbTester.components().insertSnapshot(project1); | |||
SnapshotDto analysis2 = dbTester.components().insertSnapshot(project2); | |||
SnapshotDto analysis3 = dbTester.components().insertSnapshot(project3); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(project.uuid()); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(project1.uuid()); | |||
assertThat(docsById).hasSize(1); | |||
ProjectMeasures doc = docsById.get(project.uuid()); | |||
ProjectMeasures doc = docsById.get(project1.uuid()); | |||
assertThat(doc).isNotNull(); | |||
assertThat(doc.getProject().getUuid()).isEqualTo(project.uuid()); | |||
assertThat(doc.getProject().getKey()).isNotNull().isEqualTo(project.getDbKey()); | |||
assertThat(doc.getProject().getName()).isNotNull().isEqualTo(project.name()); | |||
assertThat(doc.getProject().getAnalysisDate()).isNotNull().isEqualTo(analysis.getCreatedAt()); | |||
assertThat(doc.getProject().getUuid()).isEqualTo(project1.uuid()); | |||
assertThat(doc.getProject().getKey()).isNotNull().isEqualTo(project1.getDbKey()); | |||
assertThat(doc.getProject().getName()).isNotNull().isEqualTo(project1.name()); | |||
assertThat(doc.getProject().getAnalysisDate()).isNotNull().isEqualTo(analysis1.getCreatedAt()); | |||
} | |||
@Test | |||
public void return_nothing_on_unknown_project() throws Exception { | |||
dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
dbTester.components().insertSnapshot(project); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById("UNKNOWN"); | |||
@@ -259,14 +271,13 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
@Test | |||
public void non_main_branches_are_not_indexed() { | |||
MetricDto metric = insertIntMetric("ncloc"); | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); | |||
SnapshotDto projectAnalysis = dbTester.components().insertProjectAndSnapshot(project); | |||
insertMeasure(project, projectAnalysis, metric, 10d); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("ncloc")); | |||
dbTester.measures().insertLiveMeasure(project, metric, m -> m.setValue(10d)); | |||
ComponentDto branch = dbTester.components().insertProjectBranch(project, b -> b.setKey("feature/foo")); | |||
SnapshotDto branchAnalysis = dbTester.components().insertSnapshot(branch); | |||
insertMeasure(branch, branchAnalysis, metric, 20d); | |||
dbTester.measures().insertLiveMeasure(branch, metric, m -> m.setValue(20d)); | |||
Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); | |||
@@ -284,56 +295,4 @@ public class ProjectMeasuresIndexerIteratorTest { | |||
it.close(); | |||
return docsById; | |||
} | |||
private void assertResultSetIsEmpty() { | |||
assertThat(createResultSetAndReturnDocsById()).isEmpty(); | |||
} | |||
private MetricDto insertIntMetric(String metricKey) { | |||
return insertMetric(metricKey, true, false, INT); | |||
} | |||
private MetricDto insertMetric(String metricKey, Metric.ValueType type) { | |||
return insertMetric(metricKey, true, false, type); | |||
} | |||
private MetricDto insertMetric(String metricKey, boolean enabled, boolean hidden, Metric.ValueType type) { | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, | |||
MetricTesting.newMetricDto() | |||
.setKey(metricKey) | |||
.setEnabled(enabled) | |||
.setHidden(hidden) | |||
.setValueType(type.name())); | |||
dbSession.commit(); | |||
return metric; | |||
} | |||
private MeasureDto insertProjectAndMeasure(String projectUuid, MetricDto metric, String value) { | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), projectUuid); | |||
SnapshotDto analysis1 = dbTester.components().insertProjectAndSnapshot(project); | |||
return insertMeasure(project, analysis1, metric, value); | |||
} | |||
private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, double value) { | |||
return insertMeasure(project, analysis, metric, value, null); | |||
} | |||
private MeasureDto insertMeasureOnLeak(ComponentDto project, SnapshotDto analysis, MetricDto metric, double value) { | |||
return insertMeasure(project, analysis, metric, null, value); | |||
} | |||
private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, String value) { | |||
return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setData(value)); | |||
} | |||
private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, @Nullable Double value, @Nullable Double leakValue) { | |||
return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setValue(value).setVariation(leakValue)); | |||
} | |||
private MeasureDto insertMeasure(MeasureDto measure) { | |||
dbClient.measureDao().insert(dbSession, measure); | |||
dbSession.commit(); | |||
return measure; | |||
} | |||
} |
@@ -164,7 +164,7 @@ public class PurgeCommandsTest { | |||
@Test | |||
public void deletePermissions_deletes_permissions_of_view() { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertView(organization); | |||
ComponentDto project = dbTester.components().insertPublicPortfolio(organization); | |||
addPermissions(organization, project); | |||
PurgeCommands purgeCommands = new PurgeCommands(dbTester.getSession(), profiler); |
@@ -50,6 +50,7 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.custom.CustomMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
@@ -86,7 +87,7 @@ public class PurgeDaoTest { | |||
private PurgeDao underTest = dbTester.getDbClient().purgeDao(); | |||
@Test | |||
public void shouldDeleteAbortedBuilds() { | |||
public void purge_failed_ce_tasks() { | |||
dbTester.prepareDbUnit(getClass(), "shouldDeleteAbortedBuilds.xml"); | |||
underTest.purge(dbSession, newConfigurationWith30Days(), PurgeListener.EMPTY, new PurgeProfiler()); | |||
@@ -96,7 +97,7 @@ public class PurgeDaoTest { | |||
} | |||
@Test | |||
public void should_purge_project() { | |||
public void purge_history_of_project() { | |||
dbTester.prepareDbUnit(getClass(), "shouldPurgeProject.xml"); | |||
underTest.purge(dbSession, newConfigurationWith30Days(), PurgeListener.EMPTY, new PurgeProfiler()); | |||
dbSession.commit(); | |||
@@ -104,7 +105,7 @@ public class PurgeDaoTest { | |||
} | |||
@Test | |||
public void should_purge_inactive_short_living_branches() { | |||
public void purge_inactive_short_living_branches() { | |||
when(system2.now()).thenReturn(new Date().getTime()); | |||
RuleDefinitionDto rule = dbTester.rules().insert(); | |||
ComponentDto project = dbTester.components().insertMainBranch(); | |||
@@ -394,6 +395,26 @@ public class PurgeDaoTest { | |||
verifyNoEffect(componentDbTester.insertView(), componentDbTester.insertPrivateProject(), componentDbTester.insertPublicProject()); | |||
} | |||
@Test | |||
public void delete_live_measures_when_deleting_project() { | |||
MetricDto metric = dbTester.measures().insertMetric(); | |||
ComponentDto project1 = dbTester.components().insertPublicProject(); | |||
ComponentDto module1 = dbTester.components().insertComponent(ComponentTesting.newModuleDto(project1)); | |||
dbTester.measures().insertLiveMeasure(project1, metric); | |||
dbTester.measures().insertLiveMeasure(module1, metric); | |||
ComponentDto project2 = dbTester.components().insertPublicProject(); | |||
ComponentDto module2 = dbTester.components().insertComponent(ComponentTesting.newModuleDto(project2)); | |||
dbTester.measures().insertLiveMeasure(project2, metric); | |||
dbTester.measures().insertLiveMeasure(module2, metric); | |||
underTest.deleteProject(dbSession, project1.uuid()); | |||
assertThat(dbClient.liveMeasureDao().selectByComponentUuids(dbSession, asList(project1.uuid(), module1.uuid()), asList(metric.getId()))).isEmpty(); | |||
assertThat(dbClient.liveMeasureDao().selectByComponentUuids(dbSession, asList(project2.uuid(), module2.uuid()), asList(metric.getId()))).hasSize(2); | |||
} | |||
private void verifyNoEffect(ComponentDto firstRoot, ComponentDto... otherRoots) { | |||
DbSession dbSession = mock(DbSession.class); | |||
@@ -4,7 +4,7 @@ | |||
analysis_uuid="u2" | |||
metric_id="3" | |||
component_uuid="FILE1" | |||
person_id="23" | |||
person_id="[null]" | |||
value="2.0" | |||
text_value="measure-value" | |||
measure_data="[null]" |
@@ -1,59 +0,0 @@ | |||
<dataset> | |||
<metrics delete_historical_data="[null]" | |||
id="1" | |||
name="sqale_index" | |||
VAL_TYPE="INT" | |||
DESCRIPTION="[null]" | |||
enabled="[true]"/> | |||
<!-- project --> | |||
<projects organization_uuid="org1" | |||
uuid="ABCD" | |||
uuid_path="NOT_USED" | |||
project_uuid="ABCD" | |||
module_uuid="[null]" | |||
module_uuid_path=".ABCD." | |||
enabled="[true]" | |||
long_name="[null]" | |||
id="1" | |||
scope="PRJ" | |||
qualifier="TRK" | |||
kee="project" | |||
name="project" | |||
root_uuid="ABCD"/> | |||
<!-- snapshots --> | |||
<snapshots id="1000" | |||
uuid="u1000" | |||
component_uuid="ABCD" | |||
created_at="1225544280000" | |||
build_date="1225544280000" | |||
version="[null]" | |||
status="P" | |||
islast="[false]" | |||
/> | |||
<!-- project measures --> | |||
<project_measures id="1" | |||
VALUE="60" | |||
METRIC_ID="1" | |||
analysis_uuid="u1000" | |||
person_id="[null]" | |||
component_uuid="ABCD"/> | |||
<project_measures id="2" | |||
VALUE="20" | |||
METRIC_ID="1" | |||
analysis_uuid="u1000" | |||
person_id="20" | |||
component_uuid="ABCD"/> | |||
<project_measures id="3" | |||
VALUE="40" | |||
METRIC_ID="1" | |||
analysis_uuid="u1000" | |||
person_id="21" | |||
component_uuid="ABCD"/> | |||
</dataset> |
@@ -1,123 +0,0 @@ | |||
<dataset> | |||
<metrics id="10" | |||
name="authors_by_line"/> | |||
<metrics id="11" | |||
name="coverage_line_hits_data"/> | |||
<metrics id="12" | |||
name="ncloc"/> | |||
<projects organization_uuid="org1" | |||
uuid="uuid_1" | |||
uuid_path="NOT_USED" | |||
root_uuid="uuid_1" | |||
id="1" | |||
kee="org.struts:struts-core:src/org/struts/RequestContext.java" | |||
enabled="[true]"/> | |||
<projects organization_uuid="org1" | |||
uuid="333" | |||
uuid_path="NOT_USED" | |||
root_uuid="333" | |||
id="333" | |||
kee="dev:John-Doe" | |||
enabled="[true]"/> | |||
<snapshots id="5" | |||
uuid="u5" | |||
component_uuid="uuid_1" | |||
islast="[true]" | |||
/> | |||
<project_measures id="20" | |||
analysis_uuid="u5" | |||
metric_id="10" | |||
value="[null]" | |||
text_value="0123456789012345678901234567890123456789" | |||
measure_data="[null]" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" | |||
variation_value_4="[null]" | |||
variation_value_5="[null]" | |||
alert_status="[null]" | |||
alert_text="[null]" | |||
person_id="[null]" | |||
component_uuid="1"/> | |||
<project_measures id="21" | |||
analysis_uuid="u5" | |||
metric_id="11" | |||
value="[null]" | |||
text_value="36=1;37=1;38=1;39=1;43=1;48=1;53=1" | |||
measure_data="[null]" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" | |||
variation_value_4="[null]" | |||
variation_value_5="[null]" | |||
alert_status="[null]" | |||
alert_text="[null]" | |||
person_id="[null]" | |||
component_uuid="1"/> | |||
<project_measures id="22" | |||
analysis_uuid="u5" | |||
metric_id="12" | |||
value="10" | |||
text_value="[null]" | |||
measure_data="[null]" | |||
variation_value_1="1" | |||
variation_value_2="2" | |||
variation_value_3="3" | |||
variation_value_4="4" | |||
variation_value_5="-5" | |||
alert_status="OK" | |||
alert_text="Green" | |||
person_id="[null]" | |||
component_uuid="1"/> | |||
<!--measures for developer 333--> | |||
<project_measures id="30" | |||
analysis_uuid="u5" | |||
metric_id="10" | |||
value="[null]" | |||
text_value="0123456789012345678901234567890123456789" | |||
measure_data="[null]" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" | |||
variation_value_4="[null]" | |||
variation_value_5="[null]" | |||
alert_status="[null]" | |||
alert_text="[null]" | |||
person_id="333" | |||
component_uuid="1"/> | |||
<project_measures id="31" | |||
analysis_uuid="u5" | |||
metric_id="11" | |||
value="[null]" | |||
text_value="36=1;37=1;38=1;39=1;43=1;48=1;53=1" | |||
measure_data="[null]" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" | |||
variation_value_4="[null]" | |||
variation_value_5="[null]" | |||
alert_status="[null]" | |||
alert_text="[null]" | |||
person_id="333" | |||
component_uuid="1"/> | |||
<project_measures id="32" | |||
analysis_uuid="u5" | |||
metric_id="12" | |||
value="10" | |||
text_value="[null]" | |||
measure_data="[null]" | |||
variation_value_1="1" | |||
variation_value_2="2" | |||
variation_value_3="3" | |||
variation_value_4="4" | |||
variation_value_5="-5" | |||
alert_status="OK" | |||
alert_text="Green" | |||
person_id="333" | |||
component_uuid="1"/> | |||
</dataset> |
@@ -90,23 +90,4 @@ | |||
description="[null]" | |||
measure_data="[null]"/> | |||
<!-- delete measure on developers --> | |||
<project_measures id="7" | |||
component_uuid="1" | |||
analysis_uuid="u1" | |||
metric_id="2" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" | |||
person_id="123456" | |||
variation_value_4="[null]" | |||
variation_value_5="[null]" | |||
alert_text="[null]" | |||
value="10.0" | |||
text_value="[null]" | |||
tendency="[null]" | |||
measure_date="[null]" | |||
alert_status="[null]" | |||
description="[null]" | |||
measure_data="[null]"/> | |||
</dataset> |
@@ -111,7 +111,6 @@ | |||
<project_measures ID="2" | |||
component_uuid="2" | |||
analysis_uuid="u2" | |||
characteristic_id="[null]" | |||
variation_value_1="[null]" | |||
variation_value_2="[null]" | |||
variation_value_3="[null]" |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.platform.db.migration.step; | |||
import java.io.ByteArrayInputStream; | |||
import java.sql.PreparedStatement; | |||
import java.sql.SQLException; | |||
import java.sql.Timestamp; | |||
@@ -76,6 +77,16 @@ class BaseSqlStatement<CHILD extends SqlStatement> implements SqlStatement<CHILD | |||
return (CHILD) this; | |||
} | |||
@Override | |||
public CHILD setBytes(int columnIndex, @Nullable byte[] value) throws SQLException { | |||
if (value == null) { | |||
pstmt.setNull(columnIndex, Types.BINARY); | |||
} else { | |||
pstmt.setBinaryStream(columnIndex, new ByteArrayInputStream(value)); | |||
} | |||
return (CHILD) this; | |||
} | |||
@Override | |||
public CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException { | |||
if (value == null) { |
@@ -22,6 +22,7 @@ package org.sonar.server.platform.db.migration.step; | |||
import java.sql.Connection; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.db.dialect.Dialect; | |||
public abstract class DataChange implements MigrationStep { | |||
@@ -31,6 +32,10 @@ public abstract class DataChange implements MigrationStep { | |||
this.db = db; | |||
} | |||
protected final Dialect getDialect() { | |||
return db.getDialect(); | |||
} | |||
@Override | |||
public final void execute() throws SQLException { | |||
try (Connection readConnection = createReadUncommittedConnection(); |
@@ -26,6 +26,8 @@ import javax.annotation.Nullable; | |||
public interface SqlStatement<CHILD extends SqlStatement> extends AutoCloseable { | |||
CHILD setBoolean(int columnIndex, @Nullable Boolean value) throws SQLException; | |||
CHILD setBytes(int columnIndex, @Nullable byte[] value) throws SQLException; | |||
CHILD setDate(int columnIndex, @Nullable Date value) throws SQLException; | |||
CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException; |
@@ -0,0 +1,125 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.BlobColumnDef.newBlobColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.DecimalColumnDef.newDecimalColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.IntegerColumnDef.newIntegerColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class CreateTableLiveMeasures extends DdlChange { | |||
private static final String TABLE_NAME = "live_measures"; | |||
public CreateTableLiveMeasures(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME) | |||
.addPkColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("uuid") | |||
.setIsNullable(false) | |||
.setLimit(VarcharColumnDef.UUID_SIZE) | |||
.build()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("project_uuid") | |||
.setIsNullable(false) | |||
.setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE) | |||
.build()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("component_uuid") | |||
.setIsNullable(false) | |||
.setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE) | |||
.build()) | |||
.addColumn(newIntegerColumnDefBuilder() | |||
.setColumnName("metric_id") | |||
.setIsNullable(false) | |||
.build()) | |||
.addColumn(newDecimalColumnDefBuilder() | |||
.setColumnName("value") | |||
.setPrecision(38) | |||
.setScale(20) | |||
.build()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("text_value") | |||
.setIsNullable(true) | |||
.setLimit(4_000) | |||
.build()) | |||
.addColumn(newDecimalColumnDefBuilder() | |||
.setColumnName("variation") | |||
.setPrecision(38) | |||
.setScale(20) | |||
.build()) | |||
.addColumn(newBlobColumnDefBuilder() | |||
.setColumnName("measure_data") | |||
.build()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("update_marker") | |||
.setIsNullable(true) | |||
.setLimit(UUID_SIZE) | |||
.build()) | |||
.addColumn(newBigIntegerColumnDefBuilder() | |||
.setColumnName("created_at") | |||
.setIsNullable(false) | |||
.build()) | |||
.addColumn(newBigIntegerColumnDefBuilder() | |||
.setColumnName("updated_at") | |||
.setIsNullable(false) | |||
.build()) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("project_uuid") | |||
.setIsNullable(false) | |||
.setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE) | |||
.build()) | |||
.setUnique(false) | |||
.setTable(TABLE_NAME) | |||
.setName("live_measures_project") | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("component_uuid") | |||
.setIsNullable(false) | |||
.setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE) | |||
.build()) | |||
.addColumn(newIntegerColumnDefBuilder() | |||
.setColumnName("metric_id") | |||
.setIsNullable(false) | |||
.build()) | |||
.setUnique(true) | |||
.setTable(TABLE_NAME) | |||
.setName("live_measures_component") | |||
.build()); | |||
} | |||
} |
@@ -32,7 +32,11 @@ public class DbVersion70 implements DbVersion { | |||
.add(1902, "Make QUALITY_GATES.IS_BUILT_IN not null", MakeQualityGatesIsBuiltInNotNullable.class) | |||
.add(1903, "Remove quality gates loaded templates", RemoveQualityGateLoadedTemplates.class) | |||
.add(1904, "Rename quality gate \"SonarQube way\" to \"Sonar way\"", RenameOldSonarQubeWayQualityGate.class) | |||
.add(1905, "Drop LOADED_TEMPLATES table", DropLoadedTemplatesTable.class); | |||
.add(1905, "Drop LOADED_TEMPLATES table", DropLoadedTemplatesTable.class) | |||
.add(1906, "Create table live_measures", CreateTableLiveMeasures.class) | |||
.add(1907, "Populate table live_measures", PopulateLiveMeasures.class) | |||
.add(1908, "Delete person and file measures", DeletePersonAndFileMeasures.class) | |||
.add(1909, "Drop index on project_measures.person_id", DropIndexOnPersonMeasures.class) | |||
; | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.db.dialect.H2; | |||
import org.sonar.db.dialect.MsSql; | |||
import org.sonar.db.dialect.MySql; | |||
import org.sonar.db.dialect.Oracle; | |||
import org.sonar.db.dialect.PostgreSql; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
public class DeletePersonAndFileMeasures extends DataChange { | |||
public DeletePersonAndFileMeasures(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select uuid from snapshots"); | |||
massUpdate.rowPluralName("snapshots"); | |||
massUpdate.update(getDeleteSql()); | |||
massUpdate.execute((row, update) -> { | |||
update.setString(1, row.getString(1)); | |||
return true; | |||
}); | |||
} | |||
private String getDeleteSql() { | |||
switch (getDialect().getId()) { | |||
case MySql.ID: | |||
case MsSql.ID: | |||
return "delete pm from project_measures pm " + | |||
"inner join projects c on c.uuid = pm.component_uuid " + | |||
"where pm.analysis_uuid = ? " + | |||
"and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null)"; | |||
case H2.ID: | |||
return "delete from project_measures " + | |||
"where id in ( " + | |||
" select pm.id from project_measures pm " + | |||
" inner join projects c on c.uuid = pm.component_uuid " + | |||
" where pm.analysis_uuid = ? " + | |||
" and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " + | |||
")"; | |||
case PostgreSql.ID: | |||
return "delete from project_measures pm " + | |||
"using projects c " + | |||
"where pm.analysis_uuid = ? " + | |||
"and c.uuid = pm.component_uuid " + | |||
"and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) "; | |||
case Oracle.ID: | |||
return "delete from project_measures pm where exists (" + | |||
" select 1 from project_measures pm2 " + | |||
" inner join projects c on c.uuid = pm2.component_uuid " + | |||
" where pm2.analysis_uuid = ? " + | |||
" and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " + | |||
" and pm.id = pm2.id" + | |||
")"; | |||
default: | |||
throw new IllegalStateException("Unsupported DB dialect: " + getDialect()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.sql.DropIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
public class DropIndexOnPersonMeasures extends DdlChange { | |||
public DropIndexOnPersonMeasures(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new DropIndexBuilder(getDialect()) | |||
.setTable("project_measures") | |||
.setName("measures_person") | |||
.build()); | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
public class PopulateLiveMeasures extends DataChange { | |||
private final System2 system2; | |||
public PopulateLiveMeasures(Database db, System2 system2) { | |||
super(db); | |||
this.system2 = system2; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
long now = system2.now(); | |||
// reentrancy of migration | |||
context.prepareUpsert("TRUNCATE TABLE live_measures").execute(); | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("SELECT p.uuid, p.project_uuid, pm.metric_id, pm.value, pm.text_value, pm.variation_value_1, pm.measure_data " + | |||
"FROM project_measures pm " + | |||
"INNER JOIN projects p on p.uuid = pm.component_uuid " + | |||
"INNER JOIN snapshots s on s.uuid = pm.analysis_uuid " + | |||
"WHERE s.islast = ?") | |||
.setBoolean(1, true); | |||
massUpdate.update("INSERT INTO live_measures " | |||
+ "(uuid, component_uuid, project_uuid, metric_id, value, text_value, variation, measure_data, created_at, updated_at) " | |||
+ "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); | |||
massUpdate.rowPluralName("live measures"); | |||
massUpdate.execute((row, update) -> { | |||
update.setString(1, Uuids.create()); | |||
update.setString(2, row.getString(1)); | |||
update.setString(3, row.getString(2)); | |||
update.setInt(4, row.getInt(3)); | |||
update.setDouble(5, row.getNullableDouble(4)); | |||
update.setString(6, row.getString(5)); | |||
update.setDouble(7, row.getNullableDouble(6)); | |||
update.setBytes(8, row.getNullableBytes(7)); | |||
update.setLong(9, now); | |||
update.setLong(10, now); | |||
return true; | |||
}); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import java.sql.Types; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class CreateTableLiveMeasuresTest { | |||
private static final String TABLE = "live_measures"; | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(CreateTableLiveMeasuresTest.class, "empty.sql"); | |||
private CreateTableLiveMeasures underTest = new CreateTableLiveMeasures(db.database()); | |||
@Test | |||
public void creates_table_on_empty_db() throws SQLException { | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0); | |||
db.assertColumnDefinition(TABLE, "uuid", Types.VARCHAR, 40, false); | |||
db.assertColumnDefinition(TABLE, "project_uuid", Types.VARCHAR, 50, false); | |||
db.assertColumnDefinition(TABLE, "component_uuid", Types.VARCHAR, 50, false); | |||
db.assertColumnDefinition(TABLE, "metric_id", Types.INTEGER, null, false); | |||
db.assertColumnDefinition(TABLE, "value", Types.DOUBLE, null, true); | |||
db.assertColumnDefinition(TABLE, "text_value", Types.VARCHAR, 4_000, true); | |||
db.assertColumnDefinition(TABLE, "variation", Types.DOUBLE, null, true); | |||
db.assertColumnDefinition(TABLE, "measure_data", Types.BLOB, null, true); | |||
db.assertColumnDefinition(TABLE, "update_marker", Types.VARCHAR, 40, true); | |||
db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false); | |||
db.assertColumnDefinition(TABLE, "updated_at", Types.BIGINT, null, false); | |||
db.assertIndex(TABLE, "live_measures_project", "project_uuid"); | |||
db.assertUniqueIndex(TABLE, "live_measures_component", "component_uuid", "metric_id"); | |||
} | |||
} |
@@ -35,7 +35,7 @@ public class DbVersion70Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 6); | |||
verifyMigrationCount(underTest, 10); | |||
} | |||
} |
@@ -0,0 +1,125 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import org.apache.commons.lang.math.RandomUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class DeletePersonAndFileMeasuresTest { | |||
private static final AtomicInteger GENERATOR = new AtomicInteger(); | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(DeletePersonAndFileMeasuresTest.class, "initial.sql"); | |||
private DataChange underTest = new DeletePersonAndFileMeasures(db.database()); | |||
@Test | |||
public void delete_file_and_person_measures() throws SQLException { | |||
insertComponent("P1", "PRJ", "TRK"); | |||
insertComponent("D1", "DIR", "DIR"); | |||
insertComponent("F1", "FIL", "FIL"); | |||
insertComponent("F2", "FIL", "UTS"); | |||
insertSnapshot("S1", "P1", false); | |||
insertSnapshot("S2", "P1", true); | |||
// past measures | |||
long m1 = insertMeasure("P1", "S1"); | |||
long m2 = insertMeasure("D1", "S1"); | |||
long m3 = insertMeasure("F1", "S1"); | |||
long m4 = insertMeasure("F2", "S1"); | |||
long m5 = insertPersonMeasure("P1", "S1"); | |||
long m6 = insertPersonMeasure("F1", "S1"); | |||
// last measures | |||
long m7 = insertMeasure("P1", "S2"); | |||
long m8 = insertMeasure("D1", "S2"); | |||
long m9 = insertMeasure("F1", "S2"); | |||
long m10 = insertMeasure("F2", "S2"); | |||
long m11 = insertPersonMeasure("P1", "S2"); | |||
long m12 = insertPersonMeasure("F1", "S2"); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4); | |||
assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2); | |||
assertThatMeasuresAreExactly(m1, m2, m7, m8); | |||
// migration is re-entrant | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4); | |||
assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2); | |||
assertThatMeasuresAreExactly(m1, m2, m7, m8); | |||
} | |||
private void assertThatMeasuresAreExactly(long... expectedMeasureIds) { | |||
long[] ids = db.select("select id as \"id\" from project_measures") | |||
.stream() | |||
.mapToLong(m -> (Long) m.get("id")) | |||
.toArray(); | |||
assertThat(ids).containsOnly(expectedMeasureIds); | |||
} | |||
private void insertComponent(String uuid, String scope, String qualifier) { | |||
db.executeInsert("PROJECTS", | |||
"ORGANIZATION_UUID", "O1", | |||
"KEE", "" + GENERATOR.incrementAndGet(), | |||
"UUID", uuid, | |||
"PROJECT_UUID", "" + GENERATOR.incrementAndGet(), | |||
"MAIN_BRANCH_PROJECT_UUID", "" + GENERATOR.incrementAndGet(), | |||
"UUID_PATH", ".", | |||
"ROOT_UUID", "" + GENERATOR.incrementAndGet(), | |||
"PRIVATE", "true", | |||
"QUALIFIER", qualifier, | |||
"SCOPE", scope); | |||
} | |||
private void insertSnapshot(String uuid, String projectUuid, boolean last) { | |||
db.executeInsert("SNAPSHOTS", | |||
"UUID", uuid, | |||
"COMPONENT_UUID", projectUuid, | |||
"STATUS", "P", | |||
"ISLAST", last); | |||
} | |||
private long insertMeasure(String componentUuid, String analysisUuid) { | |||
long id = GENERATOR.incrementAndGet(); | |||
db.executeInsert("PROJECT_MEASURES", | |||
"ID", id, | |||
"METRIC_ID", "42", | |||
"COMPONENT_UUID", componentUuid, | |||
"ANALYSIS_UUID", analysisUuid); | |||
return id; | |||
} | |||
private long insertPersonMeasure(String componentUuid, String analysisUuid) { | |||
long id = GENERATOR.incrementAndGet(); | |||
db.executeInsert("PROJECT_MEASURES", | |||
"ID", id, | |||
"METRIC_ID", "42", | |||
"COMPONENT_UUID", componentUuid, | |||
"ANALYSIS_UUID", analysisUuid, | |||
"PERSON_ID", RandomUtils.nextInt(100)); | |||
return id; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
public class DropIndexOnPersonMeasuresTest { | |||
private static final String TABLE = "project_measures"; | |||
private static final String INDEX = "measures_person"; | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(DropIndexOnPersonMeasuresTest.class, "initial.sql"); | |||
private DdlChange underTest = new DropIndexOnPersonMeasures(db.database()); | |||
@Test | |||
public void drop_index() throws SQLException { | |||
db.assertIndex(TABLE, INDEX, "person_id"); | |||
underTest.execute(); | |||
db.assertIndexDoesNotExist(TABLE, INDEX); | |||
} | |||
} | |||
@@ -0,0 +1,140 @@ | |||
/* | |||
* 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.platform.db.migration.version.v70; | |||
import java.sql.SQLException; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.function.Function; | |||
import org.assertj.core.groups.Tuple; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.TestSystem2; | |||
import org.sonar.db.CoreDbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class PopulateLiveMeasuresTest { | |||
private System2 system2 = new TestSystem2().setNow(1_500_000_000_000L); | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(PopulateLiveMeasuresTest.class, "initial.sql"); | |||
private PopulateLiveMeasures underTest = new PopulateLiveMeasures(db.database(), system2); | |||
@Test | |||
public void do_nothing_when_no_data() throws SQLException { | |||
assertThat(db.countRowsOfTable("PROJECT_MEASURES")).isEqualTo(0); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("LIVE_MEASURES")).isEqualTo(0); | |||
} | |||
@Test | |||
public void execute_must_update_database() throws SQLException { | |||
generateProjectMeasures(); | |||
underTest.execute(); | |||
assertThat(getLiveMeasures()).extracting( | |||
field("COMPONENT_UUID"), | |||
field("PROJECT_UUID"), | |||
field("METRIC_ID"), | |||
field("VALUE"), | |||
field("TEXT_VALUE"), | |||
field("VARIATION"), | |||
field("MEASURE_DATA") | |||
).containsExactlyInAnyOrder(generateLiveMeasures()); | |||
} | |||
private Function<Map<String, Object>, Object> field(String name) { | |||
return m -> m.get(name); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
generateProjectMeasures(); | |||
underTest.execute(); | |||
underTest.execute(); | |||
assertThat(getLiveMeasures()).extracting( | |||
field("COMPONENT_UUID"), | |||
field("PROJECT_UUID"), | |||
field("METRIC_ID"), | |||
field("VALUE"), | |||
field("TEXT_VALUE"), | |||
field("VARIATION"), | |||
field("MEASURE_DATA") | |||
).containsExactlyInAnyOrder(generateLiveMeasures()); | |||
} | |||
private void generateProjectMeasures() { | |||
Map<String, Object> project = new HashMap<>(); | |||
project.put("UUID", "PRJ1"); | |||
project.put("ORGANIZATION_UUID", "ORG1"); | |||
project.put("UUID_PATH", "X"); | |||
project.put("ROOT_UUID", "X"); | |||
project.put("PROJECT_UUID", "PRJ1"); | |||
project.put("PRIVATE", "FALSE"); | |||
db.executeInsert("PROJECTS", project); | |||
Map<String, Object> analysis1 = new HashMap<>(); | |||
analysis1.put("UUID", "A1"); | |||
analysis1.put("ISLAST", "FALSE"); | |||
analysis1.put("COMPONENT_UUID", "PRJ1"); | |||
db.executeInsert("SNAPSHOTS", analysis1); | |||
Map<String, Object> analysis2 = new HashMap<>(); | |||
analysis2.put("UUID", "A2"); | |||
analysis2.put("ISLAST", "TRUE"); | |||
analysis2.put("COMPONENT_UUID", "PRJ1"); | |||
db.executeInsert("SNAPSHOTS", analysis2); | |||
Map<String, Object> measure1 = new HashMap<>(); | |||
measure1.put("COMPONENT_UUID", "PRJ1"); | |||
measure1.put("ANALYSIS_UUID", "A1"); | |||
measure1.put("METRIC_ID", "123"); | |||
db.executeInsert("PROJECT_MEASURES", measure1); | |||
Map<String, Object> measure2 = new HashMap<>(); | |||
measure2.put("COMPONENT_UUID", "PRJ1"); | |||
measure2.put("ANALYSIS_UUID", "A2"); | |||
measure2.put("METRIC_ID", "123"); | |||
measure2.put("VALUE", "234"); | |||
measure2.put("TEXT_VALUE", "TEXT_VALUEx"); | |||
measure2.put("VARIATION_VALUE_1", "345"); | |||
measure2.put("MEASURE_DATA", "FFFF"); | |||
db.executeInsert("PROJECT_MEASURES", measure2); | |||
} | |||
private List<Map<String, Object>> getLiveMeasures() { | |||
return db.select("SELECT * FROM LIVE_MEASURES"); | |||
} | |||
private Tuple[] generateLiveMeasures() { | |||
return new Tuple[] { | |||
tuple("PRJ1", "PRJ1", 123L, 234.0, "TEXT_VALUEx", 345.0, new byte[] {-1, -1}) | |||
}; | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
CREATE TABLE "PROJECTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(400), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"UUID_PATH" VARCHAR(1500) NOT NULL, | |||
"ROOT_UUID" VARCHAR(50) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"MODULE_UUID" VARCHAR(50), | |||
"MODULE_UUID_PATH" VARCHAR(1500), | |||
"MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), | |||
"NAME" VARCHAR(2000), | |||
"DESCRIPTION" VARCHAR(2000), | |||
"PRIVATE" BOOLEAN NOT NULL, | |||
"TAGS" VARCHAR(500), | |||
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, | |||
"SCOPE" VARCHAR(3), | |||
"QUALIFIER" VARCHAR(10), | |||
"DEPRECATED_KEE" VARCHAR(400), | |||
"PATH" VARCHAR(2000), | |||
"LANGUAGE" VARCHAR(20), | |||
"COPY_COMPONENT_UUID" VARCHAR(50), | |||
"LONG_NAME" VARCHAR(2000), | |||
"DEVELOPER_UUID" VARCHAR(50), | |||
"CREATED_AT" TIMESTAMP, | |||
"AUTHORIZATION_UPDATED_AT" BIGINT, | |||
"B_CHANGED" BOOLEAN, | |||
"B_COPY_COMPONENT_UUID" VARCHAR(50), | |||
"B_DESCRIPTION" VARCHAR(2000), | |||
"B_ENABLED" BOOLEAN, | |||
"B_UUID_PATH" VARCHAR(1500), | |||
"B_LANGUAGE" VARCHAR(20), | |||
"B_LONG_NAME" VARCHAR(500), | |||
"B_MODULE_UUID" VARCHAR(50), | |||
"B_MODULE_UUID_PATH" VARCHAR(1500), | |||
"B_NAME" VARCHAR(500), | |||
"B_PATH" VARCHAR(2000), | |||
"B_QUALIFIER" VARCHAR(10) | |||
); | |||
CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); | |||
CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); | |||
CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); | |||
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); | |||
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); | |||
CREATE TABLE "SNAPSHOTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"CREATED_AT" BIGINT, | |||
"BUILD_DATE" BIGINT, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"STATUS" VARCHAR(4) NOT NULL DEFAULT 'U', | |||
"PURGE_STATUS" INTEGER, | |||
"ISLAST" BOOLEAN NOT NULL DEFAULT FALSE, | |||
"VERSION" VARCHAR(500), | |||
"PERIOD1_MODE" VARCHAR(100), | |||
"PERIOD1_PARAM" VARCHAR(100), | |||
"PERIOD1_DATE" BIGINT, | |||
"PERIOD2_MODE" VARCHAR(100), | |||
"PERIOD2_PARAM" VARCHAR(100), | |||
"PERIOD2_DATE" BIGINT, | |||
"PERIOD3_MODE" VARCHAR(100), | |||
"PERIOD3_PARAM" VARCHAR(100), | |||
"PERIOD3_DATE" BIGINT, | |||
"PERIOD4_MODE" VARCHAR(100), | |||
"PERIOD4_PARAM" VARCHAR(100), | |||
"PERIOD4_DATE" BIGINT, | |||
"PERIOD5_MODE" VARCHAR(100), | |||
"PERIOD5_PARAM" VARCHAR(100), | |||
"PERIOD5_DATE" BIGINT | |||
); | |||
CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID"); | |||
CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID"); | |||
CREATE TABLE "PROJECT_MEASURES" ( | |||
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"VALUE" DOUBLE, | |||
"METRIC_ID" INTEGER NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"ALERT_STATUS" VARCHAR(5), | |||
"ALERT_TEXT" VARCHAR(4000), | |||
"DESCRIPTION" VARCHAR(4000), | |||
"PERSON_ID" INTEGER, | |||
"VARIATION_VALUE_1" DOUBLE, | |||
"VARIATION_VALUE_2" DOUBLE, | |||
"VARIATION_VALUE_3" DOUBLE, | |||
"VARIATION_VALUE_4" DOUBLE, | |||
"VARIATION_VALUE_5" DOUBLE, | |||
"MEASURE_DATA" BINARY | |||
); | |||
CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID"); | |||
CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID"); |
@@ -0,0 +1,21 @@ | |||
CREATE TABLE "PROJECT_MEASURES" ( | |||
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"VALUE" DOUBLE, | |||
"METRIC_ID" INTEGER NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"ALERT_STATUS" VARCHAR(5), | |||
"ALERT_TEXT" VARCHAR(4000), | |||
"DESCRIPTION" VARCHAR(4000), | |||
"PERSON_ID" INTEGER, | |||
"VARIATION_VALUE_1" DOUBLE, | |||
"VARIATION_VALUE_2" DOUBLE, | |||
"VARIATION_VALUE_3" DOUBLE, | |||
"VARIATION_VALUE_4" DOUBLE, | |||
"VARIATION_VALUE_5" DOUBLE, | |||
"MEASURE_DATA" BINARY | |||
); | |||
CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID"); | |||
CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID"); | |||
CREATE INDEX "MEASURES_PERSON" ON "PROJECT_MEASURES" ("PERSON_ID"); |
@@ -0,0 +1,116 @@ | |||
CREATE TABLE "PROJECTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(400), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"UUID_PATH" VARCHAR(1500) NOT NULL, | |||
"ROOT_UUID" VARCHAR(50) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"MODULE_UUID" VARCHAR(50), | |||
"MODULE_UUID_PATH" VARCHAR(1500), | |||
"MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), | |||
"NAME" VARCHAR(2000), | |||
"DESCRIPTION" VARCHAR(2000), | |||
"PRIVATE" BOOLEAN NOT NULL, | |||
"TAGS" VARCHAR(500), | |||
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, | |||
"SCOPE" VARCHAR(3), | |||
"QUALIFIER" VARCHAR(10), | |||
"DEPRECATED_KEE" VARCHAR(400), | |||
"PATH" VARCHAR(2000), | |||
"LANGUAGE" VARCHAR(20), | |||
"COPY_COMPONENT_UUID" VARCHAR(50), | |||
"LONG_NAME" VARCHAR(2000), | |||
"DEVELOPER_UUID" VARCHAR(50), | |||
"CREATED_AT" TIMESTAMP, | |||
"AUTHORIZATION_UPDATED_AT" BIGINT, | |||
"B_CHANGED" BOOLEAN, | |||
"B_COPY_COMPONENT_UUID" VARCHAR(50), | |||
"B_DESCRIPTION" VARCHAR(2000), | |||
"B_ENABLED" BOOLEAN, | |||
"B_UUID_PATH" VARCHAR(1500), | |||
"B_LANGUAGE" VARCHAR(20), | |||
"B_LONG_NAME" VARCHAR(500), | |||
"B_MODULE_UUID" VARCHAR(50), | |||
"B_MODULE_UUID_PATH" VARCHAR(1500), | |||
"B_NAME" VARCHAR(500), | |||
"B_PATH" VARCHAR(2000), | |||
"B_QUALIFIER" VARCHAR(10) | |||
); | |||
CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); | |||
CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); | |||
CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); | |||
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); | |||
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); | |||
CREATE TABLE "SNAPSHOTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"CREATED_AT" BIGINT, | |||
"BUILD_DATE" BIGINT, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"STATUS" VARCHAR(4) NOT NULL DEFAULT 'U', | |||
"PURGE_STATUS" INTEGER, | |||
"ISLAST" BOOLEAN NOT NULL DEFAULT FALSE, | |||
"VERSION" VARCHAR(500), | |||
"PERIOD1_MODE" VARCHAR(100), | |||
"PERIOD1_PARAM" VARCHAR(100), | |||
"PERIOD1_DATE" BIGINT, | |||
"PERIOD2_MODE" VARCHAR(100), | |||
"PERIOD2_PARAM" VARCHAR(100), | |||
"PERIOD2_DATE" BIGINT, | |||
"PERIOD3_MODE" VARCHAR(100), | |||
"PERIOD3_PARAM" VARCHAR(100), | |||
"PERIOD3_DATE" BIGINT, | |||
"PERIOD4_MODE" VARCHAR(100), | |||
"PERIOD4_PARAM" VARCHAR(100), | |||
"PERIOD4_DATE" BIGINT, | |||
"PERIOD5_MODE" VARCHAR(100), | |||
"PERIOD5_PARAM" VARCHAR(100), | |||
"PERIOD5_DATE" BIGINT | |||
); | |||
CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID"); | |||
CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID"); | |||
CREATE TABLE "LIVE_MEASURES" ( | |||
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"METRIC_ID" INTEGER NOT NULL, | |||
"VALUE" DOUBLE, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"VARIATION" DOUBLE, | |||
"MEASURE_DATA" BINARY, | |||
"UPDATE_MARKER" VARCHAR(40), | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL | |||
); | |||
CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES" ("PROJECT_UUID"); | |||
CREATE UNIQUE INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES" ("COMPONENT_UUID", "METRIC_ID"); | |||
CREATE TABLE "PROJECT_MEASURES" ( | |||
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"VALUE" DOUBLE, | |||
"METRIC_ID" INTEGER NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(50) NOT NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"ALERT_STATUS" VARCHAR(5), | |||
"ALERT_TEXT" VARCHAR(4000), | |||
"DESCRIPTION" VARCHAR(4000), | |||
"PERSON_ID" INTEGER, | |||
"VARIATION_VALUE_1" DOUBLE, | |||
"VARIATION_VALUE_2" DOUBLE, | |||
"VARIATION_VALUE_3" DOUBLE, | |||
"VARIATION_VALUE_4" DOUBLE, | |||
"VARIATION_VALUE_5" DOUBLE, | |||
"MEASURE_DATA" BINARY | |||
); | |||
CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID"); | |||
CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID"); | |||
CREATE INDEX "MEASURES_PERSON" ON "PROJECT_MEASURES" ("PERSON_ID"); | |||
@@ -31,14 +31,14 @@ import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.util.Protobuf; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.issue.index.BranchStatistics; | |||
import org.sonar.server.issue.index.IssueIndex; | |||
@@ -97,13 +97,12 @@ public class ListAction implements BranchWsAction { | |||
checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); | |||
Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project); | |||
MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY); | |||
Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() | |||
.selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) | |||
.stream().collect(uniqueIndex(BranchDto::getUuid)); | |||
Map<String, MeasureDto> qualityGateMeasuresByComponentUuids = dbClient.measureDao() | |||
.selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId())) | |||
.stream().collect(uniqueIndex(MeasureDto::getComponentUuid)); | |||
Map<String, LiveMeasureDto> qualityGateMeasuresByComponentUuids = dbClient.liveMeasureDao() | |||
.selectByComponentUuidsAndMetricKeys(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(ALERT_STATUS_KEY)) | |||
.stream().collect(uniqueIndex(LiveMeasureDto::getComponentUuid)); | |||
Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), branches.stream() | |||
.filter(b -> b.getBranchType().equals(SHORT)) | |||
.map(BranchDto::getUuid).collect(toList())) | |||
@@ -113,15 +112,14 @@ public class ListAction implements BranchWsAction { | |||
.stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); | |||
ProjectBranches.ListWsResponse.Builder protobufResponse = ProjectBranches.ListWsResponse.newBuilder(); | |||
branches.stream() | |||
.forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), | |||
branches.forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), | |||
analysisDateByBranchUuid.get(b.getUuid()))); | |||
WsUtils.writeProtobuf(protobufResponse.build(), request, response); | |||
} | |||
} | |||
private static void addBranch(ProjectBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, | |||
@Nullable MeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) { | |||
@Nullable LiveMeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) { | |||
ProjectBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); | |||
setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics); | |||
if (analysisDate != null) { | |||
@@ -147,11 +145,11 @@ public class ListAction implements BranchWsAction { | |||
return builder; | |||
} | |||
private static void setBranchStatus(ProjectBranches.Branch.Builder builder, BranchDto branch, @Nullable MeasureDto qualityGateMeasure, | |||
private static void setBranchStatus(ProjectBranches.Branch.Builder builder, BranchDto branch, @Nullable LiveMeasureDto qualityGateMeasure, | |||
@Nullable BranchStatistics branchStatistics) { | |||
ProjectBranches.Branch.Status.Builder statusBuilder = ProjectBranches.Branch.Status.newBuilder(); | |||
if (branch.getBranchType() == LONG && qualityGateMeasure != null) { | |||
statusBuilder.setQualityGateStatus(qualityGateMeasure.getData()); | |||
Protobuf.setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); | |||
} | |||
if (branch.getBranchType() == BranchType.SHORT) { | |||
statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); |
@@ -19,12 +19,10 @@ | |||
*/ | |||
package org.sonar.server.component.ws; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.Maps; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.BooleanUtils; | |||
@@ -37,8 +35,7 @@ import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.db.property.PropertyQuery; | |||
@@ -46,6 +43,8 @@ import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.user.UserSession; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.unmodifiableList; | |||
import static org.sonar.api.measures.CoreMetrics.COVERAGE; | |||
import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY; | |||
@@ -66,12 +65,12 @@ public class AppAction implements ComponentsWsAction { | |||
private static final String PARAM_COMPONENT_ID = "componentId"; | |||
private static final String PARAM_COMPONENT = "component"; | |||
private static final List<String> METRIC_KEYS = ImmutableList.of( | |||
private static final List<String> METRIC_KEYS = unmodifiableList(asList( | |||
LINES_KEY, | |||
VIOLATIONS_KEY, | |||
COVERAGE_KEY, | |||
DUPLICATED_LINES_DENSITY_KEY, | |||
TESTS_KEY); | |||
TESTS_KEY)); | |||
private final DbClient dbClient; | |||
@@ -121,7 +120,7 @@ public class AppAction implements ComponentsWsAction { | |||
JsonWriter json = response.newJsonWriter(); | |||
json.beginObject(); | |||
Map<String, MeasureDto> measuresByMetricKey = measuresByMetricKey(component, session); | |||
Map<String, LiveMeasureDto> measuresByMetricKey = loadMeasuresGroupedByMetricKey(component, session); | |||
appendComponent(json, component, userSession, session); | |||
appendPermissions(json, userSession); | |||
appendMeasures(json, measuresByMetricKey); | |||
@@ -177,7 +176,7 @@ public class AppAction implements ComponentsWsAction { | |||
json.prop("canMarkAsFavorite", userSession.isLoggedIn()); | |||
} | |||
private static void appendMeasures(JsonWriter json, Map<String, MeasureDto> measuresByMetricKey) { | |||
private static void appendMeasures(JsonWriter json, Map<String, LiveMeasureDto> measuresByMetricKey) { | |||
json.name("measures").beginObject(); | |||
json.prop("lines", formatMeasure(measuresByMetricKey, LINES)); | |||
json.prop("coverage", formatMeasure(measuresByMetricKey, COVERAGE)); | |||
@@ -187,12 +186,11 @@ public class AppAction implements ComponentsWsAction { | |||
json.endObject(); | |||
} | |||
private Map<String, MeasureDto> measuresByMetricKey(ComponentDto component, DbSession session) { | |||
MeasureQuery query = MeasureQuery.builder().setComponentUuid(component.uuid()).setMetricKeys(METRIC_KEYS).build(); | |||
List<MeasureDto> measures = dbClient.measureDao().selectByQuery(session, query); | |||
Set<Integer> metricIds = measures.stream().map(MeasureDto::getMetricId).collect(Collectors.toSet()); | |||
List<MetricDto> metrics = dbClient.metricDao().selectByIds(session, metricIds); | |||
private Map<String, LiveMeasureDto> loadMeasuresGroupedByMetricKey(ComponentDto component, DbSession dbSession) { | |||
List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, METRIC_KEYS); | |||
Map<Integer, MetricDto> metricsById = Maps.uniqueIndex(metrics, MetricDto::getId); | |||
List<LiveMeasureDto> measures = dbClient.liveMeasureDao() | |||
.selectByComponentUuids(dbSession, Collections.singletonList(component.uuid()), metricsById.keySet()); | |||
return Maps.uniqueIndex(measures, m -> metricsById.get(m.getMetricId()).getKey()); | |||
} | |||
@@ -205,12 +203,12 @@ public class AppAction implements ComponentsWsAction { | |||
} | |||
@CheckForNull | |||
private static String formatMeasure(Map<String, MeasureDto> measuresByMetricKey, Metric metric) { | |||
MeasureDto measure = measuresByMetricKey.get(metric.getKey()); | |||
private static String formatMeasure(Map<String, LiveMeasureDto> measuresByMetricKey, Metric metric) { | |||
LiveMeasureDto measure = measuresByMetricKey.get(metric.getKey()); | |||
return formatMeasure(measure, metric); | |||
} | |||
private static String formatMeasure(@Nullable MeasureDto measure, Metric metric) { | |||
private static String formatMeasure(@Nullable LiveMeasureDto measure, Metric metric) { | |||
if (measure == null) { | |||
return null; | |||
} | |||
@@ -222,7 +220,7 @@ public class AppAction implements ComponentsWsAction { | |||
} | |||
@CheckForNull | |||
private static Double getDoubleValue(MeasureDto measure, Metric metric) { | |||
private static Double getDoubleValue(LiveMeasureDto measure, Metric metric) { | |||
Double value = measure.getValue(); | |||
if (BooleanUtils.isTrue(metric.isOptimizedBestValue()) && value == null) { | |||
value = metric.getBestValue(); |
@@ -54,11 +54,11 @@ public class ProjectCleaner { | |||
this.purgeListener = purgeListener; | |||
} | |||
public ProjectCleaner purge(DbSession session, IdUuidPair idUuidPair, Configuration projectConfig, Collection<String> disabledComponentUuids) { | |||
public ProjectCleaner purge(DbSession session, IdUuidPair rootId, Configuration projectConfig, Collection<String> disabledComponentUuids) { | |||
long start = System.currentTimeMillis(); | |||
profiler.reset(); | |||
PurgeConfiguration configuration = newDefaultPurgeConfiguration(projectConfig, idUuidPair, disabledComponentUuids); | |||
PurgeConfiguration configuration = newDefaultPurgeConfiguration(projectConfig, rootId, disabledComponentUuids); | |||
periodCleaner.clean(session, configuration.rootProjectIdUuid().getUuid(), projectConfig); | |||
purgeDao.purge(session, configuration, purgeListener, profiler); |
@@ -19,8 +19,7 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.base.Predicates; | |||
import java.util.function.Predicate; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
@@ -40,7 +39,7 @@ public class BestValueOptimization implements Predicate<Measure> { | |||
if (isBestValueOptimized(metric) && isBestValueOptimized(component)) { | |||
return new BestValueOptimization(metric); | |||
} | |||
return Predicates.alwaysFalse(); | |||
return x -> false; | |||
} | |||
private static boolean isBestValueOptimized(Metric metric) { | |||
@@ -52,7 +51,7 @@ public class BestValueOptimization implements Predicate<Measure> { | |||
} | |||
@Override | |||
public boolean apply(@Nonnull Measure measure) { | |||
public boolean test(@Nonnull Measure measure) { | |||
return isBestValueOptimized(measure); | |||
} | |||
@@ -24,7 +24,6 @@ import com.google.common.base.Optional; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.collect.ImmutableSetMultimap; | |||
import com.google.common.collect.SetMultimap; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
@@ -60,11 +59,6 @@ public final class MapBasedRawMeasureRepository<T> implements MeasureRepository | |||
throw new UnsupportedOperationException("This implementation of MeasureRepository supports only raw measures"); | |||
} | |||
@Override | |||
public int loadAsRawMeasures(Collection<Component> components, Collection<Metric> metrics) { | |||
throw new UnsupportedOperationException("This implementation of MeasureRepository supports only raw measures"); | |||
} | |||
@Override | |||
public Optional<Measure> getRawMeasure(final Component component, final Metric metric) { | |||
// fail fast |
@@ -19,16 +19,13 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import java.util.Collection; | |||
import com.google.common.base.Optional; | |||
import com.google.common.collect.SetMultimap; | |||
import java.util.Set; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricImpl; | |||
import com.google.common.base.Optional; | |||
import com.google.common.collect.SetMultimap; | |||
public interface MeasureRepository { | |||
/** | |||
@@ -43,8 +40,6 @@ public interface MeasureRepository { | |||
*/ | |||
Optional<Measure> getBaseMeasure(Component component, Metric metric); | |||
int loadAsRawMeasures(Collection<Component> components, Collection<Metric> metrics); | |||
/** | |||
* Retrieves the measure created during the current analysis for the specified {@link Component} for the specified | |||
* {@link Metric} if it exists (ie. one created by the Compute Engine or the Batch) and which is <strong>not</strong> |
@@ -19,21 +19,14 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentFunctions.toReportRef; | |||
import java.util.Collection; | |||
import com.google.common.base.Optional; | |||
import com.google.common.collect.SetMultimap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import org.sonar.core.util.CloseableIterator; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
@@ -42,8 +35,8 @@ import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository; | |||
import org.sonar.server.computation.task.projectanalysis.metric.ReportMetricValidator; | |||
import com.google.common.base.Optional; | |||
import com.google.common.collect.SetMultimap; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentFunctions.toReportRef; | |||
public class MeasureRepositoryImpl implements MeasureRepository { | |||
private final MapBasedRawMeasureRepository<Integer> delegate = new MapBasedRawMeasureRepository<>(toReportRef()); | |||
@@ -72,8 +65,7 @@ public class MeasureRepositoryImpl implements MeasureRepository { | |||
requireNonNull(metric); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
MeasureQuery query = MeasureQuery.builder().setComponentUuid(component.getUuid()).setMetricKey(metric.getKey()).build(); | |||
java.util.Optional<MeasureDto> measureDto = dbClient.measureDao().selectSingle(dbSession, query); | |||
java.util.Optional<MeasureDto> measureDto = dbClient.measureDao().selectLastMeasure(dbSession, component.getUuid(), metric.getKey()); | |||
if (measureDto.isPresent()) { | |||
return measureTransformer.toMeasure(measureDto.get(), metric); | |||
} | |||
@@ -81,32 +73,6 @@ public class MeasureRepositoryImpl implements MeasureRepository { | |||
} | |||
} | |||
@Override | |||
public int loadAsRawMeasures(Collection<Component> components, Collection<Metric> metrics) { | |||
requireNonNull(components); | |||
requireNonNull(metrics); | |||
Map<String, Component> componentsByUuid = components.stream() | |||
.collect(Collectors.toMap(Component::getUuid, c -> c)); | |||
Map<Integer, Metric> metricsById = metrics.stream() | |||
.collect(Collectors.toMap(Metric::getId, m -> m)); | |||
List<MeasureDto> measuresDto; | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
measuresDto = dbClient.measureDao().selectByComponentsAndMetrics(dbSession, componentsByUuid.keySet(), metricsById.keySet()); | |||
} | |||
for (MeasureDto dto : measuresDto) { | |||
Metric metric = metricsById.get(dto.getMetricId()); | |||
Component component = componentsByUuid.get(dto.getComponentUuid()); | |||
Measure measure = measureTransformer.toMeasure(dto, metric).get(); | |||
delegate.add(component, metric, measure); | |||
} | |||
return measuresDto.size(); | |||
} | |||
@Override | |||
public Optional<Measure> getRawMeasure(Component component, Metric metric) { | |||
Optional<Measure> local = delegate.getRawMeasure(component, metric); |
@@ -20,25 +20,23 @@ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.Developer; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
public class MeasureToMeasureDto { | |||
private final DbIdsRepository dbIdsRepository; | |||
private final AnalysisMetadataHolder analysisMetadataHolder; | |||
private final TreeRootHolder treeRootHolder; | |||
public MeasureToMeasureDto(DbIdsRepository dbIdsRepository, AnalysisMetadataHolder analysisMetadataHolder) { | |||
this.dbIdsRepository = dbIdsRepository; | |||
public MeasureToMeasureDto(AnalysisMetadataHolder analysisMetadataHolder, TreeRootHolder treeRootHolder) { | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
this.treeRootHolder = treeRootHolder; | |||
} | |||
@Nonnull | |||
public MeasureDto toMeasureDto(Measure measure, Metric metric, Component component) { | |||
MeasureDto out = new MeasureDto(); | |||
out.setMetricId(metric.getId()); | |||
@@ -50,9 +48,18 @@ public class MeasureToMeasureDto { | |||
if (measure.hasQualityGateStatus()) { | |||
setAlert(out, measure.getQualityGateStatus()); | |||
} | |||
Developer developer = measure.getDeveloper(); | |||
if (developer != null) { | |||
out.setDeveloperId(dbIdsRepository.getDeveloperId(developer)); | |||
out.setValue(valueAsDouble(measure)); | |||
out.setData(data(measure)); | |||
return out; | |||
} | |||
public LiveMeasureDto toLiveMeasureDto(Measure measure, Metric metric, Component component) { | |||
LiveMeasureDto out = new LiveMeasureDto(); | |||
out.setMetricId(metric.getId()); | |||
out.setComponentUuid(component.getUuid()); | |||
out.setProjectUuid(treeRootHolder.getRoot().getUuid()); | |||
if (measure.hasVariation()) { | |||
out.setVariation(measure.getVariation()); | |||
} | |||
out.setValue(valueAsDouble(measure)); | |||
out.setData(data(measure)); |
@@ -0,0 +1,133 @@ | |||
/* | |||
* 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.computation.task.projectanalysis.step; | |||
import com.google.common.collect.Multimap; | |||
import java.util.Collection; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.function.Predicate; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.measure.LiveMeasureDao; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter; | |||
import org.sonar.server.computation.task.projectanalysis.measure.BestValueOptimization; | |||
import org.sonar.server.computation.task.projectanalysis.measure.Measure; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureToMeasureDto; | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.unmodifiableSet; | |||
import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PersistLiveMeasuresStep implements ComputationStep { | |||
/** | |||
* List of metrics that should not be persisted on file measure. | |||
*/ | |||
private static final Set<String> NOT_TO_PERSIST_ON_FILE_METRIC_KEYS = unmodifiableSet(new HashSet<>(asList( | |||
FILE_COMPLEXITY_DISTRIBUTION_KEY, | |||
FUNCTION_COMPLEXITY_DISTRIBUTION_KEY, | |||
CLASS_COMPLEXITY_DISTRIBUTION_KEY))); | |||
private final DbClient dbClient; | |||
private final MetricRepository metricRepository; | |||
private final MeasureToMeasureDto measureToMeasureDto; | |||
private final TreeRootHolder treeRootHolder; | |||
private final MeasureRepository measureRepository; | |||
public PersistLiveMeasuresStep(DbClient dbClient, MetricRepository metricRepository, MeasureToMeasureDto measureToMeasureDto, | |||
TreeRootHolder treeRootHolder, MeasureRepository measureRepository) { | |||
this.dbClient = dbClient; | |||
this.metricRepository = metricRepository; | |||
this.measureToMeasureDto = measureToMeasureDto; | |||
this.treeRootHolder = treeRootHolder; | |||
this.measureRepository = measureRepository; | |||
} | |||
@Override | |||
public String getDescription() { | |||
return "Persist live measures"; | |||
} | |||
@Override | |||
public void execute() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String marker = Uuids.create(); | |||
Component root = treeRootHolder.getRoot(); | |||
new DepthTraversalTypeAwareCrawler(new MeasureVisitor(dbSession, marker)).visit(root); | |||
dbClient.liveMeasureDao().deleteByProjectUuidExcludingMarker(dbSession, root.getUuid(), marker); | |||
dbSession.commit(); | |||
} | |||
} | |||
private class MeasureVisitor extends TypeAwareVisitorAdapter { | |||
private final DbSession dbSession; | |||
private final String marker; | |||
private MeasureVisitor(DbSession dbSession, String marker) { | |||
super(CrawlerDepthLimit.LEAVES, PRE_ORDER); | |||
this.dbSession = dbSession; | |||
this.marker = marker; | |||
} | |||
@Override | |||
public void visitAny(Component component) { | |||
LiveMeasureDao dao = dbClient.liveMeasureDao(); | |||
Multimap<String, Measure> measures = measureRepository.getRawMeasures(component); | |||
for (Map.Entry<String, Collection<Measure>> measuresByMetricKey : measures.asMap().entrySet()) { | |||
String metricKey = measuresByMetricKey.getKey(); | |||
if (NOT_TO_PERSIST_ON_FILE_METRIC_KEYS.contains(metricKey) && component.getType() == Component.Type.FILE) { | |||
continue; | |||
} | |||
Metric metric = metricRepository.getByKey(metricKey); | |||
Predicate<Measure> notBestValueOptimized = BestValueOptimization.from(metric, component).negate(); | |||
measuresByMetricKey.getValue().stream() | |||
.filter(NonEmptyMeasure.INSTANCE) | |||
.filter(notBestValueOptimized) | |||
.map(measure -> measureToMeasureDto.toLiveMeasureDto(measure, metric, component)) | |||
.forEach(dto -> dao.insertOrUpdate(dbSession, dto, marker)); | |||
} | |||
} | |||
} | |||
private enum NonEmptyMeasure implements Predicate<Measure> { | |||
INSTANCE; | |||
@Override | |||
public boolean test(@Nonnull Measure input) { | |||
return input.getValueType() != Measure.ValueType.NO_VALUE || input.hasVariation() || input.getData() != null; | |||
} | |||
} | |||
} |
@@ -19,24 +19,23 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.step; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.base.Predicates; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Multimap; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.function.Predicate; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.core.config.PurgeConstants; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.measure.MeasureDao; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter; | |||
import org.sonar.server.computation.task.projectanalysis.measure.BestValueOptimization; | |||
import org.sonar.server.computation.task.projectanalysis.measure.Measure; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureToMeasureDto; | |||
@@ -44,35 +43,32 @@ import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PersistMeasuresStep implements ComputationStep { | |||
/** | |||
* List of metrics that should not be persisted on file measure (Waiting for SONAR-6688 to be implemented) | |||
*/ | |||
private static final List<String> NOT_TO_PERSIST_ON_FILE_METRIC_KEYS = ImmutableList.of( | |||
FILE_COMPLEXITY_DISTRIBUTION_KEY, | |||
FUNCTION_COMPLEXITY_DISTRIBUTION_KEY, | |||
CLASS_COMPLEXITY_DISTRIBUTION_KEY); | |||
private final DbClient dbClient; | |||
private final MetricRepository metricRepository; | |||
private final MeasureToMeasureDto measureToMeasureDto; | |||
private final TreeRootHolder treeRootHolder; | |||
private final MeasureRepository measureRepository; | |||
private final boolean persistDirectories; | |||
public PersistMeasuresStep(DbClient dbClient, MetricRepository metricRepository, MeasureToMeasureDto measureToMeasureDto, | |||
TreeRootHolder treeRootHolder, MeasureRepository measureRepository) { | |||
TreeRootHolder treeRootHolder, MeasureRepository measureRepository, ConfigurationRepository settings) { | |||
this(dbClient, metricRepository, measureToMeasureDto, treeRootHolder,measureRepository, | |||
!settings.getConfiguration().getBoolean(PurgeConstants.PROPERTY_CLEAN_DIRECTORY).orElseThrow(() -> new IllegalStateException("Missing default value"))); | |||
} | |||
@VisibleForTesting | |||
PersistMeasuresStep(DbClient dbClient, MetricRepository metricRepository, MeasureToMeasureDto measureToMeasureDto, TreeRootHolder treeRootHolder, | |||
MeasureRepository measureRepository, boolean persistDirectories) { | |||
this.dbClient = dbClient; | |||
this.metricRepository = metricRepository; | |||
this.measureToMeasureDto = measureToMeasureDto; | |||
this.treeRootHolder = treeRootHolder; | |||
this.measureRepository = measureRepository; | |||
this.persistDirectories = persistDirectories; | |||
} | |||
@Override | |||
@@ -97,25 +93,47 @@ public class PersistMeasuresStep implements ComputationStep { | |||
} | |||
@Override | |||
public void visitAny(Component component) { | |||
Multimap<String, Measure> measures = measureRepository.getRawMeasures(component); | |||
persistMeasures(component, measures); | |||
public void visitProject(Component project) { | |||
persistMeasures(project); | |||
} | |||
@Override | |||
public void visitModule(Component module) { | |||
persistMeasures(module); | |||
} | |||
@Override | |||
public void visitDirectory(Component directory) { | |||
if (persistDirectories) { | |||
persistMeasures(directory); | |||
} | |||
} | |||
@Override | |||
public void visitView(Component view) { | |||
persistMeasures(view); | |||
} | |||
@Override | |||
public void visitSubView(Component subView) { | |||
persistMeasures(subView); | |||
} | |||
private void persistMeasures(Component component, Multimap<String, Measure> batchReportMeasures) { | |||
for (Map.Entry<String, Collection<Measure>> measures : batchReportMeasures.asMap().entrySet()) { | |||
String metricKey = measures.getKey(); | |||
if (NOT_TO_PERSIST_ON_FILE_METRIC_KEYS.contains(metricKey) && component.getType() == Component.Type.FILE) { | |||
continue; | |||
} | |||
@Override | |||
public void visitProjectView(Component projectView) { | |||
persistMeasures(projectView); | |||
} | |||
private void persistMeasures(Component component) { | |||
Multimap<String, Measure> measures = measureRepository.getRawMeasures(component); | |||
for (Map.Entry<String, Collection<Measure>> measuresByMetricKey : measures.asMap().entrySet()) { | |||
String metricKey = measuresByMetricKey.getKey(); | |||
Metric metric = metricRepository.getByKey(metricKey); | |||
Predicate<Measure> notBestValueOptimized = Predicates.not(BestValueOptimization.from(metric, component)); | |||
MeasureDao measureDao = dbClient.measureDao(); | |||
for (Measure measure : from(measures.getValue()).filter(NonEmptyMeasure.INSTANCE).filter(notBestValueOptimized)) { | |||
measuresByMetricKey.getValue().stream().filter(NonEmptyMeasure.INSTANCE).forEach(measure -> { | |||
MeasureDto measureDto = measureToMeasureDto.toMeasureDto(measure, metric, component); | |||
measureDao.insert(session, measureDto); | |||
} | |||
}); | |||
} | |||
} | |||
@@ -125,7 +143,7 @@ public class PersistMeasuresStep implements ComputationStep { | |||
INSTANCE; | |||
@Override | |||
public boolean apply(@Nonnull Measure input) { | |||
public boolean test(@Nonnull Measure input) { | |||
return input.getValueType() != Measure.ValueType.NO_VALUE || input.hasVariation() || input.getData() != null; | |||
} | |||
} |
@@ -88,6 +88,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { | |||
PersistAnalysisStep.class, | |||
PersistAnalysisPropertiesStep.class, | |||
PersistMeasuresStep.class, | |||
PersistLiveMeasuresStep.class, | |||
PersistIssuesStep.class, | |||
PersistProjectLinksStep.class, | |||
PersistEventsStep.class, |
@@ -30,8 +30,7 @@ import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.user.UserSession; | |||
@@ -110,12 +109,8 @@ public class ShowAction implements DuplicationsWsAction { | |||
@CheckForNull | |||
private String findDataFromComponent(DbSession dbSession, ComponentDto component) { | |||
MeasureQuery query = MeasureQuery.builder() | |||
.setComponentUuid(component.uuid()) | |||
.setMetricKey(CoreMetrics.DUPLICATIONS_DATA_KEY) | |||
.build(); | |||
return dbClient.measureDao().selectSingle(dbSession, query) | |||
.map(MeasureDto::getData) | |||
return dbClient.liveMeasureDao().selectMeasure(dbSession, component.uuid(), CoreMetrics.DUPLICATIONS_DATA_KEY) | |||
.map(LiveMeasureDto::getDataAsString) | |||
.orElse(null); | |||
} | |||
} |
@@ -43,25 +43,22 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricDtoFunctions; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.measure.ws.MetricDtoWithBestValue.MetricDtoToMetricDtoWithBestValueFunction; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Measures; | |||
import org.sonarqube.ws.Measures.ComponentWsResponse; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.emptyMap; | |||
import static java.util.Collections.singletonList; | |||
import static java.util.Collections.singletonMap; | |||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | |||
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | |||
import static org.sonar.server.component.ComponentFinder.ParamNames.DEVELOPER_ID_AND_KEY; | |||
import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | |||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; | |||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; | |||
@@ -133,6 +130,10 @@ public class ComponentAction implements MeasuresWsAction { | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
if (request.param(PARAM_DEVELOPER_ID) != null || request.param(PARAM_DEVELOPER_KEY) != null) { | |||
throw new NotFoundException("The Developer Cockpit feature has been dropped. The specified developer cannot be found."); | |||
} | |||
ComponentWsResponse componentWsResponse = doHandle(toComponentWsRequest(request)); | |||
writeProtobuf(componentWsResponse, request, response); | |||
} | |||
@@ -140,13 +141,12 @@ public class ComponentAction implements MeasuresWsAction { | |||
private ComponentWsResponse doHandle(ComponentRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ComponentDto component = loadComponent(dbSession, request); | |||
Long developerId = searchDeveloperId(dbSession, request); | |||
Optional<ComponentDto> refComponent = getReferenceComponent(dbSession, component); | |||
checkPermissions(component); | |||
SnapshotDto analysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, component.projectUuid()).orElse(null); | |||
List<MetricDto> metrics = searchMetrics(dbSession, request); | |||
List<Measures.Period> periods = snapshotToWsPeriods(analysis); | |||
List<MeasureDto> measures = searchMeasures(dbSession, component, analysis, metrics, developerId); | |||
List<LiveMeasureDto> measures = searchMeasures(dbSession, component, metrics); | |||
return buildResponse(request, component, refComponent, measures, metrics, periods); | |||
} | |||
@@ -162,15 +162,6 @@ public class ComponentAction implements MeasuresWsAction { | |||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||
} | |||
@CheckForNull | |||
private Long searchDeveloperId(DbSession dbSession, ComponentRequest request) { | |||
if (request.getDeveloperId() == null && request.getDeveloperKey() == null) { | |||
return null; | |||
} | |||
return componentFinder.getByUuidOrKey(dbSession, request.getDeveloperId(), request.getDeveloperKey(), DEVELOPER_ID_AND_KEY).getId(); | |||
} | |||
private Optional<ComponentDto> getReferenceComponent(DbSession dbSession, ComponentDto component) { | |||
if (component.getCopyResourceUuid() == null) { | |||
return Optional.absent(); | |||
@@ -179,12 +170,12 @@ public class ComponentAction implements MeasuresWsAction { | |||
return dbClient.componentDao().selectByUuid(dbSession, component.getCopyResourceUuid()); | |||
} | |||
private static ComponentWsResponse buildResponse(ComponentRequest request, ComponentDto component, Optional<ComponentDto> refComponent, List<MeasureDto> measures, | |||
private static ComponentWsResponse buildResponse(ComponentRequest request, ComponentDto component, Optional<ComponentDto> refComponent, List<LiveMeasureDto> measures, | |||
List<MetricDto> metrics, List<Measures.Period> periods) { | |||
ComponentWsResponse.Builder response = ComponentWsResponse.newBuilder(); | |||
Map<Integer, MetricDto> metricsById = Maps.uniqueIndex(metrics, MetricDto::getId); | |||
Map<MetricDto, MeasureDto> measuresByMetric = new HashMap<>(); | |||
for (MeasureDto measure : measures) { | |||
Map<MetricDto, LiveMeasureDto> measuresByMetric = new HashMap<>(); | |||
for (LiveMeasureDto measure : measures) { | |||
MetricDto metric = metricsById.get(measure.getMetricId()); | |||
measuresByMetric.put(metric, measure); | |||
} | |||
@@ -223,20 +214,10 @@ public class ComponentAction implements MeasuresWsAction { | |||
return metrics; | |||
} | |||
private List<MeasureDto> searchMeasures(DbSession dbSession, ComponentDto component, @Nullable SnapshotDto analysis, List<MetricDto> metrics, @Nullable Long developerId) { | |||
if (analysis == null) { | |||
return emptyList(); | |||
} | |||
private List<LiveMeasureDto> searchMeasures(DbSession dbSession, ComponentDto component, List<MetricDto> metrics) { | |||
List<Integer> metricIds = Lists.transform(metrics, MetricDto::getId); | |||
MeasureQuery query = MeasureQuery.builder() | |||
.setPersonId(developerId) | |||
.setMetricIds(metricIds) | |||
.setComponentUuid(component.uuid()) | |||
.build(); | |||
List<MeasureDto> measures = dbClient.measureDao().selectByQuery(dbSession, query); | |||
List<LiveMeasureDto> measures = dbClient.liveMeasureDao().selectByComponentUuids(dbSession, singletonList(component.uuid()), metricIds); | |||
addBestValuesToMeasures(measures, component, metrics); | |||
return measures; | |||
} | |||
@@ -247,16 +228,16 @@ public class ComponentAction implements MeasuresWsAction { | |||
* <li>metric is optimized for best value</li> | |||
* </ul> | |||
*/ | |||
private static void addBestValuesToMeasures(List<MeasureDto> measures, ComponentDto component, List<MetricDto> metrics) { | |||
private static void addBestValuesToMeasures(List<LiveMeasureDto> measures, ComponentDto component, List<MetricDto> metrics) { | |||
if (!QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE.contains(component.qualifier())) { | |||
return; | |||
} | |||
List<MetricDtoWithBestValue> metricWithBestValueList = metrics.stream() | |||
.filter(MetricDtoFunctions.isOptimizedForBestValue()) | |||
.map(new MetricDtoToMetricDtoWithBestValueFunction()) | |||
.map(MetricDtoWithBestValue::new) | |||
.collect(MoreCollectors.toList(metrics.size())); | |||
Map<Integer, MeasureDto> measuresByMetricId = Maps.uniqueIndex(measures, MeasureDto::getMetricId); | |||
Map<Integer, LiveMeasureDto> measuresByMetricId = Maps.uniqueIndex(measures, LiveMeasureDto::getMetricId); | |||
for (MetricDtoWithBestValue metricWithBestValue : metricWithBestValueList) { | |||
if (measuresByMetricId.get(metricWithBestValue.getMetric().getId()) == null) { | |||
@@ -271,9 +252,7 @@ public class ComponentAction implements MeasuresWsAction { | |||
.setComponent(request.param(PARAM_COMPONENT)) | |||
.setBranch(request.param(PARAM_BRANCH)) | |||
.setAdditionalFields(request.paramAsStrings(PARAM_ADDITIONAL_FIELDS)) | |||
.setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS)) | |||
.setDeveloperId(request.param(PARAM_DEVELOPER_ID)) | |||
.setDeveloperKey(request.param(PARAM_DEVELOPER_KEY)); | |||
.setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS)); | |||
checkRequest(!componentRequest.getMetricKeys().isEmpty(), "At least one metric key must be provided"); | |||
return componentRequest; | |||
} |
@@ -22,7 +22,7 @@ package org.sonar.server.measure.ws; | |||
import java.util.Map; | |||
import org.sonar.core.util.Protobuf; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonarqube.ws.Measures; | |||
import org.sonarqube.ws.Measures.Component; | |||
@@ -32,7 +32,7 @@ class ComponentDtoToWsComponent { | |||
// static methods only | |||
} | |||
static Component.Builder componentDtoToWsComponent(ComponentDto component, Map<MetricDto, MeasureDto> measuresByMetric, | |||
static Component.Builder componentDtoToWsComponent(ComponentDto component, Map<MetricDto, LiveMeasureDto> measuresByMetric, | |||
Map<String, ComponentDto> referenceComponentsByUuid) { | |||
Component.Builder wsComponent = componentDtoToWsComponent(component); | |||
@@ -43,7 +43,7 @@ class ComponentDtoToWsComponent { | |||
} | |||
Measures.Measure.Builder measureBuilder = Measures.Measure.newBuilder(); | |||
for (Map.Entry<MetricDto, MeasureDto> entry : measuresByMetric.entrySet()) { | |||
for (Map.Entry<MetricDto, LiveMeasureDto> entry : measuresByMetric.entrySet()) { | |||
MeasureDtoToWsMeasure.updateMeasureBuilder(measureBuilder, entry.getKey(), entry.getValue()); | |||
wsComponent.addMeasures(measureBuilder); | |||
measureBuilder.clear(); |
@@ -61,7 +61,7 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTreeQuery; | |||
import org.sonar.db.component.ComponentTreeQuery.Strategy; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.measure.MeasureTreeQuery; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricDtoFunctions; | |||
@@ -94,8 +94,8 @@ import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetri | |||
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; | |||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.ACTION_COMPONENT_TREE; | |||
@@ -261,6 +261,10 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
} | |||
private ComponentTreeWsResponse doHandle(ComponentTreeRequest request) { | |||
if (request.getDeveloperId() != null || request.getDeveloperKey() != null) { | |||
return emptyResponse(null, request); | |||
} | |||
ComponentTreeData data = load(request); | |||
if (data.getComponents() == null) { | |||
return emptyResponse(data.getBaseComponent(), request); | |||
@@ -320,13 +324,15 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
return additionalFields != null && additionalFields.contains(ADDITIONAL_PERIODS); | |||
} | |||
private static ComponentTreeWsResponse emptyResponse(ComponentDto baseComponent, ComponentTreeRequest request) { | |||
private static ComponentTreeWsResponse emptyResponse(@Nullable ComponentDto baseComponent, ComponentTreeRequest request) { | |||
ComponentTreeWsResponse.Builder response = ComponentTreeWsResponse.newBuilder(); | |||
response.getPagingBuilder() | |||
.setPageIndex(request.getPage()) | |||
.setPageSize(request.getPageSize()) | |||
.setTotal(0); | |||
response.setBaseComponent(componentDtoToWsComponent(baseComponent)); | |||
if (baseComponent != null) { | |||
response.setBaseComponent(componentDtoToWsComponent(baseComponent)); | |||
} | |||
return response.build(); | |||
} | |||
@@ -395,14 +401,13 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
.setBaseComponent(baseComponent) | |||
.build(); | |||
} | |||
Long developerId = searchDeveloperId(dbSession, wsRequest); | |||
ComponentTreeQuery componentTreeQuery = toComponentTreeQuery(wsRequest, baseComponent); | |||
List<ComponentDto> components = searchComponents(dbSession, componentTreeQuery); | |||
List<MetricDto> metrics = searchMetrics(dbSession, wsRequest); | |||
Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric = searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, componentTreeQuery, | |||
components, | |||
metrics, developerId); | |||
metrics); | |||
components = filterComponents(components, measuresByComponentUuidAndMetric, metrics, wsRequest); | |||
components = sortComponents(components, wsRequest, metrics, measuresByComponentUuidAndMetric); | |||
@@ -432,15 +437,6 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||
} | |||
@CheckForNull | |||
private Long searchDeveloperId(DbSession dbSession, ComponentTreeRequest wsRequest) { | |||
if (wsRequest.getDeveloperId() == null && wsRequest.getDeveloperKey() == null) { | |||
return null; | |||
} | |||
return componentFinder.getByUuidOrKey(dbSession, wsRequest.getDeveloperId(), wsRequest.getDeveloperKey(), DEVELOPER_ID_AND_KEY).getId(); | |||
} | |||
private Map<String, ComponentDto> searchReferenceComponentsById(DbSession dbSession, List<ComponentDto> components) { | |||
List<String> referenceComponentUUids = components.stream() | |||
.map(ComponentDto::getCopyResourceUuid) | |||
@@ -483,20 +479,19 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
} | |||
private Table<String, MetricDto, ComponentTreeData.Measure> searchMeasuresByComponentUuidAndMetric(DbSession dbSession, ComponentDto baseComponent, | |||
ComponentTreeQuery componentTreeQuery, List<ComponentDto> components, List<MetricDto> metrics, @Nullable Long developerId) { | |||
ComponentTreeQuery componentTreeQuery, List<ComponentDto> components, List<MetricDto> metrics) { | |||
Map<Integer, MetricDto> metricsById = Maps.uniqueIndex(metrics, MetricDto::getId); | |||
MeasureTreeQuery measureQuery = MeasureTreeQuery.builder() | |||
.setStrategy(MeasureTreeQuery.Strategy.valueOf(componentTreeQuery.getStrategy().name())) | |||
.setNameOrKeyQuery(componentTreeQuery.getNameOrKeyQuery()) | |||
.setQualifiers(componentTreeQuery.getQualifiers()) | |||
.setPersonId(developerId) | |||
.setMetricIds(new ArrayList<>(metricsById.keySet())) | |||
.build(); | |||
Table<String, MetricDto, ComponentTreeData.Measure> measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(), metrics.size()); | |||
dbClient.measureDao().selectTreeByQuery(dbSession, baseComponent, measureQuery, result -> { | |||
MeasureDto measureDto = result.getResultObject(); | |||
dbClient.liveMeasureDao().selectTreeByQuery(dbSession, baseComponent, measureQuery, result -> { | |||
LiveMeasureDto measureDto = result.getResultObject(); | |||
measuresByComponentUuidAndMetric.put( | |||
measureDto.getComponentUuid(), | |||
metricsById.get(measureDto.getMetricId()), |
@@ -25,7 +25,7 @@ import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonarqube.ws.Measures; | |||
@@ -149,9 +149,9 @@ class ComponentTreeData { | |||
private String data; | |||
private double variation; | |||
private Measure(MeasureDto measureDto) { | |||
private Measure(LiveMeasureDto measureDto) { | |||
this.value = toPrimitive(measureDto.getValue()); | |||
this.data = measureDto.getData(); | |||
this.data = measureDto.getDataAsString(); | |||
this.variation = toPrimitive(measureDto.getVariation()); | |||
} | |||
@@ -176,7 +176,7 @@ class ComponentTreeData { | |||
return !isNaN(variation); | |||
} | |||
static Measure createFromMeasureDto(MeasureDto measureDto) { | |||
static Measure createFromMeasureDto(LiveMeasureDto measureDto) { | |||
return new Measure(measureDto); | |||
} | |||
@@ -26,7 +26,6 @@ import javax.annotation.Nullable; | |||
class ComponentTreeRequest { | |||
private String baseComponentId; | |||
private String baseComponentKey; | |||
private String component; | |||
private String branch; | |||
private String strategy; |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.measure.ws; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonarqube.ws.Measures; | |||
@@ -40,6 +41,12 @@ class MeasureDtoToWsMeasure { | |||
updateMeasureBuilder(measureBuilder, metricDto, value == null ? Double.NaN : value, measureDto.getData(), variation == null ? Double.NaN : variation); | |||
} | |||
static void updateMeasureBuilder(Measure.Builder measureBuilder, MetricDto metricDto, LiveMeasureDto measureDto) { | |||
Double value = measureDto.getValue(); | |||
Double variation = measureDto.getVariation(); | |||
updateMeasureBuilder(measureBuilder, metricDto, value == null ? Double.NaN : value, measureDto.getDataAsString(), variation == null ? Double.NaN : variation); | |||
} | |||
static void updateMeasureBuilder(Measure.Builder measureBuilder, MetricDto metric, double doubleValue, @Nullable String stringValue, double variation) { | |||
measureBuilder.setMetric(metric.getKey()); | |||
// a measure value can be null, new_violations metric for example |
@@ -22,12 +22,10 @@ package org.sonar.server.measure.ws; | |||
import com.google.common.collect.ImmutableSortedSet; | |||
import java.util.Locale; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import java.util.function.Predicate; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
class MetricDtoWithBestValue { | |||
@@ -35,11 +33,11 @@ class MetricDtoWithBestValue { | |||
private static final Set<String> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE = ImmutableSortedSet.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE); | |||
private final MetricDto metric; | |||
private final MeasureDto bestValue; | |||
private final LiveMeasureDto bestValue; | |||
MetricDtoWithBestValue(MetricDto metric) { | |||
this.metric = metric; | |||
MeasureDto measure = new MeasureDto().setMetricId(metric.getId()); | |||
LiveMeasureDto measure = new LiveMeasureDto().setMetricId(metric.getId()); | |||
boolean isNewTypeMetric = metric.getKey().toLowerCase(Locale.ENGLISH).startsWith(LOWER_CASE_NEW_METRIC_PREFIX); | |||
if (isNewTypeMetric) { | |||
measure.setVariation(metric.getBestValue()); | |||
@@ -54,19 +52,11 @@ class MetricDtoWithBestValue { | |||
return metric; | |||
} | |||
MeasureDto getBestValue() { | |||
LiveMeasureDto getBestValue() { | |||
return bestValue; | |||
} | |||
static Predicate<ComponentDto> isEligibleForBestValue() { | |||
return component -> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE.contains(component.qualifier()); | |||
} | |||
static class MetricDtoToMetricDtoWithBestValueFunction implements Function<MetricDto, MetricDtoWithBestValue> { | |||
@Override | |||
public MetricDtoWithBestValue apply(@Nonnull MetricDto input) { | |||
return new MetricDtoWithBestValue(input); | |||
} | |||
} | |||
} |
@@ -34,7 +34,7 @@ import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Measures.Measure; | |||
@@ -105,7 +105,7 @@ public class SearchAction implements MeasuresWsAction { | |||
private SearchRequest request; | |||
private List<ComponentDto> projects; | |||
private List<MetricDto> metrics; | |||
private List<MeasureDto> measures; | |||
private List<LiveMeasureDto> measures; | |||
ResponseBuilder(Request httpRequest, DbSession dbSession) { | |||
this.dbSession = dbSession; | |||
@@ -161,10 +161,10 @@ public class SearchAction implements MeasuresWsAction { | |||
.collect(toList()); | |||
} | |||
private List<MeasureDto> searchMeasures() { | |||
return dbClient.measureDao().selectByComponentsAndMetrics(dbSession, | |||
projects.stream().map(ComponentDto::uuid).collect(toList()), | |||
metrics.stream().map(MetricDto::getId).collect(toList())); | |||
private List<LiveMeasureDto> searchMeasures() { | |||
return dbClient.liveMeasureDao().selectByComponentUuids(dbSession, | |||
projects.stream().map(ComponentDto::uuid).collect(MoreCollectors.toArrayList(projects.size())), | |||
metrics.stream().map(MetricDto::getId).collect(MoreCollectors.toArrayList(metrics.size()))); | |||
} | |||
private SearchWsResponse buildResponse() { | |||
@@ -179,7 +179,7 @@ public class SearchAction implements MeasuresWsAction { | |||
Map<String, String> componentNamesByKey = projects.stream().collect(toMap(ComponentDto::getDbKey, ComponentDto::name)); | |||
Map<Integer, MetricDto> metricsById = metrics.stream().collect(toMap(MetricDto::getId, identity())); | |||
Function<MeasureDto, MetricDto> dbMeasureToDbMetric = dbMeasure -> metricsById.get(dbMeasure.getMetricId()); | |||
Function<LiveMeasureDto, MetricDto> dbMeasureToDbMetric = dbMeasure -> metricsById.get(dbMeasure.getMetricId()); | |||
Function<Measure, String> byMetricKey = Measure::getMetric; | |||
Function<Measure, String> byComponentName = wsMeasure -> componentNamesByKey.get(wsMeasure.getComponent()); | |||
@@ -19,12 +19,13 @@ | |||
*/ | |||
package org.sonar.server.project.ws; | |||
import java.util.List; | |||
import java.util.function.Function; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Lists; | |||
import java.util.List; | |||
import java.util.function.Function; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.server.ws.Change; | |||
@@ -39,19 +40,15 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentLinkDto; | |||
import org.sonar.db.component.ComponentQuery; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse; | |||
import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse.Link; | |||
import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse.Project; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static com.google.common.base.Strings.emptyToNull; | |||
import static com.google.common.base.Strings.isNullOrEmpty; | |||
import static java.util.Collections.singletonList; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.api.utils.Paging.offset; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
@@ -177,12 +174,8 @@ public class SearchMyProjectsAction implements ProjectsWsAction { | |||
List<String> projectUuids = Lists.transform(projects, ComponentDto::projectUuid); | |||
List<ComponentLinkDto> projectLinks = dbClient.componentLinkDao().selectByComponentUuids(dbSession, projectUuids); | |||
List<SnapshotDto> snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids); | |||
MetricDto gateStatusMetric = dbClient.metricDao().selectOrFailByKey(dbSession, CoreMetrics.ALERT_STATUS_KEY); | |||
MeasureQuery measureQuery = MeasureQuery.builder() | |||
.setProjectUuids(projectUuids) | |||
.setMetricId(gateStatusMetric.getId()) | |||
.build(); | |||
List<MeasureDto> qualityGates = dbClient.measureDao().selectByQuery(dbSession, measureQuery); | |||
List<LiveMeasureDto> qualityGates = dbClient.liveMeasureDao() | |||
.selectByComponentUuidsAndMetricKeys(dbSession, projectUuids, singletonList(CoreMetrics.ALERT_STATUS_KEY)); | |||
data.setProjects(projects) | |||
.setProjectLinks(projectLinks) |
@@ -29,7 +29,7 @@ import java.util.stream.Collectors; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentLinkDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import static com.google.common.collect.ImmutableList.copyOf; | |||
import static java.util.Objects.requireNonNull; | |||
@@ -86,16 +86,16 @@ class SearchMyProjectsData { | |||
snapshot -> formatDateTime(snapshot.getCreatedAt())))); | |||
} | |||
private static Map<String, String> buildQualityGateStatuses(List<MeasureDto> measures) { | |||
private static Map<String, String> buildQualityGateStatuses(List<LiveMeasureDto> measures) { | |||
return ImmutableMap.copyOf(measures.stream() | |||
.collect(Collectors.toMap(MeasureDto::getComponentUuid, MeasureDto::getData))); | |||
.collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString))); | |||
} | |||
static class Builder { | |||
private List<ComponentDto> projects; | |||
private List<ComponentLinkDto> projectLinks; | |||
private List<SnapshotDto> snapshots; | |||
private List<MeasureDto> qualityGates; | |||
private List<LiveMeasureDto> qualityGates; | |||
private Integer totalNbOfProjects; | |||
private Builder() { | |||
@@ -117,7 +117,7 @@ class SearchMyProjectsData { | |||
return this; | |||
} | |||
public Builder setQualityGates(List<MeasureDto> qGateStatuses) { | |||
public Builder setQualityGates(List<LiveMeasureDto> qGateStatuses) { | |||
this.qualityGates = qGateStatuses; | |||
return this; | |||
} |
@@ -19,11 +19,11 @@ | |||
*/ | |||
package org.sonar.server.qualitygate.ws; | |||
import com.google.common.base.Optional; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
@@ -35,8 +35,8 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.component.ComponentFinder.ParamNames; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
@@ -45,7 +45,6 @@ import org.sonar.server.ws.KeyExamples; | |||
import org.sonarqube.ws.Qualitygates.ProjectStatusResponse; | |||
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; | |||
@@ -88,8 +87,7 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
.setSince("5.3") | |||
.setHandler(this) | |||
.setChangelog( | |||
new Change("6.4", "The field 'ignoredConditions' is added to the response") | |||
); | |||
new Change("6.4", "The field 'ignoredConditions' is added to the response")); | |||
action.createParam(PARAM_ANALYSIS_ID) | |||
.setDescription("Analysis id") | |||
@@ -120,11 +118,11 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
writeProtobuf(projectStatusResponse, request, response); | |||
} | |||
private ProjectStatusResponse doHandle(String analysisId, String projectId, String projectKey) { | |||
private ProjectStatusResponse doHandle(@Nullable String analysisId, @Nullable String projectId, @Nullable String projectKey) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ProjectAndSnapshot projectAndSnapshot = getProjectAndSnapshot(dbSession, analysisId, projectId, projectKey); | |||
checkPermission(projectAndSnapshot.project); | |||
Optional<String> measureData = getQualityGateDetailsMeasureData(dbSession, projectAndSnapshot.project); | |||
Optional<String> measureData = loadQualityGateDetails(dbSession, projectAndSnapshot, analysisId != null); | |||
return ProjectStatusResponse.newBuilder() | |||
.setProjectStatus(new QualityGateDetailsFormatter(measureData, projectAndSnapshot.snapshotDto).format()) | |||
@@ -132,10 +130,11 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
} | |||
} | |||
private ProjectAndSnapshot getProjectAndSnapshot(DbSession dbSession, String analysisId, String projectId, String projectKey) { | |||
private ProjectAndSnapshot getProjectAndSnapshot(DbSession dbSession, @Nullable String analysisId, @Nullable String projectId, @Nullable String projectKey) { | |||
if (!isNullOrEmpty(analysisId)) { | |||
return getSnapshotThenProject(dbSession, analysisId); | |||
} else if (!isNullOrEmpty(projectId) ^ !isNullOrEmpty(projectKey)) { | |||
} | |||
if (!isNullOrEmpty(projectId) ^ !isNullOrEmpty(projectKey)) { | |||
return getProjectThenSnapshot(dbSession, projectId, projectKey); | |||
} | |||
@@ -144,7 +143,7 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
private ProjectAndSnapshot getProjectThenSnapshot(DbSession dbSession, String projectId, String projectKey) { | |||
ComponentDto projectDto = componentFinder.getByUuidOrKey(dbSession, projectId, projectKey, ParamNames.PROJECT_ID_AND_KEY); | |||
java.util.Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, projectDto.projectUuid()); | |||
Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, projectDto.projectUuid()); | |||
return new ProjectAndSnapshot(projectDto, snapshot.orElse(null)); | |||
} | |||
@@ -155,20 +154,24 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
} | |||
private SnapshotDto getSnapshot(DbSession dbSession, String analysisUuid) { | |||
java.util.Optional<SnapshotDto> snapshotDto = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid); | |||
Optional<SnapshotDto> snapshotDto = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid); | |||
return checkFoundWithOptional(snapshotDto, "Analysis with id '%s' is not found", analysisUuid); | |||
} | |||
private Optional<String> getQualityGateDetailsMeasureData(DbSession dbSession, ComponentDto project) { | |||
MeasureQuery measureQuery = MeasureQuery.builder() | |||
.setProjectUuids(singletonList(project.projectUuid())) | |||
.setMetricKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY) | |||
.build(); | |||
List<MeasureDto> measures = dbClient.measureDao().selectByQuery(dbSession, measureQuery); | |||
private Optional<String> loadQualityGateDetails(DbSession dbSession, ProjectAndSnapshot projectAndSnapshot, boolean onAnalysis) { | |||
if (onAnalysis) { | |||
if (!projectAndSnapshot.snapshotDto.isPresent()) { | |||
return Optional.empty(); | |||
} | |||
// get the gate status as it was computed during the specified analysis | |||
String analysisUuid = projectAndSnapshot.snapshotDto.get().getUuid(); | |||
return dbClient.measureDao().selectMeasure(dbSession, analysisUuid, projectAndSnapshot.project.projectUuid(), CoreMetrics.QUALITY_GATE_DETAILS_KEY) | |||
.map(MeasureDto::getData); | |||
} | |||
return measures.isEmpty() | |||
? Optional.absent() | |||
: Optional.fromNullable(measures.get(0).getData()); | |||
// do not restrict to a specified analysis, use the live measure | |||
Optional<LiveMeasureDto> measure = dbClient.liveMeasureDao().selectMeasure(dbSession, projectAndSnapshot.project.projectUuid(), CoreMetrics.QUALITY_GATE_DETAILS_KEY); | |||
return measure.map(LiveMeasureDto::getDataAsString); | |||
} | |||
private void checkPermission(ComponentDto project) { | |||
@@ -178,13 +181,14 @@ public class ProjectStatusAction implements QualityGatesWsAction { | |||
} | |||
} | |||
@Immutable | |||
private static class ProjectAndSnapshot { | |||
private final ComponentDto project; | |||
private final Optional<SnapshotDto> snapshotDto; | |||
private ProjectAndSnapshot(ComponentDto project, @Nullable SnapshotDto snapshotDto) { | |||
this.project = project; | |||
this.snapshotDto = Optional.fromNullable(snapshotDto); | |||
this.snapshotDto = Optional.ofNullable(snapshotDto); | |||
} | |||
} | |||
} |
@@ -19,11 +19,11 @@ | |||
*/ | |||
package org.sonar.server.qualitygate.ws; | |||
import com.google.common.base.Optional; | |||
import com.google.gson.JsonArray; | |||
import com.google.gson.JsonElement; | |||
import com.google.gson.JsonObject; | |||
import com.google.gson.JsonParser; | |||
import java.util.Optional; | |||
import java.util.function.Predicate; | |||
import java.util.stream.StreamSupport; | |||
import javax.annotation.Nullable; |
@@ -26,9 +26,7 @@ import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Consumer; | |||
import java.util.function.Function; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.ResourceType; | |||
@@ -45,8 +43,7 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.MeasureQuery; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.permission.OrganizationPermission; | |||
import org.sonar.db.property.PropertyDto; | |||
@@ -166,10 +163,6 @@ public class ComponentAction implements NavigationWsAction { | |||
.endObject(); | |||
} | |||
private static Function<MeasureDto, Stream<QualityProfile>> toQualityProfiles() { | |||
return dbMeasure -> QPMeasureData.fromJson(dbMeasure.getData()).getProfiles().stream(); | |||
} | |||
private static void writePage(JsonWriter json, Page page) { | |||
json.beginObject() | |||
.prop("key", page.getKey()) | |||
@@ -205,12 +198,11 @@ public class ComponentAction implements NavigationWsAction { | |||
return componentFavourites.size() == 1; | |||
} | |||
private void writeProfiles(JsonWriter json, DbSession session, ComponentDto component) { | |||
private void writeProfiles(JsonWriter json, DbSession dbSession, ComponentDto component) { | |||
json.name("qualityProfiles").beginArray(); | |||
dbClient.measureDao().selectSingle(session, MeasureQuery.builder().setComponentUuid(component.projectUuid()).setMetricKey(QUALITY_PROFILES_KEY).build()) | |||
.ifPresent(dbMeasure -> Stream.of(dbMeasure) | |||
.flatMap(toQualityProfiles()) | |||
.forEach(writeToJson(json))); | |||
dbClient.liveMeasureDao().selectMeasure(dbSession, component.projectUuid(), QUALITY_PROFILES_KEY) | |||
.map(LiveMeasureDto::getDataAsString) | |||
.ifPresent(data -> QPMeasureData.fromJson(data).getProfiles().forEach(writeToJson(json))); | |||
json.endArray(); | |||
} | |||
@@ -34,7 +34,6 @@ import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.ResourceTypesRule; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.component.SnapshotTesting; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
@@ -250,8 +249,7 @@ public class ListActionTest { | |||
ComponentDto project = db.components().insertMainBranch(); | |||
userSession.logIn().addProjectPermission(UserRole.USER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); | |||
SnapshotDto branchAnalysis = db.components().insertSnapshot(branch); | |||
db.measures().insertMeasure(branch, branchAnalysis, qualityGateStatus, m -> m.setData("OK")); | |||
db.measures().insertLiveMeasure(branch, qualityGateStatus, m -> m.setData("OK")); | |||
ListWsResponse response = ws.newRequest() | |||
.setParam("project", project.getKey()) |
@@ -25,7 +25,6 @@ import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
@@ -135,19 +134,18 @@ public class AppActionTest { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto directory = db.components().insertComponent(newDirectory(project, "src")); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project, directory)); | |||
SnapshotDto analysis = db.components().insertSnapshot(project); | |||
MetricDto lines = db.measures().insertMetric(m -> m.setKey(LINES_KEY)); | |||
db.measures().insertMeasure(file, analysis, lines, m -> m.setValue(200d)); | |||
db.measures().insertLiveMeasure(file, lines, m -> m.setValue(200d)); | |||
MetricDto duplicatedLines = db.measures().insertMetric(m -> m.setKey(DUPLICATED_LINES_DENSITY_KEY)); | |||
db.measures().insertMeasure(file, analysis, duplicatedLines, m -> m.setValue(7.4)); | |||
db.measures().insertLiveMeasure(file, duplicatedLines, m -> m.setValue(7.4)); | |||
MetricDto tests = db.measures().insertMetric(m -> m.setKey(TESTS_KEY)); | |||
db.measures().insertMeasure(file, analysis, tests, m -> m.setValue(3d)); | |||
db.measures().insertLiveMeasure(file, tests, m -> m.setValue(3d)); | |||
MetricDto technicalDebt = db.measures().insertMetric(m -> m.setKey(TECHNICAL_DEBT_KEY)); | |||
db.measures().insertMeasure(file, analysis, technicalDebt, m -> m.setValue(182d)); | |||
db.measures().insertLiveMeasure(file, technicalDebt, m -> m.setValue(182d)); | |||
MetricDto issues = db.measures().insertMetric(m -> m.setKey(VIOLATIONS_KEY)); | |||
db.measures().insertMeasure(file, analysis, issues, m -> m.setValue(231d)); | |||
db.measures().insertLiveMeasure(file, issues, m -> m.setValue(231d)); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY)); | |||
db.measures().insertMeasure(file, analysis, coverage, m -> m.setValue(95.4d)); | |||
db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(95.4d)); | |||
userSession.logIn("john").addProjectPermission(USER, project); | |||
String result = ws.newRequest() | |||
@@ -170,9 +168,8 @@ public class AppActionTest { | |||
public void get_by_uuid() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project, project)); | |||
SnapshotDto analysis = db.components().insertSnapshot(project); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY)); | |||
db.measures().insertMeasure(file, analysis, coverage, m -> m.setValue(95.4d)); | |||
db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(95.4d)); | |||
userSession.logIn("john").addProjectPermission(USER, project); | |||
String result = ws.newRequest() | |||
@@ -258,9 +255,8 @@ public class AppActionTest { | |||
ComponentDto module = db.components().insertComponent(newModuleDto(branch)); | |||
ComponentDto directory = db.components().insertComponent(newDirectory(module, "src")); | |||
ComponentDto file = db.components().insertComponent(newFileDto(module, directory)); | |||
SnapshotDto analysis = db.components().insertSnapshot(branch); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY)); | |||
db.measures().insertMeasure(file, analysis, coverage, m -> m.setValue(95.4d)); | |||
db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(95.4d)); | |||
String result = ws.newRequest() | |||
.setParam("component", file.getKey()) |
@@ -41,8 +41,7 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.property.PropertyDto; | |||
@@ -316,9 +315,9 @@ public class SearchProjectsActionTest { | |||
userSession.logIn(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name())); | |||
ComponentDto project1 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setData("OK"))); | |||
ComponentDto project2 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setData("OK"))); | |||
ComponentDto project3 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setData("ERROR"))); | |||
ComponentDto project1 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK"))); | |||
ComponentDto project2 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK"))); | |||
ComponentDto project3 = insertProject(organizationDto, new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR"))); | |||
SearchProjectsWsResponse result = call(request.setFilter("alert_status = OK")); | |||
@@ -332,10 +331,10 @@ public class SearchProjectsActionTest { | |||
userSession.logIn(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType(DATA.name())); | |||
ComponentDto project1 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("<null>=2;java=6;xoo=18"))); | |||
ComponentDto project2 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("java=3;xoo=9"))); | |||
ComponentDto project3 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("xoo=1"))); | |||
ComponentDto project4 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("<null>=1;java=5;xoo=13"))); | |||
ComponentDto project1 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18"))); | |||
ComponentDto project2 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("java=3;xoo=9"))); | |||
ComponentDto project3 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("xoo=1"))); | |||
ComponentDto project4 = insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=1;java=5;xoo=13"))); | |||
SearchProjectsWsResponse result = call(request.setFilter("languages IN (java, js, <null>)")); | |||
@@ -628,10 +627,10 @@ public class SearchProjectsActionTest { | |||
userSession.logIn(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType(DATA.name())); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("<null>=2;java=6;xoo=18"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("java=5;xoo=19"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("xoo=1"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("<null>=1;java=3;xoo=8"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("java=5;xoo=19"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("xoo=1"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=1;java=3;xoo=8"))); | |||
SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_LANGUAGES))); | |||
@@ -651,8 +650,8 @@ public class SearchProjectsActionTest { | |||
userSession.logIn(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType(DATA.name())); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("<null>=2;java=6"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setData("java=5"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6"))); | |||
insertProject(organizationDto, new Measure(languagesDistribution, c -> c.setValue(null).setData("java=5"))); | |||
SearchProjectsWsResponse result = call(request.setFilter("languages = xoo").setFacets(singletonList(FILTER_LANGUAGES))); | |||
@@ -964,10 +963,10 @@ public class SearchProjectsActionTest { | |||
userSession.logIn(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name())); | |||
ComponentDto project1 = insertProject(organization, c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setData("ERROR"))); | |||
ComponentDto project2 = insertProject(organization, c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setData("WARN"))); | |||
ComponentDto project3 = insertProject(organization, c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setData("OK"))); | |||
ComponentDto project4 = insertProject(organization, c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus, c -> c.setData("OK"))); | |||
ComponentDto project1 = insertProject(organization, c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR"))); | |||
ComponentDto project2 = insertProject(organization, c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("WARN"))); | |||
ComponentDto project3 = insertProject(organization, c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK"))); | |||
ComponentDto project4 = insertProject(organization, c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK"))); | |||
assertThat(call(request.setSort(QUALITY_GATE_STATUS).setAsc(true)).getComponentsList()).extracting(Component::getKey) | |||
.containsExactly(project3.getDbKey(), project4.getDbKey(), project2.getDbKey(), project1.getDbKey()); | |||
@@ -1138,8 +1137,7 @@ public class SearchProjectsActionTest { | |||
private ComponentDto insertProject(OrganizationDto organizationDto, Consumer<ComponentDto> projectConsumer, Measure... measures) { | |||
ComponentDto project = db.components().insertPublicProject(organizationDto, projectConsumer); | |||
SnapshotDto analysis = db.components().insertSnapshot(project); | |||
Arrays.stream(measures).forEach(m -> db.measures().insertMeasure(project, analysis, m.metric, m.consumer)); | |||
Arrays.stream(measures).forEach(m -> db.measures().insertLiveMeasure(project, m.metric, m.consumer)); | |||
authorizationIndexerTester.allowOnlyAnyone(project); | |||
projectMeasuresIndexer.indexOnAnalysis(project.uuid()); | |||
return project; | |||
@@ -1147,9 +1145,9 @@ public class SearchProjectsActionTest { | |||
private static class Measure { | |||
private final MetricDto metric; | |||
private final Consumer<MeasureDto> consumer; | |||
private final Consumer<LiveMeasureDto> consumer; | |||
public Measure(MetricDto metric, Consumer<MeasureDto> consumer) { | |||
public Measure(MetricDto metric, Consumer<LiveMeasureDto> consumer) { | |||
this.metric = metric; | |||
this.consumer = consumer; | |||
} |
@@ -19,7 +19,7 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import com.google.common.base.Predicate; | |||
import java.util.function.Predicate; | |||
import org.junit.Test; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
@@ -56,18 +56,18 @@ public class BestValueOptimizationTest { | |||
public void apply_returns_true_for_value_true_for_Boolean_Metric_and_best_value_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_TRUE, FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(true))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(false))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(true))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(false))).isFalse(); | |||
} | |||
@Test | |||
public void apply_returns_false_if_component_is_not_a_FILE_for_Boolean_Metric_and_best_value_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_TRUE, SOME_NON_FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false))).isFalse(); | |||
} | |||
@Test | |||
@@ -75,8 +75,8 @@ public class BestValueOptimizationTest { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_TRUE, FILE_COMPONENT); | |||
for (Measure.NewMeasureBuilder builder : builders_of_non_bestValueOptimized_measures()) { | |||
assertThat(underTest.apply(builder.create(true))).isFalse(); | |||
assertThat(underTest.apply(builder.create(false))).isFalse(); | |||
assertThat(underTest.test(builder.create(true))).isFalse(); | |||
assertThat(underTest.test(builder.create(false))).isFalse(); | |||
} | |||
} | |||
@@ -84,25 +84,25 @@ public class BestValueOptimizationTest { | |||
public void apply_returns_false_if_measure_has_data_for_Boolean_Metric_and_best_value_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_TRUE, FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true, SOME_DATA))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false, SOME_DATA))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true, SOME_DATA))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false, SOME_DATA))).isFalse(); | |||
} | |||
@Test | |||
public void apply_returns_true_for_value_false_for_Boolean_Metric_and_best_value_not_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_FALSE, FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(false))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(false))).isTrue(); | |||
} | |||
@Test | |||
public void apply_returns_false_if_component_is_not_a_FILE_for_Boolean_Metric_and_best_value_not_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_FALSE, SOME_NON_FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false))).isFalse(); | |||
} | |||
@Test | |||
@@ -110,8 +110,8 @@ public class BestValueOptimizationTest { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_FALSE, FILE_COMPONENT); | |||
for (Measure.NewMeasureBuilder builder : builders_of_non_bestValueOptimized_measures()) { | |||
assertThat(underTest.apply(builder.create(true))).isFalse(); | |||
assertThat(underTest.apply(builder.create(false))).isFalse(); | |||
assertThat(underTest.test(builder.create(true))).isFalse(); | |||
assertThat(underTest.test(builder.create(false))).isFalse(); | |||
} | |||
} | |||
@@ -119,59 +119,59 @@ public class BestValueOptimizationTest { | |||
public void apply_returns_false_if_measure_has_data_for_Boolean_Metric_and_best_value_not_1() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(METRIC_BOOLEAN_FALSE, FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(true, SOME_DATA))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(false, SOME_DATA))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(true, SOME_DATA))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(false, SOME_DATA))).isFalse(); | |||
} | |||
@Test | |||
public void verify_value_comparison_for_int_metric() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.INT, 10), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(10))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(10))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(11))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(10))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(10))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(11))).isFalse(); | |||
} | |||
@Test | |||
public void verify_value_comparison_for_long_metric() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.WORK_DUR, 9511L), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(9511L))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(9511L))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(963L))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(9511L))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(9511L))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(963L))).isFalse(); | |||
} | |||
@Test | |||
public void verify_value_comparison_for_rating_metric() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.RATING, A.getIndex()), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(A.getIndex()))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation((double) A.getIndex()).createNoValue())).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(B.getIndex()))).isFalse(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation((double) B.getIndex()).createNoValue())).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(A.getIndex()))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation((double) A.getIndex()).createNoValue())).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(B.getIndex()))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation((double) B.getIndex()).createNoValue())).isFalse(); | |||
} | |||
@Test | |||
public void verify_value_comparison_for_double_metric() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.FLOAT, 36.5d), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(36.5d, 1))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(36.5d, 1))).isTrue(); | |||
assertThat(underTest.apply(newMeasureBuilder().create(36.6d, 1))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(36.5d, 1))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().setVariation(SOME_EMPTY_VARIATIONS).create(36.5d, 1))).isTrue(); | |||
assertThat(underTest.test(newMeasureBuilder().create(36.6d, 1))).isFalse(); | |||
} | |||
@Test | |||
public void apply_returns_false_for_String_measure() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.FLOAT, 36.5d), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create("aaa"))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create("aaa"))).isFalse(); | |||
} | |||
@Test | |||
public void apply_returns_false_for_LEVEL_measure() { | |||
Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.STRING, 36.5d), FILE_COMPONENT); | |||
assertThat(underTest.apply(newMeasureBuilder().create(Measure.Level.OK))).isFalse(); | |||
assertThat(underTest.test(newMeasureBuilder().create(Measure.Level.OK))).isFalse(); | |||
} | |||
private static MetricImpl createMetric(Metric.MetricType metricType, double bestValue) { |
@@ -19,23 +19,19 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.measure; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static com.google.common.collect.Maps.filterKeys; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Optional; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.collect.ImmutableSetMultimap; | |||
import com.google.common.collect.SetMultimap; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentProvider; | |||
@@ -48,11 +44,12 @@ import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolde | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Optional; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.collect.ImmutableSetMultimap; | |||
import com.google.common.collect.SetMultimap; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static com.google.common.collect.Maps.filterKeys; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
/** | |||
* An implementation of MeasureRepository as a JUnit rule which provides add methods for raw measures and extra add | |||
@@ -192,13 +189,6 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe | |||
return Optional.fromNullable(baseMeasures.get(new InternalKey(component, metric))); | |||
} | |||
@Override | |||
public int loadAsRawMeasures(Collection<Component> components, Collection<Metric> metrics) { | |||
this.loadedAsRawComponents = components; | |||
this.loadedAsRawMetrics = metrics; | |||
return 0; | |||
} | |||
public Collection<Component> getComponentsLoadedAsRaw() { | |||
return loadedAsRawComponents; | |||
} |
@@ -26,12 +26,11 @@ import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.Developer; | |||
import org.sonar.server.computation.task.projectanalysis.component.DumbDeveloper; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import org.sonar.server.computation.task.projectanalysis.metric.Metric; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricImpl; | |||
@@ -41,7 +40,6 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(DataProviderRunner.class) | |||
public class MeasureToMeasureDtoTest { | |||
private static final MetricImpl SOME_METRIC = new MetricImpl(42, "metric_key", "metric_name", Metric.MetricType.STRING); | |||
private static final int SOME_COMPONENT_ID = 951; | |||
private static final String SOME_DATA = "some_data"; | |||
private static final String SOME_STRING = "some_string"; | |||
private static final double SOME_VARIATIONS = 1d; | |||
@@ -55,16 +53,15 @@ public class MeasureToMeasureDtoTest { | |||
private static final Component SOME_COMPONENT = ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("uuid_1").build(); | |||
@Rule | |||
public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.create(SOME_COMPONENT); | |||
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule(); | |||
@Rule | |||
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule(); | |||
public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule(); | |||
MeasureToMeasureDto underTest = new MeasureToMeasureDto(dbIdsRepository, analysisMetadataHolder); | |||
private MeasureToMeasureDto underTest = new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder); | |||
@Before | |||
public void setUp() throws Exception { | |||
dbIdsRepository.setComponentId(SOME_COMPONENT, SOME_COMPONENT_ID); | |||
analysisMetadataHolder.setUuid(ANALYSIS_UUID); | |||
} | |||
@@ -130,22 +127,6 @@ public class MeasureToMeasureDtoTest { | |||
MeasureDto measureDto = underTest.toMeasureDto(measure, metric, SOME_COMPONENT); | |||
assertThat(measureDto.getComponentUuid()).isEqualTo(SOME_COMPONENT.getUuid()); | |||
// assertThat(measureDto.getSnapshotId()).isEqualTo(SOME_SNAPSHOT_ID); | |||
} | |||
@Test | |||
@UseDataProvider("all_types_Measures") | |||
public void toMeasureDto_does_no_set_developerId_if_not_set_in_Measure(Measure measure, Metric metric) { | |||
assertThat(underTest.toMeasureDto(measure, metric, SOME_COMPONENT).getDeveloperId()).isNull(); | |||
} | |||
@Test | |||
public void toMeasureDto_sets_developerId_if_set_in_Measure() { | |||
Developer developer = new DumbDeveloper("DEV1"); | |||
dbIdsRepository.setDeveloperId(developer, 42); | |||
Measure measure = Measure.newMeasureBuilder().forDeveloper(developer).createNoValue(); | |||
assertThat(underTest.toMeasureDto(measure, SOME_BOOLEAN_METRIC, SOME_COMPONENT).getDeveloperId()).isEqualTo(42); | |||
} | |||
@Test | |||
@@ -200,4 +181,16 @@ public class MeasureToMeasureDtoTest { | |||
assertThat(trueMeasureDto.getValue()).isNull(); | |||
assertThat(trueMeasureDto.getData()).isEqualTo(Measure.Level.OK.name()); | |||
} | |||
@Test | |||
public void toLiveMeasureDto() { | |||
treeRootHolder.setRoot(SOME_COMPONENT); | |||
LiveMeasureDto liveMeasureDto = underTest.toLiveMeasureDto( | |||
Measure.newMeasureBuilder().create(Measure.Level.OK), | |||
SOME_LEVEL_METRIC, | |||
SOME_COMPONENT); | |||
assertThat(liveMeasureDto.getTextValue()).isEqualTo(Measure.Level.OK.name()); | |||
} | |||
} |
@@ -0,0 +1,290 @@ | |||
/* | |||
* 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.computation.task.projectanalysis.step; | |||
import java.util.Optional; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.ViewsComponent; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.measure.MeasureToMeasureDto; | |||
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.measure.MeasureTesting.newLiveMeasure; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT_VIEW; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.SUBVIEW; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.VIEW; | |||
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; | |||
public class PersistLiveMeasuresStepTest extends BaseStepTest { | |||
private static final Metric STRING_METRIC = new Metric.Builder("string-metric", "String metric", Metric.ValueType.STRING).create(); | |||
private static final Metric INT_METRIC = new Metric.Builder("int-metric", "int metric", Metric.ValueType.INT).create(); | |||
private static final Metric METRIC_WITH_BEST_VALUE = new Metric.Builder("best-value-metric", "best value metric", Metric.ValueType.INT) | |||
.setBestValue(0.0) | |||
.setOptimizedBestValue(true) | |||
.create(); | |||
private static final int REF_1 = 1; | |||
private static final int REF_2 = 2; | |||
private static final int REF_3 = 3; | |||
private static final int REF_4 = 4; | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||
@Rule | |||
public MetricRepositoryRule metricRepository = new MetricRepositoryRule(); | |||
@Rule | |||
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); | |||
@Rule | |||
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule(); | |||
private DbClient dbClient = db.getDbClient(); | |||
@Before | |||
public void setUp() { | |||
MetricDto stringMetricDto = db.measures().insertMetric(m -> m.setKey(STRING_METRIC.getKey()).setValueType(Metric.ValueType.STRING.name())); | |||
MetricDto intMetricDto = db.measures().insertMetric(m -> m.setKey(INT_METRIC.getKey()).setValueType(Metric.ValueType.INT.name())); | |||
MetricDto bestValueMMetricDto = db.measures().insertMetric(m -> m.setKey(METRIC_WITH_BEST_VALUE.getKey()).setValueType(Metric.ValueType.INT.name()).setOptimizedBestValue(true).setBestValue(0.0)); | |||
metricRepository.add(stringMetricDto.getId(), STRING_METRIC); | |||
metricRepository.add(intMetricDto.getId(), INT_METRIC); | |||
metricRepository.add(bestValueMMetricDto.getId(), METRIC_WITH_BEST_VALUE); | |||
} | |||
@Test | |||
public void persist_live_measures_of_project_analysis() { | |||
prepareProject(); | |||
// the computed measures | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value")); | |||
measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("module-value")); | |||
measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("dir-value")); | |||
measureRepository.addRawMeasure(REF_4, STRING_METRIC.getKey(), newMeasureBuilder().create("file-value")); | |||
step().execute(); | |||
// all measures are persisted, from project to file | |||
assertThat(db.countRowsOfTable("live_measures")).isEqualTo(4); | |||
assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("project-value"); | |||
assertThat(selectMeasure("module-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("module-value"); | |||
assertThat(selectMeasure("dir-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("dir-value"); | |||
assertThat(selectMeasure("file-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("file-value"); | |||
} | |||
@Test | |||
public void measures_without_value_are_not_persisted() { | |||
prepareProject(); | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().createNoValue()); | |||
measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().createNoValue()); | |||
step().execute(); | |||
assertThatMeasureIsNotPersisted("project-uuid", STRING_METRIC); | |||
assertThatMeasureIsNotPersisted("project-uuid", INT_METRIC); | |||
} | |||
@Test | |||
public void measures_on_leak_period_are_persisted() { | |||
prepareProject(); | |||
measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().setVariation(42.0).createNoValue()); | |||
step().execute(); | |||
LiveMeasureDto persistedMeasure = selectMeasure("project-uuid", INT_METRIC).get(); | |||
assertThat(persistedMeasure.getValue()).isNull(); | |||
assertThat(persistedMeasure.getVariation()).isEqualTo(42.0); | |||
} | |||
@Test | |||
public void delete_measures_from_db_if_no_more_computed() { | |||
prepareProject(); | |||
// measure to be updated | |||
LiveMeasureDto measureOnFileInProject = insertMeasure("file-uuid", "project-uuid", INT_METRIC); | |||
// measure to be deleted because on a file that has been deleted | |||
LiveMeasureDto measureOnDeletedFileInProject = insertMeasure("deleted-file-in-project", "project-uuid", INT_METRIC); | |||
// measure to be deleted because not computed anymore | |||
LiveMeasureDto otherMeasureOnFileInProject = insertMeasure("file-uuid", "project-uuid", STRING_METRIC); | |||
// measure in another project, not touched | |||
LiveMeasureDto measureInOtherProject = insertMeasure("other-file-uuid", "other-project-uuid", INT_METRIC); | |||
db.commit(); | |||
measureRepository.addRawMeasure(REF_4, INT_METRIC.getKey(), newMeasureBuilder().create(42)); | |||
step().execute(); | |||
assertThatMeasureHasValue(measureOnFileInProject, 42); | |||
assertThatMeasureDoesNotExist(measureOnDeletedFileInProject); | |||
assertThatMeasureDoesNotExist(otherMeasureOnFileInProject); | |||
assertThatMeasureHasValue(measureInOtherProject, (int)measureInOtherProject.getValue().doubleValue()); | |||
} | |||
@Test | |||
public void do_not_persist_file_measures_with_best_value() { | |||
prepareProject(); | |||
// measure to be deleted because new value matches the metric best value | |||
LiveMeasureDto oldMeasure = insertMeasure("file-uuid", "project-uuid", INT_METRIC); | |||
db.commit(); | |||
// project measure with metric best value -> persist with value 0 | |||
measureRepository.addRawMeasure(REF_1, METRIC_WITH_BEST_VALUE.getKey(), newMeasureBuilder().create(0)); | |||
// file measure with metric best value -> do not persist | |||
measureRepository.addRawMeasure(REF_4, METRIC_WITH_BEST_VALUE.getKey(), newMeasureBuilder().create(0)); | |||
step().execute(); | |||
assertThatMeasureDoesNotExist(oldMeasure); | |||
assertThatMeasureHasValue("project-uuid", METRIC_WITH_BEST_VALUE, 0); | |||
} | |||
@Test | |||
public void persist_live_measures_of_portfolio_analysis() { | |||
preparePortfolio(); | |||
// the computed measures | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("view-value")); | |||
measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("subview-value")); | |||
measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value")); | |||
step().execute(); | |||
assertThat(db.countRowsOfTable("live_measures")).isEqualTo(3); | |||
assertThat(selectMeasure("view-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("view-value"); | |||
assertThat(selectMeasure("subview-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("subview-value"); | |||
assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getDataAsString()).isEqualTo("project-value"); | |||
} | |||
private LiveMeasureDto insertMeasure(String componentUuid, String projectUuid, Metric metric) { | |||
LiveMeasureDto measure = newLiveMeasure() | |||
.setComponentUuid(componentUuid) | |||
.setProjectUuid(projectUuid) | |||
.setMetricId(metricRepository.getByKey(metric.getKey()).getId()); | |||
dbClient.liveMeasureDao().insertOrUpdate(db.getSession(), measure, null); | |||
return measure; | |||
} | |||
private void assertThatMeasureHasValue(LiveMeasureDto template, int expectedValue) { | |||
Optional<LiveMeasureDto> persisted = dbClient.liveMeasureDao().selectMeasure(db.getSession(), | |||
template.getComponentUuid(), metricRepository.getById(template.getMetricId()).getKey()); | |||
assertThat(persisted).isPresent(); | |||
assertThat(persisted.get().getValue()).isEqualTo((double) expectedValue); | |||
} | |||
private void assertThatMeasureHasValue(String componentUuid, Metric metric, int expectedValue) { | |||
Optional<LiveMeasureDto> persisted = dbClient.liveMeasureDao().selectMeasure(db.getSession(), | |||
componentUuid, metric.getKey()); | |||
assertThat(persisted).isPresent(); | |||
assertThat(persisted.get().getValue()).isEqualTo((double) expectedValue); | |||
} | |||
private void assertThatMeasureDoesNotExist(LiveMeasureDto template) { | |||
assertThat(dbClient.liveMeasureDao().selectMeasure(db.getSession(), | |||
template.getComponentUuid(), metricRepository.getById(template.getMetricId()).getKey())) | |||
.isEmpty(); | |||
} | |||
private void prepareProject() { | |||
// tree of components as defined by scanner report | |||
Component project = ReportComponent.builder(PROJECT, REF_1).setUuid("project-uuid") | |||
.addChildren( | |||
ReportComponent.builder(MODULE, REF_2).setUuid("module-uuid") | |||
.addChildren( | |||
ReportComponent.builder(DIRECTORY, REF_3).setUuid("dir-uuid") | |||
.addChildren( | |||
ReportComponent.builder(FILE, REF_4).setUuid("file-uuid") | |||
.build()) | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(project); | |||
analysisMetadataHolder.setProject(Project.copyOf(project)); | |||
// components as persisted in db | |||
ComponentDto projectDto = insertComponent("project-key", "project-uuid"); | |||
ComponentDto moduleDto = insertComponent("module-key", "module-uuid"); | |||
ComponentDto dirDto = insertComponent("dir-key", "dir-uuid"); | |||
ComponentDto fileDto = insertComponent("file-key", "file-uuid"); | |||
} | |||
private void preparePortfolio() { | |||
// tree of components | |||
Component portfolio = ViewsComponent.builder(VIEW, REF_1).setUuid("view-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(SUBVIEW, REF_2).setUuid("subview-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(PROJECT_VIEW, REF_3).setUuid("project-uuid") | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(portfolio); | |||
// components as persisted in db | |||
ComponentDto portfolioDto = insertComponent("view-key", "view-uuid"); | |||
ComponentDto subViewDto = insertComponent("subview-key", "subview-uuid"); | |||
ComponentDto projectDto = insertComponent("project-key", "project-uuid"); | |||
analysisMetadataHolder.setProject(Project.copyOf(portfolioDto)); | |||
} | |||
private void assertThatMeasureIsNotPersisted(String componentUuid, Metric metric) { | |||
assertThat(selectMeasure(componentUuid, metric)).isEmpty(); | |||
} | |||
private Optional<LiveMeasureDto> selectMeasure(String componentUuid, Metric metric) { | |||
return dbClient.liveMeasureDao().selectMeasure(db.getSession(), componentUuid, metric.getKey()); | |||
} | |||
private ComponentDto insertComponent(String key, String uuid) { | |||
ComponentDto componentDto = new ComponentDto() | |||
.setOrganizationUuid("org1") | |||
.setDbKey(key) | |||
.setUuid(uuid) | |||
.setUuidPath(uuid + ".") | |||
.setRootUuid(uuid) | |||
.setProjectUuid(uuid); | |||
dbClient.componentDao().insert(db.getSession(), componentDto); | |||
return componentDto; | |||
} | |||
@Override | |||
protected ComputationStep step() { | |||
return new PersistLiveMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder), treeRootHolder, measureRepository); | |||
} | |||
} |
@@ -19,8 +19,7 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.step; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -29,12 +28,10 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.Developer; | |||
import org.sonar.server.computation.task.projectanalysis.component.DumbDeveloper; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.ViewsComponent; | |||
@@ -44,12 +41,6 @@ import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION; | |||
import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION; | |||
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; | |||
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE; | |||
@@ -61,325 +52,180 @@ import static org.sonar.server.computation.task.projectanalysis.measure.Measure. | |||
public class PersistMeasuresStepTest extends BaseStepTest { | |||
private static final String STRING_METRIC_KEY = "string-metric-key"; | |||
private static final String DOUBLE_METRIC_KEY = "double-metric-key"; | |||
private static final String INT_METRIC_KEY = "int-metric-key"; | |||
private static final String LONG_METRIC_KEY = "long-metric-key"; | |||
private static final String OPTIMIZED_METRIC_KEY = "optimized-metric-key"; | |||
private static final Metric STRING_METRIC = new Metric.Builder(STRING_METRIC_KEY, "String metric", Metric.ValueType.STRING).create(); | |||
private static final Metric DOUBLE_METRIC = new Metric.Builder(DOUBLE_METRIC_KEY, "Double metric", Metric.ValueType.FLOAT).create(); | |||
private static final Metric INT_METRIC = new Metric.Builder(INT_METRIC_KEY, "int metric", Metric.ValueType.INT).create(); | |||
private static final Metric LONG_METRIC = new Metric.Builder(LONG_METRIC_KEY, "long metric", Metric.ValueType.WORK_DUR).create(); | |||
private static final int ROOT_REF = 1; | |||
private static final int INTERMEDIATE_1_REF = 2; | |||
private static final int INTERMEDIATE_2_REF = 3; | |||
private static final int LEAF_REF = 4; | |||
private static final Metric STRING_METRIC = new Metric.Builder("string-metric", "String metric", Metric.ValueType.STRING).create(); | |||
private static final Metric INT_METRIC = new Metric.Builder("int-metric", "int metric", Metric.ValueType.INT).create(); | |||
private static final String ANALYSIS_UUID = "a1"; | |||
private static final int REF_1 = 1; | |||
private static final int REF_2 = 2; | |||
private static final int REF_3 = 3; | |||
private static final int REF_4 = 4; | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||
@Rule | |||
public MetricRepositoryRule metricRepository = new MetricRepositoryRule(); | |||
@Rule | |||
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); | |||
@Rule | |||
public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.create(treeRootHolder); | |||
@Rule | |||
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule(); | |||
DbClient dbClient = dbTester.getDbClient(); | |||
RuleDto rule; | |||
ComponentDto rootDto; | |||
ComponentDto intermediate1Dto; | |||
ComponentDto intermediate2Dto; | |||
ComponentDto leafDto; | |||
PersistMeasuresStep underTest; | |||
private DbClient dbClient = db.getDbClient(); | |||
@Before | |||
public void setUp() { | |||
underTest = new PersistMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(dbIdsRepository, analysisMetadataHolder), treeRootHolder, measureRepository); | |||
analysisMetadataHolder.setUuid(ANALYSIS_UUID); | |||
} | |||
private void setupReportComponents() { | |||
Component project = ReportComponent.builder(PROJECT, ROOT_REF).setUuid("root-uuid") | |||
.addChildren( | |||
ReportComponent.builder(MODULE, INTERMEDIATE_1_REF).setUuid("intermediate1-uuid") | |||
.addChildren( | |||
ReportComponent.builder(DIRECTORY, INTERMEDIATE_2_REF).setUuid("intermediate2-uuid") | |||
.addChildren( | |||
ReportComponent.builder(FILE, LEAF_REF).setUuid("leaf-uuid") | |||
.build()) | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(project); | |||
setupDbIds(); | |||
} | |||
private void setupViewsComponents() { | |||
Component view = ViewsComponent.builder(VIEW, ROOT_REF).setUuid("root-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(SUBVIEW, INTERMEDIATE_1_REF).setUuid("intermediate1-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(SUBVIEW, INTERMEDIATE_2_REF).setUuid("intermediate2-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(PROJECT_VIEW, LEAF_REF).setUuid("leaf-uuid") | |||
.build()) | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(view); | |||
setupDbIds(); | |||
} | |||
private void setupDbIds() { | |||
rootDto = addComponent("root-key", "root-uuid"); | |||
intermediate1Dto = addComponent("intermediate1-key", "intermediate1-uuid"); | |||
intermediate2Dto = addComponent("intermediate2-key", "intermediate2-uuid"); | |||
leafDto = addComponent("leaf-key", "leaf-uuid"); | |||
setDbIds(ROOT_REF, rootDto.getId()); | |||
setDbIds(INTERMEDIATE_1_REF, intermediate1Dto.getId()); | |||
setDbIds(INTERMEDIATE_2_REF, intermediate2Dto.getId()); | |||
setDbIds(LEAF_REF, leafDto.getId()); | |||
} | |||
private void setDbIds(int componentRef, Long dbId) { | |||
dbIdsRepository.setComponentId(componentRef, dbId); | |||
MetricDto stringMetricDto = db.measures().insertMetric(m -> m.setKey(STRING_METRIC.getKey()).setValueType(Metric.ValueType.STRING.name())); | |||
MetricDto intMetricDto = db.measures().insertMetric(m -> m.setKey(INT_METRIC.getKey()).setValueType(Metric.ValueType.INT.name())); | |||
metricRepository.add(stringMetricDto.getId(), STRING_METRIC); | |||
metricRepository.add(intMetricDto.getId(), INT_METRIC); | |||
} | |||
@Test | |||
public void insert_measures_from_report() { | |||
setupReportComponents(); | |||
public void persist_measures_of_project_analysis() { | |||
prepareProject(); | |||
insertMeasures(); | |||
} | |||
// the computed measures | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value")); | |||
measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("module-value")); | |||
measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("dir-value")); | |||
measureRepository.addRawMeasure(REF_4, STRING_METRIC.getKey(), newMeasureBuilder().create("file-value")); | |||
@Test | |||
public void insert_measures_from_views() { | |||
setupViewsComponents(); | |||
insertMeasures(); | |||
} | |||
private void insertMeasures() { | |||
int stringMetricId = 1; | |||
int doubleMetricId = 2; | |||
int intMetricId = 3; | |||
int longMetricId = 4; | |||
metricRepository.add(stringMetricId, STRING_METRIC); | |||
metricRepository.add(doubleMetricId, DOUBLE_METRIC); | |||
metricRepository.add(intMetricId, INT_METRIC); | |||
metricRepository.add(longMetricId, LONG_METRIC); | |||
measureRepository.addRawMeasure(ROOT_REF, STRING_METRIC_KEY, newMeasureBuilder().create("measure-data")); | |||
measureRepository.addRawMeasure(INTERMEDIATE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(12)); | |||
measureRepository.addRawMeasure(INTERMEDIATE_2_REF, LONG_METRIC_KEY, newMeasureBuilder().create(9635L)); | |||
measureRepository.addRawMeasure(LEAF_REF, DOUBLE_METRIC_KEY, newMeasureBuilder().create(123.123d, 1)); | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(4); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
Map<String, Object> dto = dtos.get(0); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(rootDto.uuid()); | |||
assertThat(dto.get("metricId")).isEqualTo((long) stringMetricId); | |||
assertThat(dto.get("value")).isNull(); | |||
assertThat(dto.get("textValue")).isEqualTo("measure-data"); | |||
assertThat(dto.get("severity")).isNull(); | |||
dto = dtos.get(1); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(intermediate1Dto.uuid()); | |||
assertThat(dto.get("metricId")).isEqualTo((long) intMetricId); | |||
assertValue(dto, 12d); | |||
assertThat(dto.get("textValue")).isNull(); | |||
assertThat(dto.get("severity")).isNull(); | |||
dto = dtos.get(2); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(intermediate2Dto.uuid()); | |||
assertThat(dto.get("metricId")).isEqualTo((long) longMetricId); | |||
assertValue(dto, 9635d); | |||
assertThat(dto.get("textValue")).isNull(); | |||
assertThat(dto.get("severity")).isNull(); | |||
dto = dtos.get(3); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(leafDto.uuid()); | |||
assertThat(dto.get("metricId")).isEqualTo((long) doubleMetricId); | |||
assertValue(dto, 123.1d); | |||
assertThat(dto.get("textValue")).isNull(); | |||
assertThat(dto.get("severity")).isNull(); | |||
} | |||
execute(true); | |||
/** | |||
* Horrible trick to support oracle retuning number as BigDecimal and DbTester#select converting BigDecimal with no | |||
* scale to Long instead of Double when all other DBs will return a Double anyway. | |||
*/ | |||
private static void assertValue(Map<String, Object> dto, double expected) { | |||
Object actual = dto.get("value"); | |||
if (expected % 1 == 0d && actual instanceof Long) { | |||
assertThat(actual).isEqualTo((long) expected); | |||
} else { | |||
assertThat(actual).isEqualTo(expected); | |||
} | |||
// project, module and dir measures are persisted, but not file measures | |||
assertThat(db.countRowsOfTable("project_measures")).isEqualTo(3); | |||
assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getData()).isEqualTo("project-value"); | |||
assertThat(selectMeasure("module-uuid", STRING_METRIC).get().getData()).isEqualTo("module-value"); | |||
assertThat(selectMeasure("dir-uuid", STRING_METRIC).get().getData()).isEqualTo("dir-value"); | |||
assertThatMeasuresAreNotPersisted("file-uuid"); | |||
} | |||
@Test | |||
public void insert_measure_with_variations_from_report() { | |||
setupReportComponents(); | |||
insertMeasureWithVariations(); | |||
} | |||
@Test | |||
public void insert_measure_with_variations_from_views() { | |||
setupViewsComponents(); | |||
insertMeasureWithVariations(); | |||
} | |||
private void insertMeasureWithVariations() { | |||
metricRepository.add(1, DOUBLE_METRIC); | |||
public void persist_measures_of_project_analysis_excluding_directories() { | |||
prepareProject(); | |||
measureRepository.addRawMeasure(ROOT_REF, DOUBLE_METRIC_KEY, | |||
newMeasureBuilder() | |||
.setVariation(1.1d) | |||
.create(10d, 1)); | |||
// the computed measures | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value")); | |||
measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("module-value")); | |||
measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("dir-value")); | |||
measureRepository.addRawMeasure(REF_4, STRING_METRIC.getKey(), newMeasureBuilder().create("file-value")); | |||
underTest.execute(); | |||
execute(false); | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(1); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
Map<String, Object> dto = dtos.get(0); | |||
assertThat(dto.get("variation_value")).isEqualTo(1.1d); | |||
// project, module and dir measures are persisted, but not file measures | |||
assertThat(db.countRowsOfTable("project_measures")).isEqualTo(2); | |||
assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getData()).isEqualTo("project-value"); | |||
assertThat(selectMeasure("module-uuid", STRING_METRIC).get().getData()).isEqualTo("module-value"); | |||
assertThatMeasuresAreNotPersisted("dir-uuid"); | |||
assertThatMeasuresAreNotPersisted("file-uuid"); | |||
} | |||
@Test | |||
public void bestValue_measure_of_bestValueOptimized_metrics_are_not_persisted() { | |||
setupReportComponents(); | |||
metricRepository.add(1, new Metric.Builder(OPTIMIZED_METRIC_KEY, "Optimized metric", Metric.ValueType.BOOL).setOptimizedBestValue(true).setBestValue(1d).create()); | |||
public void measures_without_value_are_not_persisted() { | |||
prepareProject(); | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().createNoValue()); | |||
measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().createNoValue()); | |||
measureRepository.addRawMeasure(LEAF_REF, OPTIMIZED_METRIC_KEY, newMeasureBuilder().create(true)); | |||
execute(false); | |||
underTest.execute(); | |||
assertThat(selectSnapshots()).isEmpty(); | |||
assertThatMeasureIsNotPersisted("project-uuid", STRING_METRIC); | |||
assertThatMeasureIsNotPersisted("project-uuid", INT_METRIC); | |||
} | |||
@Test | |||
public void empty_values_are_not_persisted() { | |||
setupReportComponents(); | |||
metricRepository.add(1, STRING_METRIC); | |||
metricRepository.add(2, DOUBLE_METRIC); | |||
measureRepository.addRawMeasure(LEAF_REF, STRING_METRIC_KEY, newMeasureBuilder().createNoValue()); | |||
measureRepository.addRawMeasure(LEAF_REF, DOUBLE_METRIC_KEY, newMeasureBuilder().createNoValue()); | |||
public void measures_on_leak_period_are_persisted() { | |||
prepareProject(); | |||
measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().setVariation(42.0).createNoValue()); | |||
underTest.execute(); | |||
execute(false); | |||
assertThat(selectSnapshots()).isEmpty(); | |||
MeasureDto persistedMeasure = selectMeasure("project-uuid", INT_METRIC).get(); | |||
assertThat(persistedMeasure.getValue()).isNull(); | |||
assertThat(persistedMeasure.getVariation()).isEqualTo(42.0); | |||
} | |||
@Test | |||
public void do_not_insert_file_complexity_distribution_metric_on_files() { | |||
setupReportComponents(); | |||
public void persist_all_measures_of_portfolio_analysis() { | |||
preparePortfolio(); | |||
metricRepository.add(1, FILE_COMPLEXITY_DISTRIBUTION); | |||
// the computed measures | |||
measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("view-value")); | |||
measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("subview-value")); | |||
measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value")); | |||
measureRepository.addRawMeasure(ROOT_REF, FILE_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
measureRepository.addRawMeasure(LEAF_REF, FILE_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
execute(true); | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(1); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
Map<String, Object> dto = dtos.get(0); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(rootDto.uuid()); | |||
assertThat(dto.get("textValue")).isEqualTo("0=1;2=10"); | |||
assertThat(db.countRowsOfTable("project_measures")).isEqualTo(3); | |||
assertThat(selectMeasure("view-uuid", STRING_METRIC).get().getData()).isEqualTo("view-value"); | |||
assertThat(selectMeasure("subview-uuid", STRING_METRIC).get().getData()).isEqualTo("subview-value"); | |||
assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getData()).isEqualTo("project-value"); | |||
} | |||
@Test | |||
public void do_not_insert_function_complexity_distribution_metric_on_files() { | |||
setupReportComponents(); | |||
metricRepository.add(1, FUNCTION_COMPLEXITY_DISTRIBUTION); | |||
measureRepository.addRawMeasure(ROOT_REF, FUNCTION_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
measureRepository.addRawMeasure(LEAF_REF, FUNCTION_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(1); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
private void prepareProject() { | |||
// tree of components as defined by scanner report | |||
Component project = ReportComponent.builder(PROJECT, REF_1).setUuid("project-uuid") | |||
.addChildren( | |||
ReportComponent.builder(MODULE, REF_2).setUuid("module-uuid") | |||
.addChildren( | |||
ReportComponent.builder(DIRECTORY, REF_3).setUuid("dir-uuid") | |||
.addChildren( | |||
ReportComponent.builder(FILE, REF_4).setUuid("file-uuid") | |||
.build()) | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(project); | |||
Map<String, Object> dto = dtos.get(0); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(rootDto.uuid()); | |||
assertThat(dto.get("textValue")).isEqualTo("0=1;2=10"); | |||
// components as persisted in db | |||
ComponentDto projectDto = insertComponent("project-key", "project-uuid"); | |||
ComponentDto moduleDto = insertComponent("module-key", "module-uuid"); | |||
ComponentDto dirDto = insertComponent("dir-key", "dir-uuid"); | |||
ComponentDto fileDto = insertComponent("file-key", "file-uuid"); | |||
db.components().insertSnapshot(projectDto, s -> s.setUuid(ANALYSIS_UUID)); | |||
} | |||
@Test | |||
public void do_not_insert_class_complexity_distribution_metric_on_files() { | |||
setupReportComponents(); | |||
metricRepository.add(1, CLASS_COMPLEXITY_DISTRIBUTION); | |||
measureRepository.addRawMeasure(ROOT_REF, CLASS_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
measureRepository.addRawMeasure(LEAF_REF, CLASS_COMPLEXITY_DISTRIBUTION_KEY, newMeasureBuilder().create("0=1;2=10")); | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(1); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
private void preparePortfolio() { | |||
// tree of components | |||
Component portfolio = ViewsComponent.builder(VIEW, REF_1).setUuid("view-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(SUBVIEW, REF_2).setUuid("subview-uuid") | |||
.addChildren( | |||
ViewsComponent.builder(PROJECT_VIEW, REF_3).setUuid("project-uuid") | |||
.build()) | |||
.build()) | |||
.build(); | |||
treeRootHolder.setRoot(portfolio); | |||
Map<String, Object> dto = dtos.get(0); | |||
assertThat(dto.get("analysisUuid")).isEqualTo(ANALYSIS_UUID); | |||
assertThat(dto.get("componentUuid")).isEqualTo(rootDto.uuid()); | |||
assertThat(dto.get("textValue")).isEqualTo("0=1;2=10"); | |||
// components as persisted in db | |||
ComponentDto viewDto = insertComponent("view-key", "view-uuid"); | |||
ComponentDto subViewDto = insertComponent("subview-key", "subview-uuid"); | |||
ComponentDto projectDto = insertComponent("project-key", "project-uuid"); | |||
db.components().insertSnapshot(viewDto, s -> s.setUuid(ANALYSIS_UUID)); | |||
} | |||
@Test | |||
public void insert_developer_measure_from_report() { | |||
setupReportComponents(); | |||
metricRepository.add(1, INT_METRIC); | |||
Developer developer = new DumbDeveloper("DEV1"); | |||
dbIdsRepository.setDeveloperId(developer, 10); | |||
measureRepository.addRawMeasure(ROOT_REF, INT_METRIC_KEY, newMeasureBuilder().forDeveloper(developer).create(1)); | |||
private void assertThatMeasureIsNotPersisted(String componentUuid, Metric metric) { | |||
assertThat(selectMeasure(componentUuid, metric)).isEmpty(); | |||
} | |||
underTest.execute(); | |||
private void assertThatMeasuresAreNotPersisted(String componentUuid) { | |||
assertThatMeasureIsNotPersisted(componentUuid, STRING_METRIC); | |||
assertThatMeasureIsNotPersisted(componentUuid, INT_METRIC); | |||
} | |||
assertThat(dbTester.countRowsOfTable("project_measures")).isEqualTo(1); | |||
List<Map<String, Object>> dtos = selectSnapshots(); | |||
Map<String, Object> dto = dtos.get(0); | |||
private void execute(boolean persistDirectories) { | |||
new PersistMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder), treeRootHolder, measureRepository, persistDirectories) | |||
.execute(); | |||
} | |||
assertValue(dto, 1d); | |||
assertThat(dto.get("developerId")).isEqualTo(10L); | |||
private Optional<MeasureDto> selectMeasure(String componentUuid, Metric metric) { | |||
return dbClient.measureDao().selectMeasure(db.getSession(), ANALYSIS_UUID, componentUuid, metric.getKey()); | |||
} | |||
private ComponentDto addComponent(String key, String uuid) { | |||
private ComponentDto insertComponent(String key, String uuid) { | |||
ComponentDto componentDto = new ComponentDto() | |||
.setOrganizationUuid("org1") | |||
.setDbKey(key) | |||
@@ -387,23 +233,12 @@ public class PersistMeasuresStepTest extends BaseStepTest { | |||
.setUuidPath(uuid + ".") | |||
.setRootUuid(uuid) | |||
.setProjectUuid(uuid); | |||
dbClient.componentDao().insert(dbTester.getSession(), componentDto); | |||
dbClient.componentDao().insert(db.getSession(), componentDto); | |||
return componentDto; | |||
} | |||
private List<Map<String, Object>> selectSnapshots() { | |||
return dbTester | |||
.select( | |||
"SELECT analysis_uuid as \"analysisUuid\", component_uuid as \"componentUuid\", metric_id as \"metricId\", person_id as \"developerId\", " | |||
+ | |||
"value as \"value\", text_value as \"textValue\", " + | |||
"variation_value_1 as \"variation_value\"" + | |||
"FROM project_measures " + | |||
"ORDER by id asc"); | |||
} | |||
@Override | |||
protected ComputationStep step() { | |||
return underTest; | |||
return new PersistMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder), treeRootHolder, measureRepository, true); | |||
} | |||
} |
@@ -29,7 +29,6 @@ import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.component.TestComponentFinder; | |||
@@ -113,9 +112,8 @@ public class ShowActionTest { | |||
ComponentDto project = db.components().insertMainBranch(); | |||
userSessionRule.addProjectPermission(UserRole.CODEVIEWER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(branch)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(branch)); | |||
db.measures().insertMeasure(file, analysis, dataMetric, m -> m.setData(format("<duplications>\n" + | |||
db.measures().insertLiveMeasure(file, dataMetric, m -> m.setData(format("<duplications>\n" + | |||
" <g>\n" + | |||
" <b s=\"31\" l=\"5\" r=\"%s\"/>\n" + | |||
" <b s=\"20\" l=\"5\" r=\"%s\"/>\n" + | |||
@@ -224,14 +222,13 @@ public class ShowActionTest { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
userSessionRule.addProjectPermission(UserRole.CODEVIEWER, project); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project).setDbKey("foo.js")); | |||
SnapshotDto snapshot = db.components().insertSnapshot(newAnalysis(project)); | |||
String xml = "<duplications>\n" + | |||
" <g>\n" + | |||
" <b s=\"31\" l=\"5\" r=\"foo.js\"/>\n" + | |||
" <b s=\"20\" l=\"5\" r=\"foo.js\"/>\n" + | |||
" </g>\n" + | |||
"</duplications>\n"; | |||
db.measures().insertMeasure(file, snapshot, dataMetric, m -> m.setData(xml)); | |||
db.measures().insertLiveMeasure(file, dataMetric, m -> m.setData(xml)); | |||
TestRequest request = requestFactory.apply(file); | |||
TestResponse result = request.execute(); |
@@ -29,7 +29,7 @@ import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.component.TestComponentFinder; | |||
@@ -52,7 +52,7 @@ import static org.sonar.api.utils.DateUtils.parseDateTime; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.INT; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.DEPRECATED_PARAM_COMPONENT_ID; | |||
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS; | |||
@@ -92,10 +92,10 @@ public class ComponentActionTest { | |||
@Test | |||
public void provided_project() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
insertNclocMetric(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
ComponentWsResponse response = newRequest(project.getKey(), "ncloc"); | |||
ComponentWsResponse response = newRequest(project.getKey(), metric.getKey()); | |||
assertThat(response.getMetrics().getMetricsCount()).isEqualTo(1); | |||
assertThat(response.getPeriods().getPeriodsCount()).isEqualTo(0); | |||
@@ -105,13 +105,13 @@ public class ComponentActionTest { | |||
@Test | |||
public void without_additional_fields() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
db.components().insertSnapshot(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
String response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.execute().getInput(); | |||
assertThat(response) | |||
@@ -122,12 +122,12 @@ public class ComponentActionTest { | |||
@Test | |||
public void branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); | |||
SnapshotDto analysis = db.components().insertSnapshot(branch); | |||
ComponentDto file = db.components().insertComponent(newFileDto(branch)); | |||
MetricDto complexity = insertComplexityMetric(); | |||
MeasureDto measure = db.measures().insertMeasure(file, analysis, complexity, m -> m.setValue(12.0d).setVariation(2.0d)); | |||
MetricDto complexity = db.measures().insertMetric(m1 -> m1.setKey("complexity").setValueType(INT.name())); | |||
LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d).setVariation(2.0d)); | |||
ComponentWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, file.getKey()) | |||
@@ -149,9 +149,9 @@ public class ComponentActionTest { | |||
ComponentDto view = db.components().insertView(); | |||
db.components().insertSnapshot(view); | |||
ComponentDto projectCopy = db.components().insertComponent(newProjectCopy("project-uuid-copy", project, view)); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
ComponentWsResponse response = newRequest(projectCopy.getKey(), "ncloc"); | |||
ComponentWsResponse response = newRequest(projectCopy.getKey(), metric.getKey()); | |||
assertThat(response.getComponent().getRefId()).isEqualTo(project.uuid()); | |||
assertThat(response.getComponent().getRefKey()).isEqualTo(project.getKey()); | |||
@@ -160,11 +160,11 @@ public class ComponentActionTest { | |||
@Test | |||
public void return_deprecated_id_in_the_response() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
db.components().insertSnapshot(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
ComponentWsResponse response = newRequest(project.getKey(), "ncloc"); | |||
ComponentWsResponse response = newRequest(project.getKey(), metric.getKey()); | |||
assertThat(response.getComponent().getId()).isEqualTo(project.uuid()); | |||
} | |||
@@ -172,13 +172,13 @@ public class ComponentActionTest { | |||
@Test | |||
public void use_deprecated_component_id_parameter() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
userSession.addProjectPermission(USER, project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
ComponentWsResponse response = ws.newRequest() | |||
.setParam("componentId", project.uuid()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.executeProtobuf(ComponentWsResponse.class); | |||
assertThat(response.getComponent().getKey()).isEqualTo(project.getDbKey()); | |||
@@ -187,13 +187,13 @@ public class ComponentActionTest { | |||
@Test | |||
public void use_deprecated_component_key_parameter() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
userSession.addProjectPermission(USER, project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
ComponentWsResponse response = ws.newRequest() | |||
.setParam("componentKey", project.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.executeProtobuf(ComponentWsResponse.class); | |||
assertThat(response.getComponent().getKey()).isEqualTo(project.getDbKey()); | |||
@@ -202,12 +202,11 @@ public class ComponentActionTest { | |||
@Test | |||
public void metric_without_a_domain() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
SnapshotDto analysis = db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(project)); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metricWithoutDomain = db.measures().insertMetric(m -> m | |||
.setValueType(Measure.ValueType.INT.name()) | |||
.setDomain(null)); | |||
db.measures().insertMeasure(project, analysis, metricWithoutDomain); | |||
db.measures().insertLiveMeasure(project, metricWithoutDomain); | |||
ComponentWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -215,36 +214,58 @@ public class ComponentActionTest { | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics") | |||
.executeProtobuf(ComponentWsResponse.class); | |||
assertThat(response.getComponent().getMeasures(0).getMetric()).isEqualTo(metricWithoutDomain.getKey()); | |||
assertThat(response.getComponent().getMeasuresList()).extracting(Measures.Measure::getMetric).containsExactly(metricWithoutDomain.getKey()); | |||
Common.Metric responseMetric = response.getMetrics().getMetrics(0); | |||
assertThat(responseMetric.getKey()).isEqualTo(metricWithoutDomain.getKey()); | |||
assertThat(responseMetric.hasDomain()).isFalse(); | |||
} | |||
@Test | |||
public void use_best_values() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(m -> m | |||
.setValueType(Measure.ValueType.INT.name()) | |||
.setBestValue(7.0d) | |||
.setOptimizedBestValue(true) | |||
.setDomain(null)); | |||
ComponentWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, file.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics") | |||
.executeProtobuf(ComponentWsResponse.class); | |||
assertThat(response.getComponent().getMeasuresList()) | |||
.extracting(Measures.Measure::getMetric, Measures.Measure::getValue) | |||
.containsExactly(tuple(metric.getKey(), "7")); | |||
} | |||
@Test | |||
public void fail_when_developer_is_not_found() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
db.components().insertSnapshot(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("Component id 'unknown-developer-id' not found"); | |||
expectedException.expectMessage("The Developer Cockpit feature has been dropped. The specified developer cannot be found."); | |||
ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.setParam(PARAM_DEVELOPER_ID, "unknown-developer-id").executeProtobuf(ComponentWsResponse.class); | |||
} | |||
@Test | |||
public void fail_when_a_metric_is_not_found() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
db.components().insertSnapshot(project); | |||
insertNclocMetric(); | |||
insertComplexityMetric(); | |||
db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.name())); | |||
db.measures().insertMetric(m -> m.setKey("complexity").setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("The following metric keys are not found: unknown-metric, another-unknown-metric"); | |||
@@ -255,7 +276,7 @@ public class ComponentActionTest { | |||
@Test | |||
public void fail_when_empty_metric_keys_parameter() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
db.components().insertSnapshot(project); | |||
expectedException.expect(BadRequestException.class); | |||
@@ -269,39 +290,39 @@ public class ComponentActionTest { | |||
userSession.logIn(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.components().insertSnapshot(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(ForbiddenException.class); | |||
newRequest(project.getKey(), "ncloc"); | |||
newRequest(project.getKey(), metric.getKey()); | |||
} | |||
@Test | |||
public void fail_when_component_does_not_exist() { | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("Component key 'project-key' not found"); | |||
ws.newRequest() | |||
.setParam(PARAM_COMPONENT, "project-key") | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_when_component_is_removed() { | |||
ComponentDto project = db.components().insertPrivateProject(p -> p.setEnabled(false)); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
userSession.addProjectPermission(USER, project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(String.format("Component key '%s' not found", project.getKey())); | |||
ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.execute(); | |||
} | |||
@@ -345,14 +366,14 @@ public class ComponentActionTest { | |||
ComponentDto project = db.components().insertMainBranch(organization); | |||
userSession.logIn().addProjectPermission(UserRole.USER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); | |||
ws.newRequest() | |||
.setParam(PARAM_COMPONENT, branch.getDbKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.execute(); | |||
} | |||
@@ -362,21 +383,21 @@ public class ComponentActionTest { | |||
ComponentDto project = db.components().insertMainBranch(organization); | |||
userSession.logIn().addProjectPermission(UserRole.USER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
insertNclocMetric(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(format("Component id '%s' not found", branch.uuid())); | |||
ws.newRequest() | |||
.setParam(DEPRECATED_PARAM_COMPONENT_ID, branch.uuid()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc") | |||
.setParam(PARAM_METRIC_KEYS, metric.getKey()) | |||
.execute(); | |||
} | |||
@Test | |||
public void json_example() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
logAsUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
SnapshotDto analysis = db.components().insertSnapshot(project, | |||
s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime()) | |||
.setPeriodMode("previous_version") | |||
@@ -386,66 +407,36 @@ public class ComponentActionTest { | |||
.setName("ElementImpl.java") | |||
.setLanguage("java") | |||
.setPath("src/main/java/com/sonarsource/markdown/impl/ElementImpl.java")); | |||
MetricDto complexity = insertComplexityMetric(); | |||
db.measures().insertMeasure(file, analysis, complexity, | |||
m -> m.setValue(12.0d) | |||
.setVariation(2.0d) | |||
.setData(null)); | |||
MetricDto ncloc = insertNclocMetric(); | |||
db.measures().insertMeasure(file, analysis, ncloc, | |||
m -> m.setValue(114.0d) | |||
.setVariation(3.0d) | |||
.setData(null)); | |||
MetricDto newViolations = insertNewViolationMetric(); | |||
db.measures().insertMeasure(file, analysis, newViolations, | |||
m -> m.setVariation(25.0d) | |||
.setValue(null) | |||
.setData(null)); | |||
String response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, file.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations") | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods") | |||
.execute() | |||
.getInput(); | |||
assertJson(response).isSimilarTo(getClass().getResource("component-example.json")); | |||
} | |||
private ComponentWsResponse newRequest(String componentKey, String metricKeys) { | |||
return ws.newRequest() | |||
.setParam(PARAM_COMPONENT, componentKey) | |||
.setParam(PARAM_METRIC_KEYS, metricKeys) | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods") | |||
.executeProtobuf(ComponentWsResponse.class); | |||
} | |||
private MetricDto insertNclocMetric() { | |||
return db.measures().insertMetric(m -> m.setKey("ncloc") | |||
.setShortName("Lines of code") | |||
.setDescription("Non Commenting Lines of Code") | |||
.setDomain("Size") | |||
MetricDto complexity = db.measures().insertMetric(m -> m.setKey("complexity") | |||
.setShortName("Complexity") | |||
.setDescription("Cyclomatic complexity") | |||
.setDomain("Complexity") | |||
.setValueType("INT") | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
} | |||
db.measures().insertLiveMeasure(file, complexity, | |||
m -> m.setValue(12.0d) | |||
.setVariation(2.0d) | |||
.setData((String) null)); | |||
private MetricDto insertComplexityMetric() { | |||
return db.measures().insertMetric(m -> m.setKey("complexity") | |||
.setShortName("Complexity") | |||
.setDescription("Cyclomatic complexity") | |||
.setDomain("Complexity") | |||
MetricDto ncloc = db.measures().insertMetric(m1 -> m1.setKey("ncloc") | |||
.setShortName("Lines of code") | |||
.setDescription("Non Commenting Lines of Code") | |||
.setDomain("Size") | |||
.setValueType("INT") | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
} | |||
db.measures().insertLiveMeasure(file, ncloc, | |||
m -> m.setValue(114.0d) | |||
.setVariation(3.0d) | |||
.setData((String) null)); | |||
private MetricDto insertNewViolationMetric() { | |||
return db.measures().insertMetric(m -> m.setKey("new_violations") | |||
MetricDto newViolations = db.measures().insertMetric(m -> m.setKey("new_violations") | |||
.setShortName("New issues") | |||
.setDescription("New Issues") | |||
.setDomain("Issues") | |||
@@ -454,10 +445,26 @@ public class ComponentActionTest { | |||
.setQualitative(true) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
} | |||
db.measures().insertLiveMeasure(file, newViolations, | |||
m -> m.setVariation(25.0d) | |||
.setValue(null) | |||
.setData((String) null)); | |||
private void logAsUser(ComponentDto project) { | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
String response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, file.getKey()) | |||
.setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations") | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods") | |||
.execute() | |||
.getInput(); | |||
assertJson(response).isSimilarTo(getClass().getResource("component-example.json")); | |||
} | |||
private ComponentWsResponse newRequest(String componentKey, String metricKeys) { | |||
return ws.newRequest() | |||
.setParam(PARAM_COMPONENT, componentKey) | |||
.setParam(PARAM_METRIC_KEYS, metricKeys) | |||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics,periods") | |||
.executeProtobuf(ComponentWsResponse.class); | |||
} | |||
} |
@@ -37,7 +37,7 @@ import org.sonar.db.component.ComponentDbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ResourceTypesRule; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
@@ -73,7 +73,6 @@ import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.db.measure.MeasureTesting.newMeasureDto; | |||
import static org.sonar.server.measure.ws.ComponentTreeAction.LEAVES_STRATEGY; | |||
import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_PERIOD_SORT; | |||
import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_SORT; | |||
@@ -142,33 +141,19 @@ public class ComponentTreeActionTest { | |||
.setQualifier(DIRECTORY)); | |||
MetricDto complexity = insertComplexityMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(complexity, file1, analysis) | |||
.setValue(12.0d), | |||
newMeasureDto(complexity, dir, analysis) | |||
.setValue(35.0d) | |||
.setVariation(0.0d), | |||
newMeasureDto(complexity, project, analysis) | |||
.setValue(42.0d)); | |||
db.measures().insertLiveMeasure(file1, complexity, m -> m.setValue(12.0d)); | |||
db.measures().insertLiveMeasure(dir, complexity, m -> m.setValue(35.0d).setVariation(0.0d)); | |||
db.measures().insertLiveMeasure(project, complexity, m -> m.setValue(42.0d)); | |||
MetricDto ncloc = insertNclocMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file1, analysis) | |||
.setValue(114.0d), | |||
newMeasureDto(ncloc, dir, analysis) | |||
.setValue(217.0d) | |||
.setVariation(0.0d), | |||
newMeasureDto(ncloc, project, analysis) | |||
.setValue(1984.0d)); | |||
db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(114.0d)); | |||
db.measures().insertLiveMeasure(dir, ncloc, m -> m.setValue(217.0d).setVariation(0.0d)); | |||
db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(1984.0d)); | |||
MetricDto newViolations = insertNewViolationsMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(newViolations, file1, analysis) | |||
.setVariation(25.0d), | |||
newMeasureDto(newViolations, dir, analysis) | |||
.setVariation(25.0d), | |||
newMeasureDto(newViolations, project, analysis) | |||
.setVariation(255.0d)); | |||
db.measures().insertLiveMeasure(file1, newViolations, m -> m.setVariation(25.0d)); | |||
db.measures().insertLiveMeasure(dir, newViolations, m -> m.setVariation(25.0d)); | |||
db.measures().insertLiveMeasure(project, newViolations, m -> m.setVariation(255.0d)); | |||
db.commit(); | |||
@@ -206,17 +191,16 @@ public class ComponentTreeActionTest { | |||
.setPeriodMode("last_version") | |||
.setPeriodDate(System.currentTimeMillis())); | |||
userSession.anonymous().addProjectPermission(UserRole.USER, project); | |||
ComponentDto directoryDto = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directoryDto); | |||
ComponentDto file = newFileDto(directoryDto, null, "file-uuid").setName("file-1"); | |||
ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directory); | |||
ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1"); | |||
componentDb.insertComponent(file); | |||
MetricDto ncloc = insertNclocMetric(); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file, projectSnapshot).setValue(5.0d).setVariation(4.0d), | |||
newMeasureDto(coverage, file, projectSnapshot).setValue(15.5d), | |||
newMeasureDto(coverage, directoryDto, projectSnapshot).setValue(15.0d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(5.0d).setVariation(4.0d)); | |||
db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d)); | |||
db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(15.5d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -237,9 +221,9 @@ public class ComponentTreeActionTest { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
SnapshotDto projectSnapshot = db.components().insertSnapshot(project); | |||
userSession.anonymous().addProjectPermission(UserRole.USER, project); | |||
ComponentDto directoryDto = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directoryDto); | |||
ComponentDto file = newFileDto(directoryDto, null, "file-uuid").setName("file-1"); | |||
ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directory); | |||
ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1"); | |||
componentDb.insertComponent(file); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto() | |||
@@ -253,10 +237,9 @@ public class ComponentTreeActionTest { | |||
.setOptimizedBestValue(true) | |||
.setBestValue(1984.0d) | |||
.setValueType(INT.name())); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(coverage, file, projectSnapshot).setValue(15.5d), | |||
newMeasureDto(coverage, directoryDto, projectSnapshot).setValue(42.0d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d)); | |||
db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(42.0d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -284,17 +267,17 @@ public class ComponentTreeActionTest { | |||
.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime()) | |||
.setPeriodMode("previous_version") | |||
.setPeriodParam("1.0-SNAPSHOT")); | |||
ComponentDto directoryDto = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directoryDto); | |||
ComponentDto file = newFileDto(directoryDto, null, "file-uuid").setName("file-1"); | |||
ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1"); | |||
componentDb.insertComponent(directory); | |||
ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1"); | |||
componentDb.insertComponent(file); | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto() | |||
.setKey(NEW_SECURITY_RATING_KEY) | |||
.setOptimizedBestValue(true) | |||
.setBestValue(1d) | |||
.setValueType(RATING.name())); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(metric, directoryDto, projectSnapshot).setVariation(2d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(directory, metric, m -> m.setVariation(2d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -322,17 +305,16 @@ public class ComponentTreeActionTest { | |||
ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-1")); | |||
ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-1")); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(coverage, file1, projectSnapshot).setValue(1.0d), | |||
newMeasureDto(coverage, file2, projectSnapshot).setValue(2.0d), | |||
newMeasureDto(coverage, file3, projectSnapshot).setValue(3.0d), | |||
newMeasureDto(coverage, file4, projectSnapshot).setValue(4.0d), | |||
newMeasureDto(coverage, file5, projectSnapshot).setValue(5.0d), | |||
newMeasureDto(coverage, file6, projectSnapshot).setValue(6.0d), | |||
newMeasureDto(coverage, file7, projectSnapshot).setValue(7.0d), | |||
newMeasureDto(coverage, file8, projectSnapshot).setValue(8.0d), | |||
newMeasureDto(coverage, file9, projectSnapshot).setValue(9.0d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(file1, coverage, m -> m.setValue(1.0d)); | |||
db.measures().insertLiveMeasure(file2, coverage, m -> m.setValue(2.0d)); | |||
db.measures().insertLiveMeasure(file3, coverage, m -> m.setValue(3.0d)); | |||
db.measures().insertLiveMeasure(file4, coverage, m -> m.setValue(4.0d)); | |||
db.measures().insertLiveMeasure(file5, coverage, m -> m.setValue(5.0d)); | |||
db.measures().insertLiveMeasure(file6, coverage, m -> m.setValue(6.0d)); | |||
db.measures().insertLiveMeasure(file7, coverage, m -> m.setValue(7.0d)); | |||
db.measures().insertLiveMeasure(file8, coverage, m -> m.setValue(8.0d)); | |||
db.measures().insertLiveMeasure(file9, coverage, m -> m.setValue(9.0d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -361,11 +343,10 @@ public class ComponentTreeActionTest { | |||
ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2")); | |||
MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1); | |||
dbClient.metricDao().insert(dbSession, ncloc); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file1, projectSnapshot).setValue(1.0d), | |||
newMeasureDto(ncloc, file2, projectSnapshot).setValue(2.0d), | |||
newMeasureDto(ncloc, file3, projectSnapshot).setValue(3.0d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(1.0d)); | |||
db.measures().insertLiveMeasure(file2, ncloc, m -> m.setValue(2.0d)); | |||
db.measures().insertLiveMeasure(file3, ncloc, m -> m.setValue(3.0d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -392,12 +373,11 @@ public class ComponentTreeActionTest { | |||
componentDb.insertComponent(file4); | |||
MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1); | |||
dbClient.metricDao().insert(dbSession, ncloc); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file1, projectSnapshot).setValue(1.0d), | |||
newMeasureDto(ncloc, file2, projectSnapshot).setValue(2.0d), | |||
newMeasureDto(ncloc, file3, projectSnapshot).setValue(3.0d), | |||
// measure on period 1 | |||
newMeasureDto(ncloc, file4, projectSnapshot).setVariation(4.0d)); | |||
db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(1.0d).setVariation(null)); | |||
db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(2.0d).setVariation(null)); | |||
db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(3.0d).setVariation(null)); | |||
// measure on period 1 | |||
db.measures().insertLiveMeasure(file4, ncloc, m -> m.setData((String) null).setValue(null).setVariation(4.0d)); | |||
db.commit(); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
@@ -423,11 +403,10 @@ public class ComponentTreeActionTest { | |||
ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2")); | |||
MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1); | |||
dbClient.metricDao().insert(dbSession, ncloc); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file1, projectSnapshot).setVariation(1.0d), | |||
newMeasureDto(ncloc, file2, projectSnapshot).setVariation(2.0d), | |||
newMeasureDto(ncloc, file3, projectSnapshot).setVariation(3.0d)); | |||
db.commit(); | |||
db.measures().insertLiveMeasure(file1, ncloc, m -> m.setVariation(1.0d)); | |||
db.measures().insertLiveMeasure(file2, ncloc, m -> m.setVariation(2.0d)); | |||
db.measures().insertLiveMeasure(file3, ncloc, m -> m.setVariation(3.0d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -450,12 +429,11 @@ public class ComponentTreeActionTest { | |||
ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1")); | |||
MetricDto ncloc = newMetricDto().setKey("new_ncloc").setValueType(INT.name()).setDirection(1); | |||
dbClient.metricDao().insert(dbSession, ncloc); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, file1, projectSnapshot).setVariation(1.0d), | |||
newMeasureDto(ncloc, file2, projectSnapshot).setVariation(2.0d), | |||
newMeasureDto(ncloc, file3, projectSnapshot).setVariation(3.0d), | |||
// file 4 measure is on absolute value | |||
newMeasureDto(ncloc, file4, projectSnapshot).setValue(4.0d)); | |||
db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(null).setVariation(1.0d)); | |||
db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(null).setVariation(2.0d)); | |||
db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(null).setVariation(3.0d)); | |||
// file 4 measure is on absolute value | |||
db.measures().insertLiveMeasure(file4, ncloc, m -> m.setData((String) null).setValue(4.0d).setVariation(null)); | |||
db.commit(); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
@@ -492,12 +470,13 @@ public class ComponentTreeActionTest { | |||
@Test | |||
public void branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); | |||
SnapshotDto analysis = db.components().insertSnapshot(branch); | |||
ComponentDto file = db.components().insertComponent(newFileDto(branch)); | |||
MetricDto complexity = insertComplexityMetric(); | |||
MeasureDto measure = db.measures().insertMeasure(file, analysis, complexity, m -> m.setValue(12.0d)); | |||
MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name())); | |||
LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, file.getKey()) | |||
@@ -518,7 +497,7 @@ public class ComponentTreeActionTest { | |||
SnapshotDto analysis = db.components().insertSnapshot(project); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(project)); | |||
MetricDto ncloc = insertNclocMetric(); | |||
db.measures().insertMeasure(file, analysis, ncloc, m -> m.setValue(2d)); | |||
db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(2d)); | |||
ComponentTreeWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -565,7 +544,7 @@ public class ComponentTreeActionTest { | |||
MetricDto metricWithoutDomain = db.measures().insertMetric(m -> m | |||
.setValueType(Metric.ValueType.INT.name()) | |||
.setDomain(null)); | |||
db.measures().insertMeasure(project, analysis, metricWithoutDomain); | |||
db.measures().insertLiveMeasure(project, metricWithoutDomain); | |||
ComponentTreeWsResponse result = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, project.getKey()) | |||
@@ -582,11 +561,11 @@ public class ComponentTreeActionTest { | |||
@Test | |||
public void reference_component() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto view = db.components().insertView(); | |||
ComponentDto view = db.components().insertPrivatePortfolio(db.getDefaultOrganization()); | |||
SnapshotDto viewAnalysis = db.components().insertSnapshot(view); | |||
ComponentDto projectCopy = db.components().insertComponent(newProjectCopy(project, view)); | |||
MetricDto ncloc = insertNclocMetric(); | |||
db.measures().insertMeasure(projectCopy, viewAnalysis, ncloc, m -> m.setValue(5d)); | |||
db.measures().insertLiveMeasure(projectCopy, ncloc, m -> m.setValue(5d)); | |||
ComponentTreeWsResponse result = ws.newRequest() | |||
.setParam(PARAM_COMPONENT, view.getKey()) | |||
@@ -903,7 +882,7 @@ public class ComponentTreeActionTest { | |||
.setShortName("Lines of code") | |||
.setDescription("Non Commenting Lines of Code") | |||
.setDomain("Size") | |||
.setValueType("INT") | |||
.setValueType(INT.name()) | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
@@ -918,7 +897,7 @@ public class ComponentTreeActionTest { | |||
.setShortName("Complexity") | |||
.setDescription("Cyclomatic complexity") | |||
.setDomain("Complexity") | |||
.setValueType("INT") | |||
.setValueType(INT.name()) | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) |
@@ -30,7 +30,7 @@ import org.sonar.api.measures.Metric.ValueType; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.measure.MeasureDto; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -78,9 +78,9 @@ public class ComponentTreeSortTest { | |||
// same number than path field | |||
double currentValue = 9; | |||
for (ComponentDto component : components) { | |||
measuresByComponentUuidAndMetric.put(component.uuid(), violationsMetric, createFromMeasureDto(new MeasureDto().setValue(currentValue) | |||
measuresByComponentUuidAndMetric.put(component.uuid(), violationsMetric, createFromMeasureDto(new LiveMeasureDto().setValue(currentValue) | |||
.setVariation(-currentValue))); | |||
measuresByComponentUuidAndMetric.put(component.uuid(), sqaleIndexMetric, createFromMeasureDto(new MeasureDto().setData(String.valueOf(currentValue)))); | |||
measuresByComponentUuidAndMetric.put(component.uuid(), sqaleIndexMetric, createFromMeasureDto(new LiveMeasureDto().setData(String.valueOf(currentValue)))); | |||
currentValue--; | |||
} | |||
} | |||
@@ -167,7 +167,7 @@ public class ComponentTreeSortTest { | |||
for (int i = 0; i < components.size(); i++) { | |||
ComponentDto component = components.get(i); | |||
String alertStatus = statuses.get(i % 3); | |||
measuresByComponentUuidAndMetric.put(component.uuid(), metrics.get(0), createFromMeasureDto(new MeasureDto().setData(alertStatus))); | |||
measuresByComponentUuidAndMetric.put(component.uuid(), metrics.get(0), createFromMeasureDto(new LiveMeasureDto().setData(alertStatus))); | |||
} | |||
ComponentTreeRequest wsRequest = newRequest(newArrayList(METRIC_SORT, NAME_SORT), true, CoreMetrics.ALERT_STATUS_KEY); | |||
@@ -20,29 +20,21 @@ | |||
package org.sonar.server.measure.ws; | |||
import com.google.common.base.Joiner; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import javax.annotation.Nullable; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
@@ -57,16 +49,12 @@ import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.sonar.api.utils.DateUtils.parseDateTime; | |||
import static org.sonar.db.component.ComponentTesting.newApplication; | |||
import static org.sonar.api.measures.Metric.ValueType.FLOAT; | |||
import static org.sonar.api.measures.Metric.ValueType.INT; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newSubView; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.db.measure.MeasureTesting.newMeasureDto; | |||
import static org.sonar.db.metric.MetricTesting.newMetricDto; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_KEYS; | |||
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_PROJECT_KEYS; | |||
@@ -77,25 +65,41 @@ public class SearchActionTest { | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
public UserSessionRule userSession = UserSessionRule.standalone().logIn(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private DbClient dbClient = db.getDbClient(); | |||
private DbSession dbSession = db.getSession(); | |||
private UserDto user; | |||
private WsActionTester ws = new WsActionTester(new SearchAction(userSession, dbClient)); | |||
@Before | |||
public void setUp() throws Exception { | |||
user = db.users().insertUser("john"); | |||
userSession.logIn(user); | |||
} | |||
private WsActionTester ws = new WsActionTester(new SearchAction(userSession, db.getDbClient())); | |||
@Test | |||
public void json_example() { | |||
List<String> projectKeys = insertJsonExampleData(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project1 = db.components().insertPrivateProject(organization, p -> p.setDbKey("MY_PROJECT_1").setName("Project 1")); | |||
ComponentDto project2 = db.components().insertPrivateProject(organization, p -> p.setDbKey("MY_PROJECT_2").setName("Project 2")); | |||
ComponentDto project3 = db.components().insertPrivateProject(organization, p -> p.setDbKey("MY_PROJECT_3").setName("Project 3")); | |||
userSession.addProjectPermission(UserRole.USER, project1); | |||
userSession.addProjectPermission(UserRole.USER, project2); | |||
userSession.addProjectPermission(UserRole.USER, project3); | |||
MetricDto complexity = db.measures().insertMetric(m -> m.setKey("complexity").setValueType(INT.name())); | |||
db.measures().insertLiveMeasure(project1, complexity, m -> m.setValue(12.0d)); | |||
db.measures().insertLiveMeasure(project2, complexity, m -> m.setValue(35.0d).setVariation(0.0d)); | |||
db.measures().insertLiveMeasure(project3, complexity, m -> m.setValue(42.0d)); | |||
MetricDto ncloc = db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.name())); | |||
db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(114.0d)); | |||
db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(217.0d).setVariation(0.0d)); | |||
db.measures().insertLiveMeasure(project3, ncloc, m -> m.setValue(1984.0d)); | |||
MetricDto newViolations = db.measures().insertMetric(m -> m.setKey("new_violations").setValueType(INT.name())); | |||
db.measures().insertLiveMeasure(project1, newViolations, m -> m.setVariation(25.0d)); | |||
db.measures().insertLiveMeasure(project2, newViolations, m -> m.setVariation(25.0d)); | |||
db.measures().insertLiveMeasure(project3, newViolations, m -> m.setVariation(255.0d)); | |||
List<String> projectKeys = Arrays.asList(project1.getDbKey(), project2.getDbKey(), project3.getDbKey()); | |||
String result = ws.newRequest() | |||
.setParam(PARAM_PROJECT_KEYS, Joiner.on(",").join(projectKeys)) | |||
@@ -108,40 +112,34 @@ public class SearchActionTest { | |||
@Test | |||
public void return_measures() throws Exception { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||
SnapshotDto projectSnapshot = db.components().insertProjectAndSnapshot(project); | |||
setBrowsePermissionOnUser(project); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, project, projectSnapshot).setValue(15.5d)); | |||
db.commit(); | |||
ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
db.measures().insertLiveMeasure(project, coverage, m -> m.setValue(15.5d)); | |||
SearchWsResponse result = call(singletonList(project.getDbKey()), singletonList("coverage")); | |||
SearchWsResponse result = call(singletonList(project.getDbKey()), singletonList(coverage.getKey())); | |||
List<Measure> measures = result.getMeasuresList(); | |||
assertThat(measures).hasSize(1); | |||
Measure measure = measures.get(0); | |||
assertThat(measure.getMetric()).isEqualTo("coverage"); | |||
assertThat(measure.getMetric()).isEqualTo(coverage.getKey()); | |||
assertThat(measure.getValue()).isEqualTo("15.5"); | |||
} | |||
@Test | |||
public void return_measures_on_leak_period() throws Exception { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.organizations().insert()); | |||
SnapshotDto projectSnapshot = db.components().insertProjectAndSnapshot(project); | |||
setBrowsePermissionOnUser(project); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(coverage, project, projectSnapshot) | |||
.setValue(15.5d) | |||
.setVariation(10d)); | |||
db.commit(); | |||
SearchWsResponse result = call(singletonList(project.getDbKey()), singletonList("coverage")); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
db.measures().insertLiveMeasure(project, coverage, m -> m.setValue(15.5d).setVariation(10d)); | |||
SearchWsResponse result = call(singletonList(project.getDbKey()), singletonList(coverage.getKey())); | |||
List<Measure> measures = result.getMeasuresList(); | |||
assertThat(measures).hasSize(1); | |||
Measure measure = measures.get(0); | |||
assertThat(measure.getMetric()).isEqualTo("coverage"); | |||
assertThat(measure.getMetric()).isEqualTo(coverage.getKey()); | |||
assertThat(measure.getValue()).isEqualTo("15.5"); | |||
assertThat(measure.getPeriods().getPeriodsValueList()) | |||
.extracting(Measures.PeriodValue::getIndex, Measures.PeriodValue::getValue) | |||
@@ -150,130 +148,121 @@ public class SearchActionTest { | |||
@Test | |||
public void sort_by_metric_key_then_project_name() throws Exception { | |||
MetricDto coverage = insertCoverageMetric(); | |||
MetricDto complexity = insertComplexityMetric(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(organizationDto).setName("C"); | |||
SnapshotDto projectSnapshot1 = db.components().insertProjectAndSnapshot(project1); | |||
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(organizationDto).setName("A"); | |||
SnapshotDto projectSnapshot2 = db.components().insertProjectAndSnapshot(project2); | |||
ComponentDto project3 = ComponentTesting.newPrivateProjectDto(organizationDto).setName("B"); | |||
SnapshotDto projectSnapshot3 = db.components().insertProjectAndSnapshot(project3); | |||
setBrowsePermissionOnUser(project1, project2, project3); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, project1, projectSnapshot1).setValue(5.5d)); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, project2, projectSnapshot2).setValue(6.5d)); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, project3, projectSnapshot3).setValue(7.5d)); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(complexity, project1, projectSnapshot1).setValue(10d)); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(complexity, project2, projectSnapshot2).setValue(15d)); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(complexity, project3, projectSnapshot3).setValue(20d)); | |||
db.commit(); | |||
SearchWsResponse result = call(asList(project1.getDbKey(), project2.getDbKey(), project3.getDbKey()), asList("coverage", "complexity")); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setKey("coverage").setValueType(FLOAT.name())); | |||
MetricDto complexity = db.measures().insertMetric(m -> m.setKey("complexity").setValueType(INT.name())); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project1 = db.components().insertPrivateProject(organization, p -> p.setName("C")); | |||
ComponentDto project2 = db.components().insertPrivateProject(organization, p -> p.setName("A")); | |||
ComponentDto project3 = db.components().insertPrivateProject(organization, p -> p.setName("B")); | |||
userSession.addProjectPermission(UserRole.USER, project1); | |||
userSession.addProjectPermission(UserRole.USER, project2); | |||
userSession.addProjectPermission(UserRole.USER, project3); | |||
db.measures().insertLiveMeasure(project1, coverage, m -> m.setValue(5.5d)); | |||
db.measures().insertLiveMeasure(project2, coverage, m -> m.setValue(6.5d)); | |||
db.measures().insertLiveMeasure(project3, coverage, m -> m.setValue(7.5d)); | |||
db.measures().insertLiveMeasure(project1, complexity, m -> m.setValue(10d)); | |||
db.measures().insertLiveMeasure(project2, complexity, m -> m.setValue(15d)); | |||
db.measures().insertLiveMeasure(project3, complexity, m -> m.setValue(20d)); | |||
SearchWsResponse result = call(asList(project1.getDbKey(), project2.getDbKey(), project3.getDbKey()), asList(coverage.getKey(), complexity.getKey())); | |||
assertThat(result.getMeasuresList()).extracting(Measure::getMetric, Measure::getComponent) | |||
.containsExactly( | |||
tuple("complexity", project2.getDbKey()), tuple("complexity", project3.getDbKey()), tuple("complexity", project1.getDbKey()), | |||
tuple("coverage", project2.getDbKey()), tuple("coverage", project3.getDbKey()), tuple("coverage", project1.getDbKey())); | |||
tuple(complexity.getKey(), project2.getDbKey()), tuple(complexity.getKey(), project3.getDbKey()), tuple(complexity.getKey(), project1.getDbKey()), | |||
tuple(coverage.getKey(), project2.getDbKey()), tuple(coverage.getKey(), project3.getDbKey()), tuple(coverage.getKey(), project1.getDbKey())); | |||
} | |||
@Test | |||
public void return_measures_on_view() throws Exception { | |||
ComponentDto view = newView(db.getDefaultOrganization()); | |||
SnapshotDto viewSnapshot = db.components().insertProjectAndSnapshot(view); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, view, viewSnapshot).setValue(15.5d)); | |||
db.commit(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto view = db.components().insertPrivatePortfolio(organization); | |||
userSession.addProjectPermission(UserRole.USER, view); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
db.measures().insertLiveMeasure(view, coverage, m -> m.setValue(15.5d)); | |||
SearchWsResponse result = call(singletonList(view.getDbKey()), singletonList("coverage")); | |||
SearchWsResponse result = call(singletonList(view.getDbKey()), singletonList(coverage.getKey())); | |||
List<Measure> measures = result.getMeasuresList(); | |||
assertThat(measures).hasSize(1); | |||
Measure measure = measures.get(0); | |||
assertThat(measure.getMetric()).isEqualTo("coverage"); | |||
assertThat(measure.getMetric()).isEqualTo(coverage.getKey()); | |||
assertThat(measure.getValue()).isEqualTo("15.5"); | |||
} | |||
@Test | |||
public void return_measures_on_application() throws Exception { | |||
ComponentDto application = newApplication(db.getDefaultOrganization()); | |||
SnapshotDto viewSnapshot = db.components().insertProjectAndSnapshot(application); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, application, viewSnapshot).setValue(15.5d)); | |||
db.commit(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto application = db.components().insertPrivateApplication(organization); | |||
userSession.addProjectPermission(UserRole.USER, application); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
db.measures().insertLiveMeasure(application, coverage, m -> m.setValue(15.5d)); | |||
SearchWsResponse result = call(singletonList(application.getDbKey()), singletonList("coverage")); | |||
SearchWsResponse result = call(singletonList(application.getDbKey()), singletonList(coverage.getKey())); | |||
List<Measure> measures = result.getMeasuresList(); | |||
assertThat(measures).hasSize(1); | |||
Measure measure = measures.get(0); | |||
assertThat(measure.getMetric()).isEqualTo("coverage"); | |||
assertThat(measure.getMetric()).isEqualTo(coverage.getKey()); | |||
assertThat(measure.getValue()).isEqualTo("15.5"); | |||
} | |||
@Test | |||
public void return_measures_on_sub_view() throws Exception { | |||
ComponentDto view = newView(db.getDefaultOrganization()); | |||
SnapshotDto viewSnapshot = db.components().insertProjectAndSnapshot(view); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto view = db.components().insertPrivatePortfolio(organization); | |||
ComponentDto subView = db.components().insertComponent(newSubView(view)); | |||
MetricDto coverage = insertCoverageMetric(); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, subView, viewSnapshot).setValue(15.5d)); | |||
db.commit(); | |||
userSession.addProjectPermission(UserRole.USER, subView); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
db.measures().insertLiveMeasure(subView, metric, m -> m.setValue(15.5d)); | |||
SearchWsResponse result = call(singletonList(subView.getDbKey()), singletonList("coverage")); | |||
SearchWsResponse result = call(singletonList(subView.getDbKey()), singletonList(metric.getKey())); | |||
List<Measure> measures = result.getMeasuresList(); | |||
assertThat(measures).hasSize(1); | |||
Measure measure = measures.get(0); | |||
assertThat(measure.getMetric()).isEqualTo("coverage"); | |||
assertThat(measure.getMetric()).isEqualTo(metric.getKey()); | |||
assertThat(measure.getValue()).isEqualTo("15.5"); | |||
} | |||
@Test | |||
public void only_returns_authorized_projects() { | |||
MetricDto metricDto = insertComplexityMetric(); | |||
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||
SnapshotDto projectSnapshot1 = db.components().insertProjectAndSnapshot(project1); | |||
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||
SnapshotDto projectSnapshot2 = db.components().insertProjectAndSnapshot(project2); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(metricDto, project1, projectSnapshot1).setValue(15.5d), | |||
newMeasureDto(metricDto, project2, projectSnapshot2).setValue(42.0d)); | |||
db.commit(); | |||
setBrowsePermissionOnUser(project1); | |||
SearchWsResponse result = call(asList(project1.getDbKey(), project2.getDbKey()), singletonList("complexity")); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
ComponentDto project1 = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
ComponentDto project2 = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
db.measures().insertLiveMeasure(project1, metric, m -> m.setValue(15.5d)); | |||
db.measures().insertLiveMeasure(project2, metric, m -> m.setValue(42.0d)); | |||
Arrays.stream(new ComponentDto[]{project1}).forEach(p -> userSession.addProjectPermission(UserRole.USER, p)); | |||
SearchWsResponse result = call(asList(project1.getDbKey(), project2.getDbKey()), singletonList(metric.getKey())); | |||
assertThat(result.getMeasuresList()).extracting(Measure::getComponent).containsOnly(project1.getDbKey()); | |||
} | |||
@Test | |||
public void do_not_verify_permissions_if_user_is_root() { | |||
MetricDto metricDto = insertComplexityMetric(); | |||
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||
SnapshotDto projectSnapshot1 = db.components().insertProjectAndSnapshot(project1); | |||
dbClient.measureDao().insert(dbSession, newMeasureDto(metricDto, project1, projectSnapshot1).setValue(15.5d)); | |||
db.commit(); | |||
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
ComponentDto project1 = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
db.measures().insertLiveMeasure(project1, metric, m -> m.setValue(15.5d)); | |||
userSession.setNonRoot(); | |||
SearchWsResponse result = call(asList(project1.getDbKey()), singletonList("complexity")); | |||
SearchWsResponse result = call(singletonList(project1.getDbKey()), singletonList(metric.getKey())); | |||
assertThat(result.getMeasuresCount()).isEqualTo(0); | |||
userSession.setRoot(); | |||
result = call(asList(project1.getDbKey()), singletonList("complexity")); | |||
result = call(singletonList(project1.getDbKey()), singletonList(metric.getKey())); | |||
assertThat(result.getMeasuresCount()).isEqualTo(1); | |||
} | |||
@Test | |||
public void does_not_return_branch_when_using_db_key() { | |||
MetricDto coverage = insertCoverageMetric(); | |||
MetricDto coverage = db.measures().insertMetric(m -> m.setValueType(FLOAT.name())); | |||
ComponentDto project = db.components().insertMainBranch(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
SnapshotDto analysis = db.components().insertSnapshot(branch); | |||
db.measures().insertMeasure(branch, analysis, coverage, m -> m.setValue(10d)); | |||
setBrowsePermissionOnUser(project); | |||
db.measures().insertLiveMeasure(branch, coverage, m -> m.setValue(10d)); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
SearchWsResponse result = call(asList(branch.getDbKey()), singletonList(coverage.getKey())); | |||
SearchWsResponse result = call(singletonList(branch.getDbKey()), singletonList(coverage.getKey())); | |||
assertThat(result.getMeasuresList()).isEmpty(); | |||
} | |||
@@ -281,7 +270,7 @@ public class SearchActionTest { | |||
@Test | |||
public void fail_if_no_metric() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
setBrowsePermissionOnUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'metricKeys' parameter is missing"); | |||
@@ -292,7 +281,7 @@ public class SearchActionTest { | |||
@Test | |||
public void fail_if_empty_metric() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
setBrowsePermissionOnUser(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Metric keys must be provided"); | |||
@@ -303,33 +292,33 @@ public class SearchActionTest { | |||
@Test | |||
public void fail_if_unknown_metric() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
setBrowsePermissionOnUser(project); | |||
insertComplexityMetric(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("The following metrics are not found: ncloc, violations"); | |||
call(singletonList(project.getDbKey()), newArrayList("violations", "complexity", "ncloc")); | |||
call(singletonList(project.getDbKey()), newArrayList("violations", metric.getKey(), "ncloc")); | |||
} | |||
@Test | |||
public void fail_if_no_project() { | |||
insertComplexityMetric(); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Project keys must be provided"); | |||
call(null, singletonList("complexity")); | |||
call(null, singletonList(metric.getKey())); | |||
} | |||
@Test | |||
public void fail_if_empty_project_key() { | |||
insertComplexityMetric(); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Project keys must be provided"); | |||
call(emptyList(), singletonList("complexity")); | |||
call(emptyList(), singletonList(metric.getKey())); | |||
} | |||
@Test | |||
@@ -338,12 +327,12 @@ public class SearchActionTest { | |||
.mapToObj(i -> db.components().insertPrivateProject()) | |||
.map(ComponentDto::getDbKey) | |||
.collect(Collectors.toList()); | |||
insertComplexityMetric(); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("101 projects provided, more than maximum authorized (100)"); | |||
call(keys, singletonList("complexity")); | |||
call(keys, singletonList(metric.getKey())); | |||
} | |||
@Test | |||
@@ -352,48 +341,48 @@ public class SearchActionTest { | |||
.mapToObj(i -> db.components().insertPrivateProject()) | |||
.map(ComponentDto::getDbKey) | |||
.collect(Collectors.toList()); | |||
insertComplexityMetric(); | |||
MetricDto metric = db.measures().insertMetric(); | |||
call(keys, singletonList("complexity")); | |||
call(keys, singletonList(metric.getKey())); | |||
} | |||
@Test | |||
public void fail_if_module() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||
setBrowsePermissionOnUser(project); | |||
insertComplexityMetric(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed"); | |||
call(singletonList(module.getDbKey()), singletonList("complexity")); | |||
call(singletonList(module.getDbKey()), singletonList(metric.getKey())); | |||
} | |||
@Test | |||
public void fail_if_directory() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto dir = db.components().insertComponent(newDirectory(project, "dir")); | |||
setBrowsePermissionOnUser(project); | |||
insertComplexityMetric(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed"); | |||
call(singletonList(dir.getDbKey()), singletonList("complexity")); | |||
call(singletonList(dir.getDbKey()), singletonList(metric.getKey())); | |||
} | |||
@Test | |||
public void fail_if_file() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
setBrowsePermissionOnUser(project); | |||
insertComplexityMetric(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
MetricDto metric = db.measures().insertMetric(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed"); | |||
call(singletonList(file.getDbKey()), singletonList("complexity")); | |||
call(singletonList(file.getDbKey()), singletonList(metric.getKey())); | |||
} | |||
@Test | |||
@@ -418,132 +407,4 @@ public class SearchActionTest { | |||
} | |||
return request.executeProtobuf(SearchWsResponse.class); | |||
} | |||
private static MetricDto newMetricDtoWithoutOptimization() { | |||
return newMetricDto() | |||
.setWorstValue(null) | |||
.setBestValue(null) | |||
.setOptimizedBestValue(false) | |||
.setUserManaged(false); | |||
} | |||
private MetricDto insertNewViolationsMetric() { | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization() | |||
.setKey("new_violations") | |||
.setShortName("New issues") | |||
.setDescription("New Issues") | |||
.setDomain("Issues") | |||
.setValueType("INT") | |||
.setDirection(-1) | |||
.setQualitative(true) | |||
.setHidden(false) | |||
.setUserManaged(false) | |||
.setOptimizedBestValue(true) | |||
.setBestValue(0.0d)); | |||
db.commit(); | |||
return metric; | |||
} | |||
private MetricDto insertNclocMetric() { | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization() | |||
.setKey("ncloc") | |||
.setShortName("Lines of code") | |||
.setDescription("Non Commenting Lines of Code") | |||
.setDomain("Size") | |||
.setValueType("INT") | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
db.commit(); | |||
return metric; | |||
} | |||
private MetricDto insertComplexityMetric() { | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization() | |||
.setKey("complexity") | |||
.setShortName("Complexity") | |||
.setDescription("Cyclomatic complexity") | |||
.setDomain("Complexity") | |||
.setValueType("INT") | |||
.setDirection(-1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
db.commit(); | |||
return metric; | |||
} | |||
private MetricDto insertCoverageMetric() { | |||
MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization() | |||
.setKey("coverage") | |||
.setShortName("Coverage") | |||
.setDescription("Code Coverage") | |||
.setDomain("Coverage") | |||
.setValueType(Metric.ValueType.FLOAT.name()) | |||
.setDirection(1) | |||
.setQualitative(false) | |||
.setHidden(false) | |||
.setUserManaged(false)); | |||
db.commit(); | |||
return metric; | |||
} | |||
private List<String> insertJsonExampleData() { | |||
List<String> projectKeys = new ArrayList<>(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey("MY_PROJECT_1").setName("Project 1"); | |||
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey("MY_PROJECT_2").setName("Project 2"); | |||
ComponentDto project3 = ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey("MY_PROJECT_3").setName("Project 3"); | |||
projectKeys.addAll(asList(project1.getDbKey(), project2.getDbKey(), project3.getDbKey())); | |||
db.components().insertComponents(project1, project2, project3); | |||
SnapshotDto projectSnapshot1 = dbClient.snapshotDao().insert(dbSession, newAnalysis(project1) | |||
.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime()) | |||
.setPeriodMode("previous_version") | |||
.setPeriodParam("1.0-SNAPSHOT")); | |||
SnapshotDto projectSnapshot2 = dbClient.snapshotDao().insert(dbSession, newAnalysis(project2) | |||
.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime()) | |||
.setPeriodMode("previous_version") | |||
.setPeriodParam("1.0-SNAPSHOT")); | |||
SnapshotDto projectSnapshot3 = dbClient.snapshotDao().insert(dbSession, newAnalysis(project3) | |||
.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime()) | |||
.setPeriodMode("previous_version") | |||
.setPeriodParam("1.0-SNAPSHOT")); | |||
MetricDto complexity = insertComplexityMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(complexity, project1, projectSnapshot1) | |||
.setValue(12.0d), | |||
newMeasureDto(complexity, project2, projectSnapshot2) | |||
.setValue(35.0d) | |||
.setVariation(0.0d), | |||
newMeasureDto(complexity, project3, projectSnapshot3) | |||
.setValue(42.0d)); | |||
MetricDto ncloc = insertNclocMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(ncloc, project1, projectSnapshot1) | |||
.setValue(114.0d), | |||
newMeasureDto(ncloc, project2, projectSnapshot2) | |||
.setValue(217.0d) | |||
.setVariation(0.0d), | |||
newMeasureDto(ncloc, project3, projectSnapshot3) | |||
.setValue(1984.0d)); | |||
MetricDto newViolations = insertNewViolationsMetric(); | |||
dbClient.measureDao().insert(dbSession, | |||
newMeasureDto(newViolations, project1, projectSnapshot1) | |||
.setVariation(25.0d), | |||
newMeasureDto(newViolations, project2, projectSnapshot2) | |||
.setVariation(25.0d), | |||
newMeasureDto(newViolations, project3, projectSnapshot3) | |||
.setVariation(255.0d)); | |||
db.commit(); | |||
setBrowsePermissionOnUser(project1, project2, project3); | |||
return projectKeys; | |||
} | |||
private void setBrowsePermissionOnUser(ComponentDto... projects) { | |||
Arrays.stream(projects).forEach(p -> userSession.addProjectPermission(UserRole.USER, p)); | |||
} | |||
} |