]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6260 Replace PeriodsRepository by a PeriodsHolder
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 8 Jun 2015 09:31:32 +0000 (11:31 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 10 Jun 2015 12:30:39 +0000 (14:30 +0200)
13 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/period/Period.java
server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodFinder.java
server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolderImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsRepository.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedPeriodsStep.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsRepositoryTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedPeriodsStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/period/PeriodsRepositoryTest/shared.xml [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedPeriodsStepTest/shared.xml [new file with mode: 0644]

index 103dc9ce2e9e1ac719d5edf42397561d949fd2be..b92b939d01db0ce81106fbdbdfc8719c48f6b394 100644 (file)
@@ -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
index 0ad15f72db86c72d94e819317acf67df3be3e8b0..6b7af6e039155df60f31fa643f5607edac78f851 100644 (file)
@@ -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;
   }
 
index a451fd68d70c7e951d1d12e172e84204a6b5262c..8b7efa5e5ed56cf16e17ef1d2189dd7a6d5619de 100644 (file)
@@ -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;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolder.java
new file mode 100644 (file)
index 0000000..622922f
--- /dev/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();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsHolderImpl.java
new file mode 100644 (file)
index 0000000..f11422f
--- /dev/null
@@ -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;
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/period/PeriodsRepository.java
deleted file mode 100644 (file)
index cf2181f..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.Strings;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.component.ComponentDto;
-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.db.DbClient;
-
-/**
- * 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 class PeriodsRepository {
-
-  private static final Logger LOG = LoggerFactory.getLogger(PeriodsRepository.class);
-
-  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(DateUtils.DATE_FORMAT);
-
-  private static final int NUMBER_OF_PERIODS = 5;
-
-  private final DbClient dbClient;
-  private final Settings settings;
-  private final TreeRootHolder treeRootHolder;
-  private final PeriodFinder periodFinder;
-  private final BatchReportReader batchReportReader;
-
-  private List<Period> periods = new ArrayList<>();
-
-  public PeriodsRepository(DbClient dbClient, Settings settings, TreeRootHolder treeRootHolder, PeriodFinder periodFinder, BatchReportReader batchReportReader) {
-    this.dbClient = dbClient;
-    this.settings = settings;
-    this.treeRootHolder = treeRootHolder;
-    this.periodFinder = periodFinder;
-    this.batchReportReader = batchReportReader;
-  }
-
-  public List<Period> getPeriods(){
-   if (periods.isEmpty()) {
-      initPeriods();
-    }
-    return periods;
-  }
-
-  private void initPeriods() {
-    DbSession session = dbClient.openSession(false);
-    try {
-      Component project = treeRootHolder.getRoot();
-      ComponentDto projectDto = dbClient.componentDao().selectNullableByKey(session, project.getKey());
-      // No project on first analysis, no period
-      if (projectDto != null) {
-        BatchReport.Component batchProject = batchReportReader.readComponent(project.getRef());
-        PeriodResolver periodResolver = new PeriodResolver(session, projectDto.getId(), batchReportReader.readMetadata().getAnalysisDate(), batchProject.getVersion(),
-          // TODO qualifier will be different for Views
-          Qualifiers.PROJECT);
-
-        for (int index = 1; index <= NUMBER_OF_PERIODS; index++) {
-          Period period = periodResolver.resolve(index);
-          // SONAR-4700 Add a past snapshot only if it exists
-          if (period != null) {
-            periods.add(period.setIndex(index));
-            LOG.debug(period.toString());
-          }
-        }
-      }
-    } finally {
-      session.close();
-    }
-  }
-
-  private class PeriodResolver {
-
-    private final DbSession session;
-    private final long projectId;
-    private final long analysisDate;
-    private final String currentVersion;
-    private final String qualifier;
-
-    public PeriodResolver(DbSession session, long projectId, long analysisDate, String currentVersion, String qualifier) {
-      this.session = session;
-      this.projectId = projectId;
-      this.analysisDate = analysisDate;
-      this.currentVersion = currentVersion;
-      this.qualifier = qualifier;
-    }
-
-    @CheckForNull
-    private Period resolve(int index) {
-      String propertyValue = getPropertyValue(qualifier, settings, index);
-      Period period = resolve(index, propertyValue);
-      if (period == null && StringUtils.isNotBlank(propertyValue)) {
-        LOG.debug("Property " + CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + " is not valid: " + propertyValue);
-      }
-      return period;
-    }
-
-    @CheckForNull
-    private Period resolve(int index, String property) {
-      if (StringUtils.isBlank(property)) {
-        return null;
-      }
-
-      Integer days = tryToResolveByDays(property);
-      if (days != null) {
-        return periodFinder.findByDays(session, projectId, analysisDate, days);
-      }
-      Date date = tryToResolveByDate(property);
-      if (date != null) {
-        return periodFinder.findByDate(session, projectId, date);
-      }
-      if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, property)) {
-        return periodFinder.findByPreviousAnalysis(session, projectId, analysisDate);
-      }
-      if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, property)) {
-        return periodFinder.findByPreviousVersion(session, projectId, currentVersion);
-      }
-      return periodFinder.findByVersion(session, projectId, property);
-    }
-
-    @CheckForNull
-    private Integer tryToResolveByDays(String property){
-      try {
-        return Integer.parseInt(property);
-      } catch (NumberFormatException e) {
-        return null;
-      }
-    }
-
-    @CheckForNull
-    private Date tryToResolveByDate(String property){
-      try {
-        return DATE_FORMAT.parse(property);
-      } catch (ParseException e) {
-        return null;
-      }
-    }
-  }
-
-  private static String getPropertyValue(@Nullable String qualifier, Settings settings, int index) {
-    String value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index);
-    // For periods 4 and 5 we're also searching for a property prefixed by the qualifier
-    if (index > 3 && Strings.isNullOrEmpty(value)) {
-      value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + "." + qualifier);
-    }
-    return value;
-  }
-
-}
index 36492c13f770afd07e15ef3b02828411fa976236..57396619bdbfc44a0e26e63dfe42040c867eb949 100644 (file)
@@ -52,6 +52,7 @@ public class ComputationSteps {
       QualityGateEventsStep.class,
 
       // Persist data
+      FeedPeriodsStep.class,
       PersistComponentsStep.class,
       PersistSnapshotsStep.class,
       PersistNumberOfDaysSinceLastCommitStep.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedPeriodsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedPeriodsStep.java
new file mode 100644 (file)
index 0000000..7612c91
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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.step;
+
+import com.google.common.base.Strings;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.component.ComponentDto;
+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;
+
+/**
+ * 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 FeedPeriodsStep implements ComputationStep {
+  private static final Logger LOG = LoggerFactory.getLogger(PeriodsHolderImpl.class);
+
+  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(DateUtils.DATE_FORMAT);
+
+  private static final int NUMBER_OF_PERIODS = 5;
+
+  private final DbClient dbClient;
+  private final Settings settings;
+  private final TreeRootHolder treeRootHolder;
+  private final PeriodFinder periodFinder;
+  private final BatchReportReader batchReportReader;
+  private final PeriodsHolderImpl periodsHolder;
+
+  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;
+  }
+
+  @Override
+  public void execute() {
+    periodsHolder.setPeriods(createPeriods());
+  }
+
+  private List<Period> createPeriods() {
+    List<Period> periods = new ArrayList<>();
+    DbSession session = dbClient.openSession(false);
+    try {
+      Component project = treeRootHolder.getRoot();
+      ComponentDto projectDto = dbClient.componentDao().selectNullableByKey(session, project.getKey());
+      // No project on first analysis, no period
+      if (projectDto != null) {
+        BatchReport.Component batchProject = batchReportReader.readComponent(project.getRef());
+        PeriodResolver periodResolver = new PeriodResolver(session, projectDto.getId(), batchReportReader.readMetadata().getAnalysisDate(), batchProject.getVersion(),
+          // TODO qualifier will be different for Views
+          Qualifiers.PROJECT);
+
+        for (int index = 1; index <= NUMBER_OF_PERIODS; index++) {
+          Period period = periodResolver.resolve(index);
+          // SONAR-4700 Add a past snapshot only if it exists
+          if (period != null) {
+            periods.add(period.setIndex(index));
+            LOG.debug(period.toString());
+          }
+        }
+      }
+    } finally {
+      session.close();
+    }
+    return periods;
+  }
+
+  private class PeriodResolver {
+
+    private final DbSession session;
+    private final long projectId;
+    private final long analysisDate;
+    private final String currentVersion;
+    private final String qualifier;
+
+    public PeriodResolver(DbSession session, long projectId, long analysisDate, String currentVersion, String qualifier) {
+      this.session = session;
+      this.projectId = projectId;
+      this.analysisDate = analysisDate;
+      this.currentVersion = currentVersion;
+      this.qualifier = qualifier;
+    }
+
+    @CheckForNull
+    private Period resolve(int index) {
+      String propertyValue = getPropertyValue(qualifier, settings, index);
+      Period period = resolve(index, propertyValue);
+      if (period == null && StringUtils.isNotBlank(propertyValue)) {
+        LOG.debug("Property " + CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + " is not valid: " + propertyValue);
+      }
+      return period;
+    }
+
+    @CheckForNull
+    private Period resolve(int index, String property) {
+      if (StringUtils.isBlank(property)) {
+        return null;
+      }
+
+      Integer days = tryToResolveByDays(property);
+      if (days != null) {
+        return periodFinder.findByDays(session, projectId, analysisDate, days);
+      }
+      Date date = tryToResolveByDate(property);
+      if (date != null) {
+        return periodFinder.findByDate(session, projectId, date);
+      }
+      if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, property)) {
+        return periodFinder.findByPreviousAnalysis(session, projectId, analysisDate);
+      }
+      if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, property)) {
+        return periodFinder.findByPreviousVersion(session, projectId, currentVersion);
+      }
+      return periodFinder.findByVersion(session, projectId, property);
+    }
+
+    @CheckForNull
+    private Integer tryToResolveByDays(String property) {
+      try {
+        return Integer.parseInt(property);
+      } catch (NumberFormatException e) {
+        return null;
+      }
+    }
+
+    @CheckForNull
+    private Date tryToResolveByDate(String property) {
+      try {
+        return DATE_FORMAT.parse(property);
+      } catch (ParseException e) {
+        return null;
+      }
+    }
+  }
+
+  private static String getPropertyValue(@Nullable String qualifier, Settings settings, int index) {
+    String value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index);
+    // For periods 4 and 5 we're also searching for a property prefixed by the qualifier
+    if (index > 3 && Strings.isNullOrEmpty(value)) {
+      value = settings.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index + "." + qualifier);
+    }
+    return value;
+  }
+
+  @Override
+  public String getDescription() {
+    return "Feed differential periods";
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsHolderImplTest.java
new file mode 100644 (file)
index 0000000..6f7f6d8
--- /dev/null
@@ -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();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/period/PeriodsRepositoryTest.java
deleted file mode 100644 (file)
index 9a61d70..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.Function;
-import com.google.common.collect.Iterables;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import org.junit.After;
-import org.junit.Before;
-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.batch.protocol.Constants;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.DbTester;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.component.db.SnapshotDao;
-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.db.DbClient;
-import org.sonar.test.DbTests;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@Category(DbTests.class)
-public class PeriodsRepositoryTest {
-
-  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
-  private static final String PROJECT_KEY = "PROJECT_KEY";
-
-  @ClassRule
-  public static final DbTester dbTester = new DbTester();
-
-  @Rule
-  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
-  @Rule
-  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
-  DbClient dbClient;
-
-  DbSession dbSession;
-
-  Settings settings = new Settings();
-
-  PeriodsRepository periodsRepository;
-
-  @Before
-  public void setUp() throws Exception {
-    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao());
-    dbSession = dbClient.openSession(false);
-
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder()
-      .setAnalysisDate(DATE_FORMAT.parse("2008-11-30").getTime())
-      .build());
-
-    reportReader.putComponent(BatchReport.Component.newBuilder()
-      .setRef(1)
-      .setType(Constants.ComponentType.PROJECT)
-      .setKey(PROJECT_KEY)
-      .setVersion("1.1")
-      .build());
-
-    Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY);
-    treeRootHolder.setRoot(project);
-
-    periodsRepository = new PeriodsRepository(dbClient, settings, treeRootHolder, new PeriodFinder(dbClient), reportReader);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    dbSession.close();
-  }
-
-  @Test
-  public void no_period_on_first_analysis() throws Exception {
-    // No project, no snapshot
-
-    assertThat(periodsRepository.getPeriods()).isEmpty();
-  }
-
-  @Test
-  public void get_one_period() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    String textDate = "2008-11-22";
-    Date date = DATE_FORMAT.parse(textDate);
-    settings.setProperty("sonar.timemachine.period1", textDate);
-
-    List<Period> periods = periodsRepository.getPeriods();
-    assertThat(periods).hasSize(1);
-
-    Period period =  periods.get(0);
-    assertThat(period.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DATE);
-    assertThat(period.getModeParameter()).isEqualTo(textDate);
-    assertThat(period.getSnapshotDate()).isEqualTo(1227358680000L);
-    assertThat(period.getTargetDate()).isEqualTo(date.getTime());
-    assertThat(period.getProjectSnapshot().getId()).isEqualTo(1003L);
-  }
-
-  @Test
-  public void no_period_when_settings_match_no_analysis() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    settings.setProperty("sonar.timemachine.period1", "UNKNWOWN VERSION");
-
-    assertThat(periodsRepository.getPeriods()).isEmpty();
-  }
-
-  @Test
-  public void no_period_when_settings_is_empty() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    settings.setProperty("sonar.timemachine.period1", "");
-
-    assertThat(periodsRepository.getPeriods()).isEmpty();
-  }
-
-  @Test
-  public void get_five_different_periods() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    settings.setProperty("sonar.timemachine.period1", "2008-11-22"); // Analysis from 2008-11-22 should be returned
-    settings.setProperty("sonar.timemachine.period2", "10"); // Analysis from 2008-11-20 should be returned
-    settings.setProperty("sonar.timemachine.period3", "previous_analysis"); // Analysis from 2008-11-29 should be returned
-    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();
-    List<String> periodModes = newArrayList(Iterables.transform(periods, new Function<Period, String>() {
-      @Override
-      public String apply(Period input) {
-        return input.getMode();
-      }
-    }));
-    assertThat(periodModes).containsOnly(CoreProperties.TIMEMACHINE_MODE_DATE, CoreProperties.TIMEMACHINE_MODE_DAYS, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS,
-      CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, CoreProperties.TIMEMACHINE_MODE_VERSION);
-
-    assertThat(periods.get(0).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DATE);
-    assertThat(periods.get(0).getIndex()).isEqualTo(1);
-    assertThat(periods.get(0).getProjectSnapshot().getId()).isEqualTo(1003L);
-
-    assertThat(periods.get(1).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DAYS);
-    assertThat(periods.get(1).getIndex()).isEqualTo(2);
-    assertThat(periods.get(1).getProjectSnapshot().getId()).isEqualTo(1002L);
-
-    assertThat(periods.get(2).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
-    assertThat(periods.get(2).getIndex()).isEqualTo(3);
-    assertThat(periods.get(2).getProjectSnapshot().getId()).isEqualTo(1004L);
-
-    assertThat(periods.get(3).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
-    assertThat(periods.get(3).getIndex()).isEqualTo(4);
-    assertThat(periods.get(3).getProjectSnapshot().getId()).isEqualTo(1001L);
-
-    assertThat(periods.get(4).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_VERSION);
-    assertThat(periods.get(4).getIndex()).isEqualTo(5);
-    assertThat(periods.get(4).getProjectSnapshot().getId()).isEqualTo(1000L);
-  }
-
-  @Test
-  public void can_use_qualifier_in_settings() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    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);
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedPeriodsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedPeriodsStepTest.java
new file mode 100644 (file)
index 0000000..699d5bd
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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.step;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+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.batch.protocol.Constants;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
+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;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class FeedPeriodsStepTest extends BaseStepTest {
+
+  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+  private static final String PROJECT_KEY = "PROJECT_KEY";
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+  @Rule
+  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+  PeriodsHolderImpl periodsHolder = new PeriodsHolderImpl();
+
+  DbClient dbClient;
+
+  DbSession dbSession;
+
+  Settings settings = new Settings();
+
+  FeedPeriodsStep sut;
+
+  @Override
+  protected ComputationStep step() {
+    return sut;
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao());
+    dbSession = dbClient.openSession(false);
+
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(DATE_FORMAT.parse("2008-11-30").getTime())
+      .build());
+
+    reportReader.putComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .setVersion("1.1")
+      .build());
+
+    Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY);
+    treeRootHolder.setRoot(project);
+
+    sut = new FeedPeriodsStep(dbClient, settings, treeRootHolder, new PeriodFinder(dbClient), reportReader, periodsHolder);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    dbSession.close();
+  }
+
+  @Test
+  public void no_period_on_first_analysis() throws Exception {
+    // No project, no snapshot
+
+    sut.execute();
+    assertThat(periodsHolder.getPeriods()).isEmpty();
+  }
+
+  @Test
+  public void get_one_period() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    String textDate = "2008-11-22";
+    Date date = DATE_FORMAT.parse(textDate);
+    settings.setProperty("sonar.timemachine.period1", textDate);
+
+    sut.execute();
+    List<Period> periods = periodsHolder.getPeriods();
+    assertThat(periods).hasSize(1);
+
+    Period period =  periods.get(0);
+    assertThat(period.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DATE);
+    assertThat(period.getModeParameter()).isEqualTo(textDate);
+    assertThat(period.getSnapshotDate()).isEqualTo(1227358680000L);
+    assertThat(period.getTargetDate()).isEqualTo(date.getTime());
+    assertThat(period.getProjectSnapshot().getId()).isEqualTo(1003L);
+  }
+
+  @Test
+  public void no_period_when_settings_match_no_analysis() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    settings.setProperty("sonar.timemachine.period1", "UNKNWOWN VERSION");
+
+    sut.execute();
+    assertThat(periodsHolder.getPeriods()).isEmpty();
+  }
+
+  @Test
+  public void no_period_when_settings_is_empty() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    settings.setProperty("sonar.timemachine.period1", "");
+
+    sut.execute();
+    assertThat(periodsHolder.getPeriods()).isEmpty();
+  }
+
+  @Test
+  public void get_five_different_periods() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    settings.setProperty("sonar.timemachine.period1", "2008-11-22"); // Analysis from 2008-11-22 should be returned
+    settings.setProperty("sonar.timemachine.period2", "10"); // Analysis from 2008-11-20 should be returned
+    settings.setProperty("sonar.timemachine.period3", "previous_analysis"); // Analysis from 2008-11-29 should be returned
+    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
+
+    sut.execute();
+    List<Period> periods = periodsHolder.getPeriods();
+
+    List<String> periodModes = newArrayList(Iterables.transform(periods, new Function<Period, String>() {
+      @Override
+      public String apply(Period input) {
+        return input.getMode();
+      }
+    }));
+    assertThat(periodModes).containsOnly(CoreProperties.TIMEMACHINE_MODE_DATE, CoreProperties.TIMEMACHINE_MODE_DAYS, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS,
+      CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, CoreProperties.TIMEMACHINE_MODE_VERSION);
+
+    assertThat(periods.get(0).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DATE);
+    assertThat(periods.get(0).getIndex()).isEqualTo(1);
+    assertThat(periods.get(0).getProjectSnapshot().getId()).isEqualTo(1003L);
+
+    assertThat(periods.get(1).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_DAYS);
+    assertThat(periods.get(1).getIndex()).isEqualTo(2);
+    assertThat(periods.get(1).getProjectSnapshot().getId()).isEqualTo(1002L);
+
+    assertThat(periods.get(2).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
+    assertThat(periods.get(2).getIndex()).isEqualTo(3);
+    assertThat(periods.get(2).getProjectSnapshot().getId()).isEqualTo(1004L);
+
+    assertThat(periods.get(3).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
+    assertThat(periods.get(3).getIndex()).isEqualTo(4);
+    assertThat(periods.get(3).getProjectSnapshot().getId()).isEqualTo(1001L);
+
+    assertThat(periods.get(4).getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_VERSION);
+    assertThat(periods.get(4).getIndex()).isEqualTo(5);
+    assertThat(periods.get(4).getProjectSnapshot().getId()).isEqualTo(1000L);
+  }
+
+  @Test
+  public void can_use_qualifier_in_settings() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    settings.setProperty("sonar.timemachine.period4.TRK", "2008-11-22");
+    settings.setProperty("sonar.timemachine.period5.TRK", "previous_analysis");
+
+    sut.execute();
+    assertThat(periodsHolder.getPeriods()).hasSize(2);
+  }
+
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/period/PeriodsRepositoryTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/period/PeriodsRepositoryTest/shared.xml
deleted file mode 100644 (file)
index ba062d9..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<dataset>
-
-  <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="PROJECT_KEY" name="project" long_name="[null]" description="[null]"
-            uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
-            enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
-
-  <!-- 2008-11-11 -->
-  <!-- Version 0.9 -->
-  <snapshots id="1000" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
-             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
-             period5_param="[null]" period5_date="[null]"
-             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="1226379600000" build_date="1226379600000" version="0.9" path=""
-             status="P" islast="false" depth="0"/>
-
-  <!-- 2008-11-12 -->
-  <!-- Version 1.0 -->
-  <snapshots id="1001" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
-             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
-             period5_param="[null]" period5_date="[null]" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="1226494680000" build_date="1226494680000" version="1.0" path=""
-             status="P" islast="false" depth="0"/>
-
-  <!-- 2008-11-20 -->
-  <!-- First version 1.1 -->
-  <snapshots id="1002" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
-             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
-             period5_param="[null]" period5_date="[null]"
-             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="1227157200000" build_date="1227157200000" version="1.1" path=""
-             status="P" islast="false" depth="0"/>
-
-  <!-- 2008-11-22 -->
-  <snapshots id="1003" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
-             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
-             period5_param="[null]" period5_date="[null]"
-             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="1227358680000" build_date="1227358680000" version="1.1" path=""
-             status="P" islast="false" depth="0"/>
-
-  <!-- 2008-11-29 -->
-  <!-- Last version 1.1 -->
-  <snapshots id="1004" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
-             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
-             period5_param="[null]" period5_date="[null]" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="1227934800000" build_date="1227934800000" version="1.1" path=""
-             status="P" islast="true" depth="0"/>
-
-
-  <events id="1" name="0.9" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1226379600000" created_at="1226379600000" description="" event_data="[null]"/>
-  <events id="2" name="1.0" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="1226494680000" created_at="1226494680000" description="" event_data="[null]"/>
-  <events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1004" category="Version" event_date="1227934800000" created_at="1227934800000" description="" event_data="[null]"/>
-
-</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedPeriodsStepTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedPeriodsStepTest/shared.xml
new file mode 100644 (file)
index 0000000..ba062d9
--- /dev/null
@@ -0,0 +1,54 @@
+<dataset>
+
+  <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="PROJECT_KEY" name="project" long_name="[null]" description="[null]"
+            uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
+            enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
+
+  <!-- 2008-11-11 -->
+  <!-- Version 0.9 -->
+  <snapshots id="1000" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
+             period5_param="[null]" period5_date="[null]"
+             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="1226379600000" build_date="1226379600000" version="0.9" path=""
+             status="P" islast="false" depth="0"/>
+
+  <!-- 2008-11-12 -->
+  <!-- Version 1.0 -->
+  <snapshots id="1001" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
+             period5_param="[null]" period5_date="[null]" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="1226494680000" build_date="1226494680000" version="1.0" path=""
+             status="P" islast="false" depth="0"/>
+
+  <!-- 2008-11-20 -->
+  <!-- First version 1.1 -->
+  <snapshots id="1002" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
+             period5_param="[null]" period5_date="[null]"
+             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="1227157200000" build_date="1227157200000" version="1.1" path=""
+             status="P" islast="false" depth="0"/>
+
+  <!-- 2008-11-22 -->
+  <snapshots id="1003" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
+             period5_param="[null]" period5_date="[null]"
+             project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="1227358680000" build_date="1227358680000" version="1.1" path=""
+             status="P" islast="false" depth="0"/>
+
+  <!-- 2008-11-29 -->
+  <!-- Last version 1.1 -->
+  <snapshots id="1004" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
+             period5_param="[null]" period5_date="[null]" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="1227934800000" build_date="1227934800000" version="1.1" path=""
+             status="P" islast="true" depth="0"/>
+
+
+  <events id="1" name="0.9" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1226379600000" created_at="1226379600000" description="" event_data="[null]"/>
+  <events id="2" name="1.0" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="1226494680000" created_at="1226494680000" description="" event_data="[null]"/>
+  <events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1004" category="Version" event_date="1227934800000" created_at="1227934800000" description="" event_data="[null]"/>
+
+</dataset>