From 38fed3b7af236c197c8caaeee618051c112f6c5b Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 8 Jun 2015 15:13:15 +0200 Subject: [PATCH] SONAR-6260 Persist snapshots with periods --- .../step/PersistSnapshotsStep.java | 30 ++- .../computation/period/PeriodsHolderRule.java | 58 ++++++ ...est.java => PersistSnapshotsStepTest.java} | 172 ++++++++++++++++-- 3 files changed, 239 insertions(+), 21 deletions(-) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderRule.java rename server/sonar-server/src/test/java/org/sonar/server/computation/step/{PersistSnapshotStepTest.java => PersistSnapshotsStepTest.java} (69%) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSnapshotsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSnapshotsStep.java index df2111a9644..f1d8e251758 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSnapshotsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSnapshotsStep.java @@ -31,6 +31,8 @@ import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.DbIdsRepository; import org.sonar.server.computation.component.TreeRootHolder; +import org.sonar.server.computation.period.Period; +import org.sonar.server.computation.period.PeriodsHolder; import org.sonar.server.db.DbClient; /** @@ -43,15 +45,17 @@ public class PersistSnapshotsStep implements ComputationStep { private final DbClient dbClient; private final TreeRootHolder treeRootHolder; private final BatchReportReader reportReader; - private final DbIdsRepository dbIdsRepository; + private final PeriodsHolder periodsHolder; - public PersistSnapshotsStep(System2 system2, DbClient dbClient, TreeRootHolder treeRootHolder, BatchReportReader reportReader, DbIdsRepository dbIdsRepository) { + public PersistSnapshotsStep(System2 system2, DbClient dbClient, TreeRootHolder treeRootHolder, BatchReportReader reportReader, DbIdsRepository dbIdsRepository, + PeriodsHolder periodsHolder) { this.system2 = system2; this.dbClient = dbClient; this.treeRootHolder = treeRootHolder; this.reportReader = reportReader; this.dbIdsRepository = dbIdsRepository; + this.periodsHolder = periodsHolder; } @Override @@ -88,22 +92,22 @@ public class PersistSnapshotsStep implements ComputationStep { switch (component.getType()) { case PROJECT: this.projectId = componentId; - SnapshotDto projectSnapshot = persistSnapshot(componentId, Qualifiers.PROJECT, Scopes.PROJECT, reportComponent.getVersion(), parentSnapshot); + SnapshotDto projectSnapshot = persistSnapshot(componentId, Qualifiers.PROJECT, Scopes.PROJECT, reportComponent.getVersion(), parentSnapshot, true); addToCache(component, projectSnapshot); processChildren(component, projectSnapshot); break; case MODULE: - SnapshotDto moduleSnapshot = persistSnapshot(componentId, Qualifiers.MODULE, Scopes.PROJECT, reportComponent.getVersion(), parentSnapshot); + SnapshotDto moduleSnapshot = persistSnapshot(componentId, Qualifiers.MODULE, Scopes.PROJECT, reportComponent.getVersion(), parentSnapshot, true); addToCache(component, moduleSnapshot); processChildren(component, moduleSnapshot); break; case DIRECTORY: - SnapshotDto directorySnapshot = persistSnapshot(componentId, Qualifiers.DIRECTORY, Scopes.DIRECTORY, null, parentSnapshot); + SnapshotDto directorySnapshot = persistSnapshot(componentId, Qualifiers.DIRECTORY, Scopes.DIRECTORY, null, parentSnapshot, false); addToCache(component, directorySnapshot); processChildren(component, directorySnapshot); break; case FILE: - SnapshotDto fileSnapshot = persistSnapshot(componentId, getFileQualifier(reportComponent), Scopes.FILE, null, parentSnapshot); + SnapshotDto fileSnapshot = persistSnapshot(componentId, getFileQualifier(reportComponent), Scopes.FILE, null, parentSnapshot, false); addToCache(component, fileSnapshot); break; default: @@ -117,7 +121,7 @@ public class PersistSnapshotsStep implements ComputationStep { } } - private SnapshotDto persistSnapshot(long componentId, String qualifier, String scope, @Nullable String version, @Nullable SnapshotDto parentSnapshot) { + private SnapshotDto persistSnapshot(long componentId, String qualifier, String scope, @Nullable String version, @Nullable SnapshotDto parentSnapshot, boolean setPeriods) { SnapshotDto snapshotDto = new SnapshotDto() .setRootProjectId(projectId) .setVersion(version) @@ -128,6 +132,9 @@ public class PersistSnapshotsStep implements ComputationStep { .setStatus(SnapshotDto.STATUS_UNPROCESSED) .setCreatedAt(analysisDate) .setBuildDate(system2.now()); + if (setPeriods) { + updateSnapshotPeriods(snapshotDto); + } if (parentSnapshot != null) { snapshotDto @@ -144,6 +151,15 @@ public class PersistSnapshotsStep implements ComputationStep { return snapshotDto; } + private void updateSnapshotPeriods(SnapshotDto snapshotDto) { + for (Period period : periodsHolder.getPeriods()) { + int index = period.getIndex(); + snapshotDto.setPeriodMode(index, period.getMode()); + snapshotDto.setPeriodParam(index, period.getModeParameter()); + snapshotDto.setPeriodDate(index, period.getSnapshotDate()); + } + } + private void addToCache(Component component, SnapshotDto snapshotDto) { dbIdsRepository.setSnapshotId(component, snapshotDto.getId()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderRule.java new file mode 100644 index 00000000000..a13a20e84cb --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderRule.java @@ -0,0 +1,58 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.period; + +import java.util.ArrayList; +import java.util.List; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class PeriodsHolderRule implements TestRule, PeriodsHolder { + private List periods = new ArrayList<>(); + + @Override + public Statement apply(final Statement statement, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + statement.evaluate(); + } finally { + clear(); + } + } + }; + } + + private void clear() { + this.periods = new ArrayList<>(); + } + + @Override + public List getPeriods() { + return periods; + } + + public void addPeriod(Period period) { + this.periods.add(period); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotsStepTest.java similarity index 69% rename from server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotStepTest.java rename to server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotsStepTest.java index c176c66f4b1..5384ad62956 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSnapshotsStepTest.java @@ -20,7 +20,6 @@ package org.sonar.server.computation.step; -import java.text.SimpleDateFormat; import java.util.List; import org.junit.After; import org.junit.Before; @@ -28,6 +27,9 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; import org.sonar.batch.protocol.Constants; import org.sonar.batch.protocol.output.BatchReport; @@ -37,6 +39,7 @@ import org.sonar.core.component.SnapshotQuery; import org.sonar.core.persistence.DbSession; import org.sonar.core.persistence.DbTester; import org.sonar.server.component.ComponentTesting; +import org.sonar.server.component.SnapshotTesting; import org.sonar.server.component.db.ComponentDao; import org.sonar.server.component.db.SnapshotDao; import org.sonar.server.computation.batch.BatchReportReaderRule; @@ -44,6 +47,8 @@ import org.sonar.server.computation.batch.TreeRootHolderRule; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.DbIdsRepository; import org.sonar.server.computation.component.DumbComponent; +import org.sonar.server.computation.period.Period; +import org.sonar.server.computation.period.PeriodsHolderRule; import org.sonar.server.db.DbClient; import org.sonar.test.DbTests; @@ -52,9 +57,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Category(DbTests.class) -public class PersistSnapshotStepTest extends BaseStepTest { - - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); +public class PersistSnapshotsStepTest extends BaseStepTest { private static final String PROJECT_KEY = "PROJECT_KEY"; @@ -67,10 +70,15 @@ public class PersistSnapshotStepTest extends BaseStepTest { @Rule public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + @Rule + public PeriodsHolderRule periodsHolderRule = new PeriodsHolderRule(); + System2 system2 = mock(System2.class); DbIdsRepository dbIdsRepository; + Settings settings = new Settings(); + DbSession session; DbClient dbClient; @@ -87,17 +95,17 @@ public class PersistSnapshotStepTest extends BaseStepTest { session = dbTester.myBatis().openSession(false); dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao()); - analysisDate = DATE_FORMAT.parse("2015-06-01").getTime(); + analysisDate = DateUtils.parseDateQuietly("2015-06-01").getTime(); reportReader.setMetadata(BatchReport.Metadata.newBuilder() .setAnalysisDate(analysisDate) .build()); dbIdsRepository = new DbIdsRepository(); - now = DATE_FORMAT.parse("2015-06-02").getTime(); + now = DateUtils.parseDateQuietly("2015-06-02").getTime(); when(system2.now()).thenReturn(now); - sut = new PersistSnapshotsStep(system2, dbClient, treeRootHolder, reportReader, dbIdsRepository); + sut = new PersistSnapshotsStep(system2, dbClient, treeRootHolder, reportReader, dbIdsRepository, periodsHolderRule); } @Override @@ -307,11 +315,6 @@ public class PersistSnapshotStepTest extends BaseStepTest { Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, moduleA, moduleB); treeRootHolder.setRoot(project); - treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, - new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_A", - new DumbComponent(Component.Type.MODULE, 3, "DEFG", "SUB_MODULE_A")), - new DumbComponent(Component.Type.MODULE, 4, "CDEF", "MODULE_B"))); - dbIdsRepository.setComponentId(project, projectDto.getId()); dbIdsRepository.setComponentId(moduleA, moduleADto.getId()); dbIdsRepository.setComponentId(subModuleA, subModuleADto.getId()); @@ -347,10 +350,151 @@ public class PersistSnapshotStepTest extends BaseStepTest { assertThat(moduleBSnapshot.getRootId()).isEqualTo(projectSnapshot.getId()); assertThat(moduleBSnapshot.getParentId()).isEqualTo(projectSnapshot.getId()); assertThat(moduleBSnapshot.getDepth()).isEqualTo(1); - assertThat(moduleBSnapshot.getPath()).isEqualTo(projectSnapshot.getId() + "." ); + assertThat(moduleBSnapshot.getPath()).isEqualTo(projectSnapshot.getId() + "."); + } + + @Test + public void persist_snapshots_with_periods() throws Exception { + ComponentDto projectDto = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project"); + dbClient.componentDao().insert(session, projectDto); + SnapshotDto snapshotDto = SnapshotTesting.createForProject(projectDto).setCreatedAt(DateUtils.parseDateQuietly("2015-01-01").getTime()); + dbClient.snapshotDao().insert(session, snapshotDto); + session.commit(); + periodsHolderRule.addPeriod(new Period(1, CoreProperties.TIMEMACHINE_MODE_DATE, "2015-01-01", analysisDate)); + + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey(PROJECT_KEY) + .setName("Project") + .setVersion("1.0") + .addChildRef(2) + .build()); + + Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY); + treeRootHolder.setRoot(project); + dbIdsRepository.setComponentId(project, projectDto.getId()); + + sut.execute(); + + SnapshotDto projectSnapshot = getUnprocessedSnapshot(projectDto.getId()); + assertThat(projectSnapshot.getPeriodMode(1)).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DATE); + assertThat(projectSnapshot.getPeriodDate(1)).isEqualTo(analysisDate); + assertThat(projectSnapshot.getPeriodModeParameter(1)).isNotNull(); + } + + @Test + public void only_persist_snapshots_with_periods_on_project_and_module() throws Exception { + periodsHolderRule.addPeriod(new Period(1, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, null, analysisDate)); + + ComponentDto projectDto = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project"); + dbClient.componentDao().insert(session, projectDto); + SnapshotDto projectSnapshot = SnapshotTesting.createForProject(projectDto); + dbClient.snapshotDao().insert(session, projectSnapshot); + + ComponentDto moduleDto = ComponentTesting.newModuleDto("BCDE", projectDto).setKey("MODULE_KEY").setName("Module"); + dbClient.componentDao().insert(session, moduleDto); + SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(moduleDto, projectSnapshot); + dbClient.snapshotDao().insert(session, moduleSnapshot); + + ComponentDto directoryDto = ComponentTesting.newDirectory(moduleDto, "CDEF", "MODULE_KEY:src/main/java/dir").setKey("MODULE_KEY:src/main/java/dir"); + dbClient.componentDao().insert(session, directoryDto); + SnapshotDto directorySnapshot = SnapshotTesting.createForComponent(directoryDto, moduleSnapshot); + dbClient.snapshotDao().insert(session, directorySnapshot); + + ComponentDto fileDto = ComponentTesting.newFileDto(moduleDto, "DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java"); + dbClient.componentDao().insert(session, fileDto); + SnapshotDto fileSnapshot = SnapshotTesting.createForComponent(fileDto, directorySnapshot); + dbClient.snapshotDao().insert(session, fileSnapshot); + + session.commit(); + + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey(PROJECT_KEY) + .setName("Project") + .setVersion("1.0") + .addChildRef(2) + .build()); + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setPath("module") + .setName("Module") + .setVersion("1.1") + .addChildRef(3) + .build()); + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(4) + .build()); + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .setLanguage("java") + .build()); + + Component file = new DumbComponent(Component.Type.FILE, 4, "DEFG", "MODULE_KEY:src/main/java/dir/Foo.java"); + Component directory = new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "MODULE_KEY:src/main/java/dir", file); + Component module = new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY", directory); + Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, module); + treeRootHolder.setRoot(project); + + dbIdsRepository.setComponentId(project, projectDto.getId()); + dbIdsRepository.setComponentId(module, moduleDto.getId()); + dbIdsRepository.setComponentId(directory, directoryDto.getId()); + dbIdsRepository.setComponentId(file, fileDto.getId()); + + sut.execute(); + + SnapshotDto newProjectSnapshot = getUnprocessedSnapshot(projectDto.getId()); + assertThat(newProjectSnapshot.getPeriodMode(1)).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS); + + SnapshotDto newModuleSnapshot = getUnprocessedSnapshot(moduleDto.getId()); + assertThat(newModuleSnapshot.getPeriodMode(1)).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS); + + SnapshotDto newDirectorySnapshot = getUnprocessedSnapshot(directoryDto.getId()); + assertThat(newDirectorySnapshot.getPeriodMode(1)).isNull(); + + SnapshotDto newFileSnapshot = getUnprocessedSnapshot(fileDto.getId()); + assertThat(newFileSnapshot.getPeriodMode(1)).isNull(); + } + + @Test + public void set_no_period_on_snapshots_when_no_period() throws Exception { + ComponentDto projectDto = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project"); + dbClient.componentDao().insert(session, projectDto); + SnapshotDto snapshotDto = SnapshotTesting.createForProject(projectDto); + dbClient.snapshotDao().insert(session, snapshotDto); + session.commit(); + + reportReader.putComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey(PROJECT_KEY) + .setName("Project") + .setVersion("1.0") + .addChildRef(2) + .build()); + + Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY); + treeRootHolder.setRoot(project); + dbIdsRepository.setComponentId(project, projectDto.getId()); + + sut.execute(); + + SnapshotDto projectSnapshot = getUnprocessedSnapshot(projectDto.getId()); + assertThat(projectSnapshot.getPeriodMode(1)).isNull(); + assertThat(projectSnapshot.getPeriodDate(1)).isNull(); + assertThat(projectSnapshot.getPeriodModeParameter(1)).isNull(); } - private SnapshotDto getUnprocessedSnapshot(long componentId){ + private SnapshotDto getUnprocessedSnapshot(long componentId) { List projectSnapshots = dbClient.snapshotDao().selectSnapshotsByQuery(session, new SnapshotQuery().setComponentId(componentId).setIsLast(false).setStatus(SnapshotDto.STATUS_UNPROCESSED)); assertThat(projectSnapshots).hasSize(1); -- 2.39.5