]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10116 Better scalability of loading of project measures
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>
Thu, 23 Nov 2017 10:13:26 +0000 (11:13 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 5 Dec 2017 08:29:16 +0000 (09:29 +0100)
110 files changed:
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ResourceDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDao.java [new file with mode: 0644]
server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDto.java [new file with mode: 0644]
server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureMapper.java [new file with mode: 0644]
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureQuery.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureTreeQuery.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/PastMeasureDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml [new file with mode: 0644]
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDtoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/LiveMeasureDaoTest.java [new file with mode: 0644]
server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDbTester.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureQueryTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureTesting.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureTreeQueryTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/PastMeasureDtoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeCommandsTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/insert-result.xml
server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/past_measures_with_person_id.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/with_some_measures_for_developer.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldDeleteWastedMeasuresWhenPurgingAnalysis.xml
server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeCommandsTest/shouldPurgeAnalysis.xml
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/BaseSqlStatement.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/SqlStatement.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasures.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest/empty.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest/initial.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest/initial.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java
server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/BestValueOptimization.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/MapBasedRawMeasureRepository.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/MeasureRepository.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/MeasureRepositoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/MeasureToMeasureDto.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStep.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistMeasuresStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowAction.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentAction.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentDtoToWsComponent.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeRequest.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/MeasureDtoToWsMeasure.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricDtoWithBestValue.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java
server/sonar-server/src/test/java/org/sonar/server/branch/ws/ListActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/AppActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/BestValueOptimizationTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/MeasureRepositoryRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/MeasureToMeasureDtoTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistMeasuresStepTest.java
server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeSortTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchHistoryActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchMyProjectsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java
server/sonar-server/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java
server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/RuleMeasure.java
sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java
tests/src/test/java/util/ItUtils.java

index 5a9d59c19edbbab2c1c06a31182a34266d734f5e..950cbde71b7e19a2cec704f0fe51fc9f157dc13d 100644 (file)
@@ -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
index c01be6b844ad6292ad7b9bd22dc092b862ed5d58..421e67fa5e8fa947673247c259e3e94cf386b774 100644 (file)
@@ -69,6 +69,7 @@ public final class SqTables {
     "internal_properties",
     "issues",
     "issue_changes",
+    "live_measures",
     "manual_measures",
     "metrics",
     "notifications",
index a4b54efd55eaa66e8b31ebaa01d8574a2ffc2593..1e43bd3cfbb4d2e0f9ff34846796323d5cfa0a17 100644 (file)
@@ -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" (
index 06a3216c6c754385eb599442cd95dd78a93fcf03..e9419b755fbea3427c2f3f86fc32393d9b217214 100644 (file)
@@ -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,
index 1cc3778af491740603b30de82d4b5c2a51f0161e..ce3e71e8087fd88fba31104f690c7eccb2e71a03 100644 (file)
@@ -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);
   }
index 03f2eb1a5567bc5834e6aca07cdb4f77ea760f88..0310390b272c3e0f37b6e88b36b2fff79e90a354 100644 (file)
@@ -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,
index 9e69d55f2d974cb189088a131406c9d59f41851e..65e14a2d8a866b89203b8ec98d3eb8aac412a7fc 100644 (file)
@@ -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;
index b8cc1cf53f66dd1f60b31e8c1aa94d6aa5f14ac6..46b06fe7a483bc381f6a2f6fc04e7dab4d31a87a 100644 (file)
@@ -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;
   }
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDao.java
new file mode 100644 (file)
index 0000000..353e129
--- /dev/null
@@ -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);
+  }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDto.java
new file mode 100644 (file)
index 0000000..b8b9d78
--- /dev/null
@@ -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();
+  }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureMapper.java
new file mode 100644 (file)
index 0000000..4cdfa21
--- /dev/null
@@ -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);
+}
index 1656c3229a22c053b42dadb40aa1116b47b91313..f6ba91fde59fb41856fa7f1bc19e0bcc6b5efff0 100644 (file)
  */
 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);
   }
index fbf5fae3594427dc56824d5464dc6bc8fe208ea0..d5161b1a1172916075fe7ee0dea144aa17c5b4d3 100644 (file)
@@ -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();
   }
 }
index 4250ac4f06755113c853cff49dc125809eb76f2f..c059728466e41cd8360287f519a3e4c6b028a490 100644 (file)
  */
 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);
 }
index 0b2685ebbe5ccc0ab8cdb649ceeacc086cb09499..5d074d93da733d4a566194477bac30d173b83422 100644 (file)
@@ -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);
     }
index 04df1a38f17aa677ace4277f466b004088799995..0f368911b78f9794755fe115a4c224d116f077ef 100644 (file)
@@ -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);
     }
index 0e5ccfb91aa1ba76d2ecbf4197328726a7e5115f..324c24a29ffd998b9803bca5a84a5279eef9a1cf 100644 (file)
@@ -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;
-  }
-
 }
index d6cd39815a93f99c0470a57eed4d7f7c9286d89e..b922e5a9ba27753a24e969064cf717d0e5c9a73d 100644 (file)
@@ -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;
index 9d65a9834c81f726e79c2d0adbfb5b1b8ce4232d..4ea147875716f70478b49238c5abfd886f2cf8c4 100644 (file)
@@ -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();
+  }
 }
index c9d903f883fc974ac5fb240820d78f2a054fc207..245c23c7c6a01cf9a9c10a8ff552560ba641152a 100644 (file)
@@ -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);
   }
 
index de29166e268ba435fb0ec3f0964bc585b7c4fe19..cad8376dc398a0f34bc0337b1837aa2a84167ff5 100644 (file)
@@ -204,6 +204,7 @@ public class PurgeDao implements Dao {
     commands.deleteCeQueue(rootUuid);
     commands.deleteWebhookDeliveries(rootUuid);
     commands.deleteBranch(rootUuid);
+    commands.deleteLiveMeasures(rootUuid);
   }
 
   /**
index 3961aa6a335450538f9f11f802c741ebef60ae3a..c6393dc4e86db948c686e2e0bb75dcd3278492d4 100644 (file)
@@ -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);
 }
index 5d7e051032f5821c144c7f79d364225136d36b31..22991a65e290465a15cc6fb00a6420f37bcba493 100644 (file)
@@ -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>
       root_uuid,
       path,
       copy_component_uuid,
-      developer_uuid,
       enabled,
       created_at,
       b_changed,
     #{rootUuid,jdbcType=VARCHAR},
     #{path,jdbcType=VARCHAR},
     #{copyComponentUuid,jdbcType=VARCHAR},
-    #{developerUuid,jdbcType=VARCHAR},
     #{enabled,jdbcType=BOOLEAN},
     #{createdAt,jdbcType=TIMESTAMP},
     ${_false},
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
new file mode 100644 (file)
index 0000000..57eb8f8
--- /dev/null
@@ -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>
index 860b4e73f47e34ccf7c871e0363c09d13ff709e2..4dd4ecd7504e1c9d865b7df44a994149cf51560f 100644 (file)
@@ -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,
     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
         #{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">
       and analysis.created_at&lt;#{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,
     text_value,
     alert_status,
     alert_text,
-    person_id,
     variation_value_1,
     measure_data)
     VALUES (
     #{textValue, jdbcType=VARCHAR},
     #{alertStatus, jdbcType=VARCHAR},
     #{alertText, jdbcType=VARCHAR},
-    #{developerId, jdbcType=INTEGER},
     #{variation, jdbcType=DOUBLE},
     #{dataValue, jdbcType=BINARY}
     )
index 36f668e5626bba7321fa76b78fc48da782609b85..471bd59dbb11ad44b70a0d28273758a8b269b6fa 100644 (file)
       <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>
 
     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>
 
index d79b8f289e8ed13c79b0c5b166088d8af40d56fb..5ff22c1e2fd0b50fdaeec8c269490a1a7244c124 100644 (file)
@@ -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);
   }
 }
index 140a3a0bfd3d2ba784afb429e56389c825ffe942..7ffbbb8371e3d681171883c030494dcdd02596c2 100644 (file)
@@ -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();
index 143f2abdf435f509d4229e584d829330d660fe07..f79ea9c4e70d1a306d592f9e1ccb1d209b53cde3 100644 (file)
@@ -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();
   }
 
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/measure/LiveMeasureDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/LiveMeasureDaoTest.java
new file mode 100644 (file)
index 0000000..c4ab865
--- /dev/null
@@ -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);
+  }
+}
index 40067b96321aaeed159942b857c36fca06873b02..05d9444c1afd3fcdeea2260ae26fbdc5e31c28da 100644 (file)
  */
 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
-
 }
index b1d45914ec3ba975ec919401192c3749aec4ce50..30ba72b4a3090cd06494c86deda8ab1f55d2f634 100644 (file)
@@ -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();
index 3e083c415bb870dfa033b6e019c0ca5bd7f2d0cc..959edae309c4dde984689ebbd5bfb43620d0b3e7 100644 (file)
@@ -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()
index 39e7671a2814663bad1d201d8a61639559fd4ad7..34f8ba2a92740f7da49bc33c313ce4c94d8ee764 100644 (file)
@@ -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++);
   }
 }
index 925f0765c95c9afdc2ab013ef5ab06a2accf1919..54dbde3ea5478ba7ed3345fc621613df56067a58 100644 (file)
@@ -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
index 07a630ad5f7b5f2e9cd64fed75651cac7f1a9e4a..02fe87598bcd0862e7d0e74a4acc20e0b3ef2f24 100644 (file)
@@ -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();
   }
 
index 5c475437ed3210c871244734aced9ec5db2f63c9..2d78a96a8574050411d09f3aea0ae726a626c00b 100644 (file)
@@ -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;
-  }
-
 }
index d6b7f01f9f9f2b64566c104067181a4735a19e4a..ba0126ffbdbe854c217b0213b00bf6e26020110b 100644 (file)
@@ -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);
index e48f5c90b704371e2243146454c3b37b3865aaba..f618a131fa4a95693249148d706320f2a396fa0a 100644 (file)
@@ -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);
 
index 692539f175b4d0af3d990a35e2a3e8cc9d8b5063..2af5e30c3707d31619976068709da701490bcb99 100644 (file)
@@ -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]"
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/past_measures_with_person_id.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/past_measures_with_person_id.xml
deleted file mode 100644 (file)
index d188655..0000000
+++ /dev/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>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/with_some_measures_for_developer.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/measure/MeasureDaoTest/with_some_measures_for_developer.xml
deleted file mode 100644 (file)
index 6773653..0000000
+++ /dev/null
@@ -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>
index 2c0a7c2df25463f1b84f986efc078108f59e1060..d683a6acfe64155ff4c2f747180e72e8c14ef9a1 100644 (file)
                     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>
index 70b5a8db7c187151ed7139b4bd7eeee6826ed8ae..5e2e4c4e819eb5997a86964d6f6f71bc858940f6 100644 (file)
   <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]"
index 6444617dc6e5549914895782dd4379cb28c16a4a..ebb62540d0bf5386aa3aac327879dcb5463720f3 100644 (file)
@@ -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) {
index 64aea4df5d9990c595979cdc8be6ed91405c14d1..2264d774ca5dbf6c8cf9846eadfad4e3e689bb7d 100644 (file)
@@ -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();
index f9628f7c658ba877bbdddf8519f413e3522c2aba..c15db0f90d61f8c1474d7dedbcc72184b137ae96 100644 (file)
@@ -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;
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java
new file mode 100644 (file)
index 0000000..bc37773
--- /dev/null
@@ -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());
+  }
+}
index f03ca93038b95a6c237fc9069c2880866eb4c616..e51e2426a93cd740b3e5a90574a93a70ad3d4a33 100644 (file)
@@ -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)
+    ;
   }
-
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java
new file mode 100644 (file)
index 0000000..92ba449
--- /dev/null
@@ -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());
+    }
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasures.java
new file mode 100644 (file)
index 0000000..c11e4e4
--- /dev/null
@@ -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());
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java
new file mode 100644 (file)
index 0000000..1d226fc
--- /dev/null
@@ -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;
+    });
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java
new file mode 100644 (file)
index 0000000..806e0ea
--- /dev/null
@@ -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");
+  }
+}
index ece11091b41b69920002c29abee707b30a605c87..fa47fed02ed2d161845b66bcb62d967e13ad16d9 100644 (file)
@@ -35,7 +35,7 @@ public class DbVersion70Test {
 
   @Test
   public void verify_migration_count() {
-    verifyMigrationCount(underTest, 6);
+    verifyMigrationCount(underTest, 10);
   }
 
 }
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java
new file mode 100644 (file)
index 0000000..2019003
--- /dev/null
@@ -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;
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest.java
new file mode 100644 (file)
index 0000000..08bf207
--- /dev/null
@@ -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);
+  }
+}
+
+
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java
new file mode 100644 (file)
index 0000000..7a2fc7e
--- /dev/null
@@ -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})
+    };
+  }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest/empty.sql
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest/initial.sql
new file mode 100644 (file)
index 0000000..be55d6f
--- /dev/null
@@ -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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropIndexOnPersonMeasuresTest/initial.sql
new file mode 100644 (file)
index 0000000..00ef5e2
--- /dev/null
@@ -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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql
new file mode 100644 (file)
index 0000000..b3dc455
--- /dev/null
@@ -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");
+
index d337d8ca5fd0fa557d06451035f09b1eed8f22de..65af52a7b8733f31cf67ce01ae788d5e72c354d9 100644 (file)
@@ -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());
index 56d4f4aa89fe1cb9c42e658427d968d8b0cbc2bd..901da41760b9ba896e588f7fd9303b8c837512fb 100644 (file)
  */
 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();
index 1def57fd52ba5d70d73ffea4e3a06ffb0e10a1bd..455bfbcb8c72ba3d8e8c3f15cf56d380440b8d6b 100644 (file)
@@ -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);
index bce3c7c57a79c779e6054e7f15cae57befc0acfc..52f30c83cb1f7d9cf6ec960fa6429f0b26f9e5c3 100644 (file)
@@ -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);
   }
 
index 751a962bf2042d9acb06fd2bb6fe04898ffad81d..8410b8345997eae95083c84e2dc5fbf183580981 100644 (file)
@@ -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
index ecc86ce8c5e82eef21dd406f9f6976365d8e0aee..c5acb1d03c261a2d18673b2c5a0b775f55b58ff5 100644 (file)
  */
 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>
index 9a0942003b3c77b001fa69cd499262e6c0603954..5755fb91cdec176e2bebd9e7f77c2a7873fa8a90 100644 (file)
  */
 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);
index cc1935fe7b2e42ca7dd8b9c41f9c0a156c7ed3fc..1970b18db377e40db21e975caae315755cd94737 100644 (file)
 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));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStep.java
new file mode 100644 (file)
index 0000000..507f152
--- /dev/null
@@ -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;
+    }
+  }
+
+}
index 69d107476455afe0f3e6980f8aadc20cf8939fb5..6c9f03a5427b9a26ca01ff346dc0ddb5ff7086d3 100644 (file)
  */
 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;
     }
   }
index 108ca3b9d84dadd4b2de499f96139a3da1d154b4..d9b4a87e366f2c73bf12bac8f7979bd75e27acef 100644 (file)
@@ -88,6 +88,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
     PersistAnalysisStep.class,
     PersistAnalysisPropertiesStep.class,
     PersistMeasuresStep.class,
+    PersistLiveMeasuresStep.class,
     PersistIssuesStep.class,
     PersistProjectLinksStep.class,
     PersistEventsStep.class,
index 73b428f23450eec8eea363e92e229322c80d1a3b..6136a64d95f2dc3f1f4bdbefb1e7004040fcc383 100644 (file)
@@ -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);
   }
 }
index 59633ac3d74ac187f96144be0b98f0cad41d2e6b..37fbe9a40f2098777c35b3992638afff97b8bc09 100644 (file)
@@ -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;
   }
index 959d707acdf66b3ca7286e6a9d65418514b275ce..66470ef3f8c84cb536e911b4acebbc79e3194dfc 100644 (file)
@@ -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();
index e47c71bb1a6fea1e75524b645f11c481506fd28a..4a1b94aa3e79a03337bbcd853eb86359d542c757 100644 (file)
@@ -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()),
index 16a7d522dbcd76adf450aef43f9e740d2d37b633..5a871110bb82105168eea92ddf6e71db31c823b3 100644 (file)
@@ -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);
     }
 
index 909a133e1bcf1a2b998be1a16f581697d82d171f..79ed3e383dd545d64ba478ec3de01e107e21ee2e 100644 (file)
@@ -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;
index 3764c46b903935820fc12c09b37d8a1732ea273d..c0bbad0037a25dcb24351834e1c09ba84d464ff5 100644 (file)
@@ -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
index f4d920f1b300e2021c6af5cd9588664e730ba58f..a76ee049fd55ffd65b92ceb4f210b9f0056ff536 100644 (file)
@@ -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);
-    }
-  }
 }
index dbbda02517f4465fcd117cf649f2749ce2457bb6..bdd6d5b2738adcd0098341e3ff339993dcc39078 100644 (file)
@@ -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());
 
index 37867d57e77d932ead6a7e9278a5aac0d991d741..74f41d8fc9d82e2c815339b95956353d817cb141 100644 (file)
  */
 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)
index 9e389e76aef4ef35e29c2025c6b8712181d9a6fa..49f746d3a8cc068115a8f8227e7a57100ebb7e2e 100644 (file)
@@ -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;
     }
index 53c9b8172823ba33ea95df4f6d84589992739091..7bd685e3203a43da4dffa523ed975f2df16e7b29 100644 (file)
  */
 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);
     }
   }
 }
index 84c902f872934dbd1af4ca931990ece7dd5ee8e8..10dfbb4831d38c5bb16b6c641c9e516fc186d040 100644 (file)
  */
 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;
index a55d2ebcfe89ebe952f0d2bfcb7098c6838d3195..34156db7759b0d53316d71227e00f2711cb08635 100644 (file)
@@ -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();
   }
 
index bb8a93ae72b0b50812a6f0dd6bbb947c4ebff310..2415c9cc93a87afba777da822d3536ddc77cde80 100644 (file)
@@ -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())
index 7eb2c50a074fa325c8ae993c1da3683a57f2a13d..be66db8cebe2bbc242bfc38cc87990e5efcd6f75 100644 (file)
@@ -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())
index 77ba51d4a7ec888f234308364fb861b4598f4f14..afddc8ae32c01fd505e32f8e3b56801107456070 100644 (file)
@@ -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;
     }
index 6ad0fbe28418fa325d652779a3fdb62d00e31f86..76d170ac3bd51d38e026b85bf363b7c2442721fe 100644 (file)
@@ -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) {
index 976ea71ae0754c99e1ad3949bf1d2910811ffdb0..a8333648e6d7e707d4a0b6ec9e7a9f7051b20762 100644 (file)
  */
 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;
   }
index 809e3d7c3eca88ad1384e765cf4f00e6e39be3be..e3adbf59c28a7eeb13ba4a0eb84ce57e20453d3d 100644 (file)
@@ -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());
+  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistLiveMeasuresStepTest.java
new file mode 100644 (file)
index 0000000..1a0f07d
--- /dev/null
@@ -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);
+  }
+
+}
index 61d0099b1576b2d977ffd781ce63dbe61b22641c..36be1d480af5b6b3d1f91fad9020c68d30031be5 100644 (file)
@@ -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);
   }
 }
index c00e6f7f18bae4f3c228944d3480a79118a0b612..b337a109258bea68c800952c2351a581958c5e72 100644 (file)
@@ -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();
index 82468f874c4115c7000eec9988a781484d2a4a7a..026a92eb616419390989114773db76cbf284801b 100644 (file)
@@ -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);
+  }
 }
index c5ab5886cdab6c97fb7851d33382c02123be27f0..8909b85dd04d232cd01a94d6a45b556c80364d7c 100644 (file)
@@ -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)
index 839a9c05864bb902a197b393e481a8823ade5bb8..438ca643ee61ee1f7d70b950d9dfece289b48eb4 100644 (file)
@@ -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);
 
index 535eeb756967fc159139ebd439006405603a165c..0ed7e63c25cf946d4d19e732e2e15c53e52b7688 100644 (file)
 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));
-  }
 }
index f778f3fdac04ae681e5159873bec0c7349e2eec2..1544e8a77b3651a954e92b6be5ad890bc4147d64 100644 (file)
@@ -264,20 +264,6 @@ public class SearchHistoryActionTest {
     assertThat(result.getPaging().getTotal()).isEqualTo(1);
   }
 
-  @Test
-  public void do_not_return_developer_measures() {
-    wsRequest.setMetrics(singletonList(complexityMetric.getKey()));
-    dbClient.measureDao().insert(dbSession, newMeasureDto(complexityMetric, project, analysis).setDeveloperId(42L));
-    db.commit();
-
-    SearchHistoryResponse result = call();
-
-    assertThat(result.getMeasuresCount()).isEqualTo(1);
-    assertThat(result.getMeasures(0).getHistoryCount()).isEqualTo(1);
-    assertThat(result.getMeasures(0).getHistory(0).hasDate()).isTrue();
-    assertThat(result.getMeasures(0).getHistory(0).hasValue()).isFalse();
-  }
-
   @Test
   public void branch() {
     ComponentDto project = db.components().insertPrivateProject();
index d0d986e8b0e37e9d04f0c0caa57919f86bca2f23..14148994fcececb132452f87becd1738436ac6b8 100644 (file)
@@ -52,7 +52,7 @@ import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
 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.measure.MeasureTesting.newLiveMeasure;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.db.user.UserTesting.newUserDto;
 import static org.sonar.test.JsonAssert.assertJson;
@@ -95,8 +95,8 @@ public class SearchMyProjectsActionTest {
     long anotherTime = DateUtils.parseDateTime("2016-06-11T14:25:53+0000").getTime();
     SnapshotDto jdk7Snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(jdk7).setCreatedAt(oneTime));
     SnapshotDto cLangSnapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(cLang).setCreatedAt(anotherTime));
-    dbClient.measureDao().insert(dbSession, newMeasureDto(alertStatusMetric, jdk7, jdk7Snapshot).setData(Level.ERROR.name()));
-    dbClient.measureDao().insert(dbSession, newMeasureDto(alertStatusMetric, cLang, cLangSnapshot).setData(Level.OK.name()));
+    dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(jdk7, alertStatusMetric).setData(Level.ERROR.name()));
+    dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(cLang, alertStatusMetric).setData(Level.OK.name()));
     db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7);
     db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, cLang);
     db.commit();
index 2bf2c728243d7e32531aec0b5a0e37ed7f723a67..242bbc6b553bef43376af3adde0ef0ecb3ad1aa6 100644 (file)
@@ -51,6 +51,7 @@ import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
+import static org.sonar.db.measure.MeasureTesting.newLiveMeasure;
 import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.test.JsonAssert.assertJson;
@@ -71,17 +72,22 @@ public class ProjectStatusActionTest {
   private WsActionTester ws;
   private DbClient dbClient;
   private DbSession dbSession;
+  private MetricDto gateDetailsMetric;
 
   @Before
   public void setUp() {
     dbClient = db.getDbClient();
     dbSession = db.getSession();
 
+    gateDetailsMetric = dbClient.metricDao().insert(dbSession, newMetricDto()
+      .setEnabled(true)
+      .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
+
     ws = new WsActionTester(new ProjectStatusAction(dbClient, TestComponentFinder.from(db), userSession));
   }
 
   @Test
-  public void definition() throws Exception {
+  public void test_definition() throws Exception {
     WebService.Action def = ws.getDef();
     assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("analysisId", "projectKey", "projectId");
     assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactly(
@@ -90,7 +96,7 @@ public class ProjectStatusActionTest {
   }
 
   @Test
-  public void json_example() throws IOException {
+  public void test_json_example() throws IOException {
     ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
     userSession.addProjectPermission(UserRole.USER, project);
 
@@ -98,11 +104,8 @@ public class ProjectStatusActionTest {
       .setPeriodMode("last_version")
       .setPeriodParam("2015-12-07")
       .setPeriodDate(956789123987L));
-    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setEnabled(true)
-      .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
     dbClient.measureDao().insert(dbSession,
-      newMeasureDto(metric, project, snapshot)
+      newMeasureDto(gateDetailsMetric, project, snapshot)
         .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
     dbSession.commit();
 
@@ -114,17 +117,43 @@ public class ProjectStatusActionTest {
   }
 
   @Test
-  public void return_status_by_project_id() throws IOException {
+  public void return_past_status_when_project_is_referenced_by_past_analysis_id() throws IOException {
     ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
-    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
+    SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
+      .setLast(false)
       .setPeriodMode("last_version")
       .setPeriodParam("2015-12-07")
       .setPeriodDate(956789123987L));
-    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setEnabled(true)
-      .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
+    SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
+      .setLast(true)
+      .setPeriodMode("last_version")
+      .setPeriodParam("2016-12-07")
+      .setPeriodDate(1_500L));
     dbClient.measureDao().insert(dbSession,
-      newMeasureDto(metric, project, snapshot)
+      newMeasureDto(gateDetailsMetric, project, pastAnalysis)
+        .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
+    dbClient.measureDao().insert(dbSession,
+      newMeasureDto(gateDetailsMetric, project, lastAnalysis)
+        .setData("not_used"));
+    dbSession.commit();
+    userSession.addProjectPermission(UserRole.USER, project);
+
+    String response = ws.newRequest()
+      .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
+      .execute().getInput();
+
+    assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
+  }
+
+  @Test
+  public void return_live_status_when_project_is_referenced_by_its_id() throws IOException {
+    ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
+      .setPeriodMode("last_version")
+      .setPeriodParam("2015-12-07")
+      .setPeriodDate(956789123987L));
+    dbClient.liveMeasureDao().insert(dbSession,
+      newLiveMeasure(project, gateDetailsMetric)
         .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
     dbSession.commit();
     userSession.addProjectPermission(UserRole.USER, project);
@@ -137,17 +166,14 @@ public class ProjectStatusActionTest {
   }
 
   @Test
-  public void return_status_by_project_key() throws IOException {
+  public void return_live_status_when_project_is_referenced_by_its_key() throws IOException {
     ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("project-key"));
-    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
       .setPeriodMode("last_version")
       .setPeriodParam("2015-12-07")
       .setPeriodDate(956789123987L));
-    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setEnabled(true)
-      .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
-    dbClient.measureDao().insert(dbSession,
-      newMeasureDto(metric, project, snapshot)
+    dbClient.liveMeasureDao().insert(dbSession,
+      newLiveMeasure(project, gateDetailsMetric)
         .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
     dbSession.commit();
     userSession.addProjectPermission(UserRole.USER, project);
@@ -160,24 +186,24 @@ public class ProjectStatusActionTest {
   }
 
   @Test
-  public void return_undefined_status_if_measure_is_not_found() {
+  public void return_undefined_status_if_specified_analysis_is_not_found() {
     ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
     SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
     dbSession.commit();
     userSession.addProjectPermission(UserRole.USER, project);
 
-    ProjectStatusResponse result = call(snapshot.getUuid());
+    ProjectStatusResponse result = callByAnalysisId(snapshot.getUuid());
 
     assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
     assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
   }
 
   @Test
-  public void return_undefined_status_if_snapshot_is_not_found() {
+  public void return_undefined_status_if_project_is_not_analyzed() {
     ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
     userSession.addProjectPermission(UserRole.USER, project);
 
-    ProjectStatusResponse result = callByProjectUuid(project.uuid());
+    ProjectStatusResponse result = callByProjectId(project.uuid());
 
     assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
     assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
@@ -190,7 +216,7 @@ public class ProjectStatusActionTest {
     dbSession.commit();
     userSession.addProjectPermission(UserRole.ADMIN, project);
 
-    call(snapshot.getUuid());
+    callByAnalysisId(snapshot.getUuid());
   }
 
   @Test
@@ -200,7 +226,7 @@ public class ProjectStatusActionTest {
     dbSession.commit();
     userSession.addProjectPermission(UserRole.USER, project);
 
-    call(snapshot.getUuid());
+    callByAnalysisId(snapshot.getUuid());
   }
 
   @Test
@@ -210,7 +236,7 @@ public class ProjectStatusActionTest {
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Analysis with id 'task-uuid' is not found");
 
-    call(ANALYSIS_ID);
+    callByAnalysisId(ANALYSIS_ID);
   }
 
   @Test
@@ -222,7 +248,7 @@ public class ProjectStatusActionTest {
 
     expectedException.expect(ForbiddenException.class);
 
-    call(snapshot.getUuid());
+    callByAnalysisId(snapshot.getUuid());
   }
 
   @Test
@@ -280,13 +306,13 @@ public class ProjectStatusActionTest {
       .execute();
   }
 
-  private ProjectStatusResponse call(String taskId) {
+  private ProjectStatusResponse callByAnalysisId(String taskId) {
     return ws.newRequest()
-      .setParam("analysisId", taskId)
+      .setParam(PARAM_ANALYSIS_ID, taskId)
       .executeProtobuf(ProjectStatusResponse.class);
   }
 
-  private ProjectStatusResponse callByProjectUuid(String projectUuid) {
+  private ProjectStatusResponse callByProjectId(String projectUuid) {
     return ws.newRequest()
       .setParam(PARAM_PROJECT_ID, projectUuid)
       .executeProtobuf(ProjectStatusResponse.class);
index 62f96974cf865c1131d3a7836f64c49503d566f6..816bac90633180e63f95a06210c29b0e825a930c 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.server.qualitygate.ws;
 
-import com.google.common.base.Optional;
 import java.io.IOException;
 import java.util.List;
+import java.util.Optional;
 import javax.annotation.Nullable;
 import org.apache.commons.io.IOUtils;
 import org.junit.Rule;
@@ -150,6 +150,6 @@ public class QualityGateDetailsFormatterTest {
   }
 
   private static QualityGateDetailsFormatter newQualityGateDetailsFormatter(@Nullable String measureData, @Nullable SnapshotDto snapshotDto) {
-    return new QualityGateDetailsFormatter(Optional.fromNullable(measureData), Optional.fromNullable(snapshotDto));
+    return new QualityGateDetailsFormatter(Optional.ofNullable(measureData), Optional.ofNullable(snapshotDto));
   }
 }
index b62eef280f183406fa74b5e7af8a07f19f86448b..f82a9649e93b5c988025d188e33184cb03996e75 100644 (file)
@@ -41,7 +41,6 @@ import org.sonar.core.platform.PluginRepository;
 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.metric.MetricDto;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.measure.index.ProjectMeasuresIndex;
@@ -126,18 +125,16 @@ public class TelemetryDaemonTest {
 
     ComponentDto project1 = db.components().insertMainBranch(db.getDefaultOrganization());
     ComponentDto project1Branch = db.components().insertProjectBranch(project1);
-    SnapshotDto analysis1 = db.components().insertSnapshot(project1);
-    db.measures().insertMeasure(project1, analysis1, lines, m -> m.setValue(200d));
-    db.measures().insertMeasure(project1, analysis1, ncloc, m -> m.setValue(100d));
-    db.measures().insertMeasure(project1, analysis1, coverage, m -> m.setValue(80d));
-    db.measures().insertMeasure(project1, analysis1, nclocDistrib, m -> m.setData("java=200;js=50"));
+    db.measures().insertLiveMeasure(project1, lines, m -> m.setValue(200d));
+    db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(100d));
+    db.measures().insertLiveMeasure(project1, coverage, m -> m.setValue(80d));
+    db.measures().insertLiveMeasure(project1, nclocDistrib, m -> m.setValue(null).setData("java=200;js=50"));
 
     ComponentDto project2 = db.components().insertMainBranch(db.getDefaultOrganization());
-    SnapshotDto analysis2 = db.components().insertSnapshot(project2);
-    db.measures().insertMeasure(project2, analysis2, lines, m -> m.setValue(300d));
-    db.measures().insertMeasure(project2, analysis2, ncloc, m -> m.setValue(200d));
-    db.measures().insertMeasure(project2, analysis2, coverage, m -> m.setValue(80d));
-    db.measures().insertMeasure(project2, analysis2, nclocDistrib, m -> m.setData("java=300;kotlin=2500"));
+    db.measures().insertLiveMeasure(project2, lines, m -> m.setValue(300d));
+    db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(200d));
+    db.measures().insertLiveMeasure(project2, coverage, m -> m.setValue(80d));
+    db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=300;kotlin=2500"));
     projectMeasuresIndexer.indexOnStartup(emptySet());
 
     underTest.start();
@@ -173,12 +170,9 @@ public class TelemetryDaemonTest {
     ComponentDto project = db.components().insertMainBranch(db.getDefaultOrganization());
     ComponentDto longBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG));
     ComponentDto shortBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(SHORT));
-    SnapshotDto projectAnalysis = db.components().insertSnapshot(project);
-    SnapshotDto longBranchAnalysis = db.components().insertSnapshot(longBranch);
-    SnapshotDto shortBranchAnalysis = db.components().insertSnapshot(shortBranch);
-    db.measures().insertMeasure(project, projectAnalysis, ncloc, m -> m.setValue(10d));
-    db.measures().insertMeasure(longBranch, longBranchAnalysis, ncloc, m -> m.setValue(20d));
-    db.measures().insertMeasure(shortBranch, shortBranchAnalysis, ncloc, m -> m.setValue(30d));
+    db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(10d));
+    db.measures().insertLiveMeasure(longBranch, ncloc, m -> m.setValue(20d));
+    db.measures().insertLiveMeasure(shortBranch, ncloc, m -> m.setValue(30d));
     projectMeasuresIndexer.indexOnStartup(emptySet());
 
     underTest.start();
index 536795e12b1273365fb54b1831ab34cd01a95e93..6c37665343490b82e326eb32f8be7f9d1ab81b09 100644 (file)
@@ -76,7 +76,7 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
-import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
+import static org.sonar.db.measure.MeasureTesting.newLiveMeasure;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
@@ -262,8 +262,7 @@ public class ComponentActionTest {
   public void return_quality_profiles() throws Exception {
     init();
     componentDbTester.insertComponent(project);
-    SnapshotDto analysis = componentDbTester.insertSnapshot(newAnalysis(project));
-    addQualityProfiles(project, analysis,
+    addQualityProfiles(project,
       createQProfile("qp1", "Sonar Way Java", "java"),
       createQProfile("qp2", "Sonar Way Xoo", "xoo"));
     userSession.addProjectPermission(UserRole.USER, project);
@@ -329,7 +328,7 @@ public class ComponentActionTest {
       .build();
 
     init(page);
-    ComponentDto application = componentDbTester.insertApplication(dbTester.getDefaultOrganization());
+    ComponentDto application = componentDbTester.insertPublicApplication(dbTester.getDefaultOrganization());
     userSession.registerComponents(application);
 
     String result = ws.newRequest()
@@ -471,7 +470,7 @@ public class ComponentActionTest {
     when(resourceTypes.get(project.qualifier())).thenReturn(DefaultResourceTypes.get().getRootType());
     UserDto user = dbTester.users().insertUser("obiwan");
     propertyDbTester.insertProperty(new PropertyDto().setKey("favourite").setResourceId(project.getId()).setUserId(user.getId()));
-    addQualityProfiles(project, analysis,
+    addQualityProfiles(project,
       createQProfile("qp1", "Sonar Way Java", "java"),
       createQProfile("qp2", "Sonar Way Xoo", "xoo"));
     QualityGateDto qualityGateDto = dbTester.qualityGates().insertQualityGate("Sonar way");
@@ -580,11 +579,11 @@ public class ComponentActionTest {
     verify(execute(componentKey), expectedJson);
   }
 
-  private void addQualityProfiles(ComponentDto project, SnapshotDto analysis, QualityProfile... qps) {
-    MetricDto metricDto = newMetricDto().setKey(QUALITY_PROFILES_KEY);
-    dbClient.metricDao().insert(dbTester.getSession(), metricDto);
-    dbClient.measureDao().insert(dbTester.getSession(),
-      newMeasureDto(metricDto, project, analysis)
+  private void addQualityProfiles(ComponentDto project, QualityProfile... qps) {
+    MetricDto metric = newMetricDto().setKey(QUALITY_PROFILES_KEY);
+    dbClient.metricDao().insert(dbTester.getSession(), metric);
+    dbClient.liveMeasureDao().insert(dbTester.getSession(),
+      newLiveMeasure(project, metric)
         .setData(qualityProfilesToJson(qps)));
     dbTester.commit();
   }
index 58dec513e1661276b2e1af7311538aa1cdba0171..2d9eceb41905aaa39ea2e45b256157f18e213371 100644 (file)
@@ -60,7 +60,6 @@ public class Measure<G extends Serializable> implements Serializable {
   protected Double variation4;
   protected Double variation5;
   protected String url;
-  protected Integer personId;
   protected PersistenceMode persistenceMode = PersistenceMode.FULL;
 
   public Measure(String metricKey) {
@@ -609,17 +608,20 @@ public class Measure<G extends Serializable> implements Serializable {
 
   /**
    * @since 2.14
+   * @deprecated in 6.5 with end of support of Developer cockpit plugin. Always return {@code null}.
    */
   @CheckForNull
+  @Deprecated
   public Integer getPersonId() {
-    return personId;
+    return null;
   }
 
   /**
    * @since 2.14
+   * @deprecated in 6.5 with end of support of Developer cockpit plugin.
    */
+  @Deprecated
   public Measure<G> setPersonId(@Nullable Integer i) {
-    this.personId = i;
     return this;
   }
 
@@ -663,17 +665,12 @@ public class Measure<G extends Serializable> implements Serializable {
     }
 
     Measure measure = (Measure) o;
-    if (metricKey != null ? !metricKey.equals(measure.metricKey) : (measure.metricKey != null)) {
-      return false;
-    }
-    return !(personId != null ? !personId.equals(measure.personId) : (measure.personId != null));
+    return metricKey != null ? metricKey.equals(measure.metricKey) : (measure.metricKey == null);
   }
 
   @Override
   public int hashCode() {
-    int result = metricKey != null ? metricKey.hashCode() : 0;
-    result = 31 * result + (personId != null ? personId.hashCode() : 0);
-    return result;
+    return metricKey != null ? metricKey.hashCode() : 0;
   }
 
   @Override
index 7049e46d8520462ad8b8a0c10d6fe8bd036fbc0f..37bc32af4ab9e07b66d64c46e1e2dbfeeeb63f25 100644 (file)
@@ -64,8 +64,7 @@ public final class MeasuresFilters {
         }
         for (Measure measure : measures) {
           if (measure.getClass().equals(Measure.class) &&
-            measure.getMetricKey().equals(metricKey) &&
-            measure.getPersonId() == null) {
+            measure.getMetricKey().equals(metricKey)) {
             return measure;
           }
         }
@@ -107,7 +106,7 @@ public final class MeasuresFilters {
 
       private boolean apply(Measure measure) {
         return measure instanceof RuleMeasure && metric.equals(measure.getMetric())
-          && measure.getPersonId() == null && ((RuleMeasure) measure).ruleKey() != null;
+          && ((RuleMeasure) measure).ruleKey() != null;
       }
 
       @Override
@@ -157,7 +156,6 @@ public final class MeasuresFilters {
     private boolean apply(Measure measure) {
       return measure instanceof RuleMeasure
         && filterOnMetricKey().equals(measure.getMetricKey())
-        && measure.getPersonId() == null
         && doApply((RuleMeasure) measure);
     }
 
index 26abdc18b84196fb117277edfb9a010cffd6c6c9..6956b04b490eb1db870839171d0ac44cb0dabf0a 100644 (file)
@@ -133,7 +133,6 @@ public class RuleMeasure extends Measure {
     RuleMeasure other = (RuleMeasure) obj;
     return new EqualsBuilder()
       .append(getMetric(), other.getMetric())
-      .append(personId, other.personId)
       .append(ruleKey, other.ruleKey)
       .isEquals();
   }
@@ -147,7 +146,6 @@ public class RuleMeasure extends Measure {
   public int hashCode() {
     return new HashCodeBuilder(17, 37)
       .append(getMetric())
-      .append(personId)
       .append(ruleKey)
       .toHashCode();
   }
@@ -156,7 +154,6 @@ public class RuleMeasure extends Measure {
   public String toString() {
     return new ToStringBuilder(this)
       .append("metric", metric)
-      .append("personId", personId)
       .append("ruleKey", ruleKey)
       .append("value", value)
       .append("data", data)
index af76fcdc2f5e6132dce0385eea4083b6a9eae588..8e3d97f865850c419df79d732860920cd7f574ed 100644 (file)
@@ -114,23 +114,6 @@ public class MeasureTest {
     assertThat(measure2.equals(measure1)).isTrue();
     assertThat(measure1.hashCode()).isEqualTo(measure2.hashCode());
 
-    // different committer
-    measure1.setPersonId(1);
-    assertThat(measure1.equals(measure2)).isFalse();
-    assertThat(measure2.equals(measure1)).isFalse();
-    assertThat(measure1.hashCode()).isNotEqualTo(measure2.hashCode());
-
-    measure2.setPersonId(2);
-    assertThat(measure1.equals(measure2)).isFalse();
-    assertThat(measure2.equals(measure1)).isFalse();
-    assertThat(measure1.hashCode()).isNotEqualTo(measure2.hashCode());
-
-    // same committer
-    measure2.setPersonId(1);
-    assertThat(measure1.equals(measure2)).isTrue();
-    assertThat(measure2.equals(measure1)).isTrue();
-    assertThat(measure1.hashCode()).isEqualTo(measure2.hashCode());
-
     // value doesn't matter
     measure1.setValue(1.0);
     measure2.setValue(2.0);
index 7a9fbafcd542b115822752241c0dea9199e77e11..9d09abf7dfb26f50cddfb7266547aa8aeb59d8ad 100644 (file)
@@ -344,7 +344,7 @@ public class ItUtils {
   @CheckForNull
   public static Measure getMeasureWithVariation(Orchestrator orchestrator, String componentKey, String metricKey) {
     Measures.ComponentWsResponse response = newWsClient(orchestrator).measures().component(new ComponentRequest()
-      .setComponentKey(componentKey)
+      .setComponent(componentKey)
       .setMetricKeys(singletonList(metricKey))
       .setAdditionalFields(singletonList("periods")));
     List<Measure> measures = response.getComponent().getMeasuresList();