@@ -51,7 +51,7 @@ import org.sonar.server.computation.language.PlatformLanguageRepository; | |||
import org.sonar.server.computation.measure.MeasureRepositoryImpl; | |||
import org.sonar.server.computation.measure.MetricCache; | |||
import org.sonar.server.computation.period.PeriodFinder; | |||
import org.sonar.server.computation.period.PeriodsRepository; | |||
import org.sonar.server.computation.period.PeriodsHolderImpl; | |||
import org.sonar.server.computation.step.ComputationStep; | |||
import org.sonar.server.computation.step.ComputationSteps; | |||
import org.sonar.server.view.index.ViewIndex; | |||
@@ -128,7 +128,7 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co | |||
MeasureRepositoryImpl.class, | |||
EventRepositoryImpl.class, | |||
ProjectSettingsRepository.class, | |||
PeriodsRepository.class, | |||
PeriodsHolderImpl.class, | |||
DbIdsRepository.class, | |||
// issues |
@@ -20,7 +20,6 @@ | |||
package org.sonar.server.computation.period; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
import javax.annotation.Nullable; | |||
@@ -86,8 +85,7 @@ public class Period { | |||
return this; | |||
} | |||
@VisibleForTesting | |||
Long getTargetDate() { | |||
public Long getTargetDate() { | |||
return targetDate; | |||
} | |||
@@ -47,7 +47,7 @@ public class PeriodFinder { | |||
} | |||
@CheckForNull | |||
Period findByDate(DbSession session, Long projectId, Date date) { | |||
public Period findByDate(DbSession session, Long projectId, Date date) { | |||
SnapshotDto snapshot = findFirstSnapshot(session, createCommonQuery(projectId).setCreatedAfter(date.getTime()).setSort(BY_DATE, ASC)); | |||
if (snapshot == null) { | |||
return null; | |||
@@ -56,7 +56,7 @@ public class PeriodFinder { | |||
} | |||
@CheckForNull | |||
Period findByDays(DbSession session, Long projectId, long analysisDate, int days) { | |||
public Period findByDays(DbSession session, Long projectId, long analysisDate, int days) { | |||
List<SnapshotDto> snapshots = dbClient.snapshotDao().selectSnapshotsByQuery(session, createCommonQuery(projectId).setCreatedBefore(analysisDate).setSort(BY_DATE, ASC)); | |||
long targetDate = DateUtils.addDays(new Date(analysisDate), -days).getTime(); | |||
SnapshotDto snapshot = findNearestSnapshotToTargetDate(snapshots, targetDate); | |||
@@ -67,7 +67,7 @@ public class PeriodFinder { | |||
} | |||
@CheckForNull | |||
Period findByPreviousAnalysis(DbSession session, Long projectId, long analysisDate) { | |||
public Period findByPreviousAnalysis(DbSession session, Long projectId, long analysisDate) { | |||
SnapshotDto snapshot = findFirstSnapshot(session, createCommonQuery(projectId).setCreatedBefore(analysisDate).setIsLast(true).setSort(BY_DATE, DESC)); | |||
if (snapshot == null) { | |||
return null; | |||
@@ -76,7 +76,7 @@ public class PeriodFinder { | |||
} | |||
@CheckForNull | |||
Period findByPreviousVersion(DbSession session, Long projectId, String version) { | |||
public Period findByPreviousVersion(DbSession session, Long projectId, String version) { | |||
List<SnapshotDto> snapshotDtos = dbClient.snapshotDao().selectPreviousVersionSnapshots(session, projectId, version); | |||
if (snapshotDtos.isEmpty()) { | |||
return null; | |||
@@ -86,7 +86,7 @@ public class PeriodFinder { | |||
} | |||
@CheckForNull | |||
Period findByVersion(DbSession session, Long projectId, String version) { | |||
public Period findByVersion(DbSession session, Long projectId, String version) { | |||
SnapshotDto snapshot = findFirstSnapshot(session, createCommonQuery(projectId).setVersion(version).setSort(BY_DATE, DESC)); | |||
if (snapshot == null) { | |||
return null; |
@@ -0,0 +1,37 @@ | |||
/* | |||
* 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.List; | |||
import org.sonar.api.CoreProperties; | |||
/** | |||
* Repository of periods used to compute differential measures. | |||
* Here are the steps to retrieve these periods : | |||
* - Read the 5 period properties ${@link CoreProperties#TIMEMACHINE_PERIOD_PREFIX} | |||
* - Try to find the matching snapshots from the properties | |||
* - If a snapshot is found, a new period is added to the repository | |||
*/ | |||
public interface PeriodsHolder { | |||
List<Period> getPeriods(); | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* 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 com.google.common.base.Preconditions; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class PeriodsHolderImpl implements PeriodsHolder { | |||
private boolean isPeriodsInitialized = false; | |||
private List<Period> periods = new ArrayList<>(); | |||
public void setPeriods(List<Period> periods) { | |||
this.periods = periods; | |||
isPeriodsInitialized = true; | |||
} | |||
@Override | |||
public List<Period> getPeriods() { | |||
Preconditions.checkArgument(isPeriodsInitialized, "Periods have not been initialized yet"); | |||
return periods; | |||
} | |||
} |
@@ -52,6 +52,7 @@ public class ComputationSteps { | |||
QualityGateEventsStep.class, | |||
// Persist data | |||
FeedPeriodsStep.class, | |||
PersistComponentsStep.class, | |||
PersistSnapshotsStep.class, | |||
PersistNumberOfDaysSinceLastCommitStep.class, |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.computation.period; | |||
package org.sonar.server.computation.step; | |||
import com.google.common.base.Strings; | |||
import java.text.ParseException; | |||
@@ -41,18 +41,21 @@ import org.sonar.core.persistence.DbSession; | |||
import org.sonar.server.computation.batch.BatchReportReader; | |||
import org.sonar.server.computation.component.Component; | |||
import org.sonar.server.computation.component.TreeRootHolder; | |||
import org.sonar.server.computation.period.Period; | |||
import org.sonar.server.computation.period.PeriodFinder; | |||
import org.sonar.server.computation.period.PeriodsHolderImpl; | |||
import org.sonar.server.db.DbClient; | |||
/** | |||
* Repository of periods used to compute differential measures. | |||
* Here are the steps to retrieve these periods : | |||
* Populates the {@link org.sonar.server.computation.period.PeriodsHolder} | |||
* | |||
* Here is how these periods are computed : | |||
* - Read the 5 period properties ${@link CoreProperties#TIMEMACHINE_PERIOD_PREFIX} | |||
* - Try to find the matching snapshots from the properties | |||
* - If a snapshot is found, a new period is added to the repository | |||
*/ | |||
public class PeriodsRepository { | |||
private static final Logger LOG = LoggerFactory.getLogger(PeriodsRepository.class); | |||
public class FeedPeriodsStep implements ComputationStep { | |||
private static final Logger LOG = LoggerFactory.getLogger(PeriodsHolderImpl.class); | |||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(DateUtils.DATE_FORMAT); | |||
@@ -63,25 +66,25 @@ public class PeriodsRepository { | |||
private final TreeRootHolder treeRootHolder; | |||
private final PeriodFinder periodFinder; | |||
private final BatchReportReader batchReportReader; | |||
private final PeriodsHolderImpl periodsHolder; | |||
private List<Period> periods = new ArrayList<>(); | |||
public PeriodsRepository(DbClient dbClient, Settings settings, TreeRootHolder treeRootHolder, PeriodFinder periodFinder, BatchReportReader batchReportReader) { | |||
public FeedPeriodsStep(DbClient dbClient, Settings settings, TreeRootHolder treeRootHolder, PeriodFinder periodFinder, BatchReportReader batchReportReader, | |||
PeriodsHolderImpl periodsHolder) { | |||
this.dbClient = dbClient; | |||
this.settings = settings; | |||
this.treeRootHolder = treeRootHolder; | |||
this.periodFinder = periodFinder; | |||
this.batchReportReader = batchReportReader; | |||
this.periodsHolder = periodsHolder; | |||
} | |||
public List<Period> getPeriods(){ | |||
if (periods.isEmpty()) { | |||
initPeriods(); | |||
} | |||
return periods; | |||
@Override | |||
public void execute() { | |||
periodsHolder.setPeriods(createPeriods()); | |||
} | |||
private void initPeriods() { | |||
private List<Period> createPeriods() { | |||
List<Period> periods = new ArrayList<>(); | |||
DbSession session = dbClient.openSession(false); | |||
try { | |||
Component project = treeRootHolder.getRoot(); | |||
@@ -105,6 +108,7 @@ public class PeriodsRepository { | |||
} finally { | |||
session.close(); | |||
} | |||
return periods; | |||
} | |||
private class PeriodResolver { | |||
@@ -157,7 +161,7 @@ public class PeriodsRepository { | |||
} | |||
@CheckForNull | |||
private Integer tryToResolveByDays(String property){ | |||
private Integer tryToResolveByDays(String property) { | |||
try { | |||
return Integer.parseInt(property); | |||
} catch (NumberFormatException e) { | |||
@@ -166,7 +170,7 @@ public class PeriodsRepository { | |||
} | |||
@CheckForNull | |||
private Date tryToResolveByDate(String property){ | |||
private Date tryToResolveByDate(String property) { | |||
try { | |||
return DATE_FORMAT.parse(property); | |||
} catch (ParseException e) { | |||
@@ -184,4 +188,8 @@ public class PeriodsRepository { | |||
return value; | |||
} | |||
@Override | |||
public String getDescription() { | |||
return "Feed differential periods"; | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* 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.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.core.component.SnapshotDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class PeriodsHolderImplTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Test | |||
public void get_periods() throws Exception { | |||
List<Period> periods = new ArrayList<>(); | |||
periods.add(new Period("mode", null, new SnapshotDto())); | |||
PeriodsHolderImpl periodsHolder = new PeriodsHolderImpl(); | |||
periodsHolder.setPeriods(periods); | |||
assertThat(periodsHolder.getPeriods()).hasSize(1); | |||
} | |||
@Test | |||
public void fail_to_get_periods_if_not_initialized() throws Exception { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("Periods have not been initialized yet"); | |||
new PeriodsHolderImpl().getPeriods(); | |||
} | |||
} |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.computation.period; | |||
package org.sonar.server.computation.step; | |||
import com.google.common.base.Function; | |||
import com.google.common.collect.Iterables; | |||
@@ -43,6 +43,9 @@ import org.sonar.server.computation.batch.BatchReportReaderRule; | |||
import org.sonar.server.computation.batch.TreeRootHolderRule; | |||
import org.sonar.server.computation.component.Component; | |||
import org.sonar.server.computation.component.DumbComponent; | |||
import org.sonar.server.computation.period.Period; | |||
import org.sonar.server.computation.period.PeriodFinder; | |||
import org.sonar.server.computation.period.PeriodsHolderImpl; | |||
import org.sonar.server.db.DbClient; | |||
import org.sonar.test.DbTests; | |||
@@ -50,7 +53,7 @@ import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@Category(DbTests.class) | |||
public class PeriodsRepositoryTest { | |||
public class FeedPeriodsStepTest extends BaseStepTest { | |||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); | |||
private static final String PROJECT_KEY = "PROJECT_KEY"; | |||
@@ -64,13 +67,20 @@ public class PeriodsRepositoryTest { | |||
@Rule | |||
public BatchReportReaderRule reportReader = new BatchReportReaderRule(); | |||
PeriodsHolderImpl periodsHolder = new PeriodsHolderImpl(); | |||
DbClient dbClient; | |||
DbSession dbSession; | |||
Settings settings = new Settings(); | |||
PeriodsRepository periodsRepository; | |||
FeedPeriodsStep sut; | |||
@Override | |||
protected ComputationStep step() { | |||
return sut; | |||
} | |||
@Before | |||
public void setUp() throws Exception { | |||
@@ -91,7 +101,7 @@ public class PeriodsRepositoryTest { | |||
Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY); | |||
treeRootHolder.setRoot(project); | |||
periodsRepository = new PeriodsRepository(dbClient, settings, treeRootHolder, new PeriodFinder(dbClient), reportReader); | |||
sut = new FeedPeriodsStep(dbClient, settings, treeRootHolder, new PeriodFinder(dbClient), reportReader, periodsHolder); | |||
} | |||
@After | |||
@@ -103,7 +113,8 @@ public class PeriodsRepositoryTest { | |||
public void no_period_on_first_analysis() throws Exception { | |||
// No project, no snapshot | |||
assertThat(periodsRepository.getPeriods()).isEmpty(); | |||
sut.execute(); | |||
assertThat(periodsHolder.getPeriods()).isEmpty(); | |||
} | |||
@Test | |||
@@ -114,7 +125,8 @@ public class PeriodsRepositoryTest { | |||
Date date = DATE_FORMAT.parse(textDate); | |||
settings.setProperty("sonar.timemachine.period1", textDate); | |||
List<Period> periods = periodsRepository.getPeriods(); | |||
sut.execute(); | |||
List<Period> periods = periodsHolder.getPeriods(); | |||
assertThat(periods).hasSize(1); | |||
Period period = periods.get(0); | |||
@@ -131,7 +143,8 @@ public class PeriodsRepositoryTest { | |||
settings.setProperty("sonar.timemachine.period1", "UNKNWOWN VERSION"); | |||
assertThat(periodsRepository.getPeriods()).isEmpty(); | |||
sut.execute(); | |||
assertThat(periodsHolder.getPeriods()).isEmpty(); | |||
} | |||
@Test | |||
@@ -140,7 +153,8 @@ public class PeriodsRepositoryTest { | |||
settings.setProperty("sonar.timemachine.period1", ""); | |||
assertThat(periodsRepository.getPeriods()).isEmpty(); | |||
sut.execute(); | |||
assertThat(periodsHolder.getPeriods()).isEmpty(); | |||
} | |||
@Test | |||
@@ -153,7 +167,9 @@ public class PeriodsRepositoryTest { | |||
settings.setProperty("sonar.timemachine.period4", "previous_version"); // Analysis from 2008-11-12 should be returned | |||
settings.setProperty("sonar.timemachine.period5", "0.9"); // Anaylsis from 2008-11-11 | |||
List<Period> periods = periodsRepository.getPeriods(); | |||
sut.execute(); | |||
List<Period> periods = periodsHolder.getPeriods(); | |||
List<String> periodModes = newArrayList(Iterables.transform(periods, new Function<Period, String>() { | |||
@Override | |||
public String apply(Period input) { | |||
@@ -191,21 +207,8 @@ public class PeriodsRepositoryTest { | |||
settings.setProperty("sonar.timemachine.period4.TRK", "2008-11-22"); | |||
settings.setProperty("sonar.timemachine.period5.TRK", "previous_analysis"); | |||
assertThat(periodsRepository.getPeriods()).hasSize(2); | |||
} | |||
@Test | |||
public void only_load_periods_on_first_call_of_get_periods() throws Exception { | |||
dbTester.prepareDbUnit(getClass(), "shared.xml"); | |||
settings.setProperty("sonar.timemachine.period1", "2008-11-22"); | |||
// First call, periods are loaded | |||
assertThat(periodsRepository.getPeriods()).hasSize(1); | |||
// Second call, set project without key to check that it won't fail with a NPE | |||
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, null, null)); | |||
assertThat(periodsRepository.getPeriods()).hasSize(1); | |||
sut.execute(); | |||
assertThat(periodsHolder.getPeriods()).hasSize(2); | |||
} | |||
} |