]> source.dussan.org Git - sonarqube.git/commitdiff
compute engine – move ProjectPurgeTask on the server side
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 3 Dec 2014 16:34:21 +0000 (17:34 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 3 Dec 2014 17:51:45 +0000 (18:51 +0100)
48 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/DataCleanerStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTask.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/test/java/org/sonar/server/computation/DataCleanerStepMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/DataCleanerStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTaskTest.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DataCleanerProperties.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerConstants.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTask.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTask.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/package-info.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleaner.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filters.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Interval.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/package-info.java [deleted file]
sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java
sonar-core/src/main/java/org/sonar/core/purge/PurgeConfiguration.java
sonar-core/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DataCleanerProperties.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DbCleanerConstants.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTask.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleaner.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filters.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Interval.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/package-info.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DataCleanerPropertiesTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerTestUtils.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTaskTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTaskTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleanerTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilterTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/IntervalTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilterTest.java [deleted file]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DataCleanerPropertiesTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DbCleanerTestUtils.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTaskTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleanerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilterTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/IntervalTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilterTest.java [new file with mode: 0644]

index 8636b0ae74cb740feacc9a582ba408ebdb1f3dc0..bcb7b7f4454f63352394b4651928ebaea7ee7f45 100644 (file)
@@ -23,7 +23,7 @@ package org.sonar.server.computation;
 import org.sonar.api.config.Settings;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.core.computation.dbcleaner.ProjectPurgeTask;
+import org.sonar.server.computation.dbcleaner.ProjectPurgeTask;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.purge.PurgeConfiguration;
 import org.sonar.server.issue.index.IssueIndex;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTask.java
new file mode 100644 (file)
index 0000000..d6e13f3
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.dbcleaner;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.TimeUtils;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeProfiler;
+
+import java.util.List;
+
+public class ProjectPurgeTask implements ServerComponent {
+  private static final Logger LOG = LoggerFactory.getLogger(ProjectPurgeTask.class);
+  private final PurgeProfiler profiler;
+  private final PurgeDao purgeDao;
+  private final DefaultPeriodCleaner periodCleaner;
+
+  public ProjectPurgeTask(PurgeDao purgeDao, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler) {
+    this.purgeDao = purgeDao;
+    this.periodCleaner = periodCleaner;
+    this.profiler = profiler;
+  }
+
+  public ProjectPurgeTask purge(DbSession session, PurgeConfiguration configuration, Settings settings) {
+    long start = System.currentTimeMillis();
+    profiler.reset();
+    cleanHistoricalData(session, configuration.rootProjectId(), settings);
+    doPurge(session, configuration);
+    if (settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
+      long duration = System.currentTimeMillis() - start;
+      LOG.info("\n -------- Profiling for purge: " + TimeUtils.formatDuration(duration) + " --------\n");
+      profiler.dump(duration, LOG);
+      LOG.info("\n -------- End of profiling for purge --------\n");
+    }
+    return this;
+  }
+
+  private void cleanHistoricalData(DbSession session, long resourceId, Settings settings) {
+    try {
+      periodCleaner.clean(session, resourceId, settings);
+    } catch (Exception e) {
+      // purge errors must no fail the batch
+      LOG.error("Fail to clean historical data [id=" + resourceId + "]", e);
+    }
+  }
+
+  private void doPurge(DbSession session, PurgeConfiguration configuration) {
+    try {
+      purgeDao.purge(session, configuration);
+    } catch (Exception e) {
+      // purge errors must no fail the report analysis
+      LOG.error("Fail to purge data [id=" + configuration.rootProjectId() + "]", e);
+    }
+  }
+
+  public List<String> findUuidsToDisable(DbSession session, Long projectId) {
+    return purgeDao.selectPurgeableFiles(session, projectId);
+  }
+}
index 922cdc96ae0b44cffbcdae992a7dbcf840b033f8..a68960db2ebca51f5018e35d82617bac72ff3221 100644 (file)
@@ -37,9 +37,9 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.utils.UriReader;
 import org.sonar.api.utils.internal.TempFolderCleaner;
 import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.computation.dbcleaner.DefaultPurgeTask;
-import org.sonar.core.computation.dbcleaner.ProjectPurgeTask;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.server.computation.dbcleaner.DefaultPurgeTask;
+import org.sonar.server.computation.dbcleaner.ProjectPurgeTask;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.core.config.Logback;
 import org.sonar.core.i18n.DefaultI18n;
index 7e6cfbefa719cdf464b5ac3910496970f42af763..512285c89112e50d7296991594228a4681d3d8c9 100644 (file)
@@ -29,8 +29,8 @@ import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.computation.db.AnalysisReportDto;
 import org.sonar.core.computation.db.AnalysisReportDto.Status;
-import org.sonar.core.computation.dbcleaner.DbCleanerConstants;
-import org.sonar.core.computation.dbcleaner.ProjectPurgeTask;
+import org.sonar.server.computation.dbcleaner.DbCleanerConstants;
+import org.sonar.server.computation.dbcleaner.ProjectPurgeTask;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.properties.PropertyDto;
index 3c6523d6d9545da3f8b34771829c023e15395cd8..800b1f7ff47e8de31844f305c1bbe604b52a7f43 100644 (file)
@@ -25,7 +25,7 @@ import org.junit.Test;
 import org.sonar.api.config.Settings;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.core.computation.dbcleaner.ProjectPurgeTask;
+import org.sonar.server.computation.dbcleaner.ProjectPurgeTask;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.purge.PurgeConfiguration;
 import org.sonar.server.issue.index.IssueIndex;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTaskTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectPurgeTaskTest.java
new file mode 100644 (file)
index 0000000..74cafe7
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.dbcleaner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeProfiler;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.*;
+
+public class ProjectPurgeTaskTest {
+
+  private ProjectPurgeTask sut;
+  private PurgeDao dao;
+  private PurgeProfiler profiler;
+  private DefaultPeriodCleaner periodCleaner;
+
+  @Before
+  public void before() throws Exception {
+    this.dao = mock(PurgeDao.class);
+    this.profiler = mock(PurgeProfiler.class);
+    this.periodCleaner = mock(DefaultPeriodCleaner.class);
+
+    this.sut = new ProjectPurgeTask(dao, periodCleaner, profiler);
+  }
+
+  @Test
+  public void no_profiling_when_property_is_false() throws Exception {
+    Settings settings = mock(Settings.class);
+    when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(false);
+
+    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), settings);
+
+    verify(profiler, never()).dump(anyLong(), any(Logger.class));
+  }
+
+  @Test
+  public void profiling_when_property_is_true() throws Exception {
+    Settings settings = mock(Settings.class);
+    when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(true);
+
+    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), settings);
+
+    verify(profiler, times(1)).dump(anyLong(), any(Logger.class));
+  }
+
+  @Test
+  public void if_dao_purge_fails_it_should_not_interrupt_program_execution() throws Exception {
+    doThrow(RuntimeException.class).when(dao).purge(any(DbSession.class), any(PurgeConfiguration.class));
+
+    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), mock(Settings.class));
+
+    verify(dao, times(1)).purge(any(DbSession.class), any(PurgeConfiguration.class));
+  }
+
+  @Test
+  public void if_profiler_cleaning_fails_it_should_not_interrupt_program_execution() throws Exception {
+    doThrow(RuntimeException.class).when(periodCleaner).clean(any(DbSession.class), anyLong(), any(Settings.class));
+
+    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), mock(Settings.class));
+
+    verify(periodCleaner, times(1)).clean(any(DbSession.class), anyLong(), any(Settings.class));
+  }
+}
index 8d0f2bfb00dd25488bae7a77b6183d2d8b143760..a3bf5ed529e1f5817212bf5de4cff16fe4461ca4 100644 (file)
@@ -32,8 +32,8 @@ import org.sonar.batch.maven.MavenProjectBuilder;
 import org.sonar.batch.maven.MavenProjectConverter;
 import org.sonar.batch.scm.ScmConfiguration;
 import org.sonar.batch.scm.ScmSensor;
-import org.sonar.core.computation.dbcleaner.DefaultPurgeTask;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.server.computation.dbcleaner.DefaultPurgeTask;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
 import org.sonar.core.config.CorePropertyDefinitions;
 
 import java.util.Collection;
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DataCleanerProperties.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DataCleanerProperties.java
deleted file mode 100644 (file)
index f4bc98d..0000000
+++ /dev/null
@@ -1,108 +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.core.computation.dbcleaner;
-
-import org.sonar.api.CoreProperties;
-import org.sonar.api.PropertyType;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.resources.Qualifiers;
-
-import java.util.Arrays;
-import java.util.List;
-
-public final class DataCleanerProperties {
-
-  private DataCleanerProperties() {
-  }
-
-  public static List<PropertyDefinition> all() {
-    return Arrays.asList(
-      PropertyDefinition.builder(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY)
-        .defaultValue("true")
-        .name("Clean directory/package history")
-        .description("If set to true, no history is kept at directory/package level. Setting this to false can cause database bloat.")
-        .type(PropertyType.BOOLEAN)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(1)
-        .build(),
-
-      PropertyDefinition.builder(DbCleanerConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES)
-        .defaultValue("30")
-        .name("Delete closed issues after")
-        .description("Issues that have been closed for more than this number of days will be deleted.")
-        .type(PropertyType.INTEGER)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(2)
-        .build(),
-
-      PropertyDefinition.builder(DbCleanerConstants.HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY)
-        .defaultValue("24")
-        .name("Keep only one snapshot a day after")
-        .description("After this number of hours, if there are several snapshots during the same day, "
-          + "the DbCleaner keeps the most recent one and fully deletes the other ones.")
-        .type(PropertyType.INTEGER)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(3)
-        .build(),
-
-      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK)
-        .defaultValue("4")
-        .name("Keep only one snapshot a week after")
-        .description("After this number of weeks, if there are several snapshots during the same week, "
-          + "the DbCleaner keeps the most recent one and fully deletes the other ones")
-        .type(PropertyType.INTEGER)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(4)
-        .build(),
-
-      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH)
-        .defaultValue("52")
-        .name("Keep only one snapshot a month after")
-        .description("After this number of weeks, if there are several snapshots during the same month, "
-          + "the DbCleaner keeps the most recent one and fully deletes the other ones.")
-        .type(PropertyType.INTEGER)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(5)
-        .build(),
-
-      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS)
-        .defaultValue("260")
-        .name("Delete all snapshots after")
-        .description("After this number of weeks, all snapshots are fully deleted.")
-        .type(PropertyType.INTEGER)
-        .onQualifiers(Qualifiers.PROJECT)
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
-        .index(6)
-        .build()
-      );
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerConstants.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerConstants.java
deleted file mode 100644 (file)
index a577f63..0000000
+++ /dev/null
@@ -1,34 +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.core.computation.dbcleaner;
-
-public interface DbCleanerConstants {
-
-  String PLUGIN_KEY = "dbcleaner";
-  String PLUGIN_NAME = "DbCleaner";
-  String PROPERTY_CLEAN_DIRECTORY = "sonar.dbcleaner.cleanDirectory";
-
-  String HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY = "sonar.dbcleaner.hoursBeforeKeepingOnlyOneSnapshotByDay";
-  String WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK = "sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByWeek";
-  String WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH = "sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByMonth";
-  String WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS = "sonar.dbcleaner.weeksBeforeDeletingAllSnapshots";
-  String DAYS_BEFORE_DELETING_CLOSED_ISSUES = "sonar.dbcleaner.daysBeforeDeletingClosedIssues";
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTask.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTask.java
deleted file mode 100644 (file)
index 2e0f073..0000000
+++ /dev/null
@@ -1,111 +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.core.computation.dbcleaner;
-
-import com.google.common.annotations.VisibleForTesting;
-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.TimeUtils;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
-import org.sonar.core.purge.IdUuidPair;
-import org.sonar.core.purge.PurgeConfiguration;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeProfiler;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.plugins.dbcleaner.api.PurgeTask;
-
-import static org.sonar.core.purge.PurgeConfiguration.newDefaultPurgeConfiguration;
-
-/**
- * @since 2.14
- */
-public class DefaultPurgeTask implements PurgeTask {
-  private static final Logger LOG = LoggerFactory.getLogger(DefaultPurgeTask.class);
-  private final PurgeProfiler profiler;
-  private final PurgeDao purgeDao;
-  private final ResourceDao resourceDao;
-  private final Settings settings;
-  private final DefaultPeriodCleaner periodCleaner;
-
-  public DefaultPurgeTask(PurgeDao purgeDao, ResourceDao resourceDao, Settings settings, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler) {
-    this.purgeDao = purgeDao;
-    this.resourceDao = resourceDao;
-    this.settings = settings;
-    this.periodCleaner = periodCleaner;
-    this.profiler = profiler;
-  }
-
-  @Override
-  public DefaultPurgeTask delete(long resourceId) {
-    ResourceDto project = resourceDao.getResource(resourceId);
-    purgeDao.deleteResourceTree(new IdUuidPair(project.getId(), project.getUuid()));
-    return this;
-  }
-
-  @VisibleForTesting
-  boolean isNotViewNorSubview(String resourceQualifier) {
-    return !(Qualifiers.VIEW.equals(resourceQualifier) || Qualifiers.SUBVIEW.equals(resourceQualifier));
-  }
-
-  @Override
-  public DefaultPurgeTask purge(long resourceId) {
-    long start = System.currentTimeMillis();
-    String resourceQualifier = resourceDao.getResource(resourceId).getQualifier();
-    if (isNotViewNorSubview(resourceQualifier)) {
-      profiler.reset();
-      cleanHistoricalData(resourceId);
-      doPurge(resourceId);
-      if (settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
-        long duration = System.currentTimeMillis() - start;
-        LOG.info("\n -------- Profiling for purge: " + TimeUtils.formatDuration(duration) + " --------\n");
-        profiler.dump(duration, LOG);
-        LOG.info("\n -------- End of profiling for purge --------\n");
-      }
-    }
-    return this;
-  }
-
-  private void cleanHistoricalData(long resourceId) {
-    try {
-      periodCleaner.clean(resourceId);
-    } catch (Exception e) {
-      // purge errors must no fail the batch
-      LOG.error("Fail to clean historical data [id=" + resourceId + "]", e);
-    }
-  }
-
-  private void doPurge(long resourceId) {
-    try {
-      purgeDao.purge(newPurgeConfigurationOnResource(resourceId));
-    } catch (Exception e) {
-      // purge errors must no fail the report analysis
-      LOG.error("Fail to purge data [id=" + resourceId + "]", e);
-    }
-  }
-
-  public PurgeConfiguration newPurgeConfigurationOnResource(long resourceId) {
-    return newDefaultPurgeConfiguration(settings, resourceId);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTask.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTask.java
deleted file mode 100644 (file)
index 931a746..0000000
+++ /dev/null
@@ -1,84 +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.core.computation.dbcleaner;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.config.Settings;
-import org.sonar.api.utils.TimeUtils;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.purge.PurgeConfiguration;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeProfiler;
-
-import java.util.List;
-
-public class ProjectPurgeTask implements ServerComponent {
-  private static final Logger LOG = LoggerFactory.getLogger(ProjectPurgeTask.class);
-  private final PurgeProfiler profiler;
-  private final PurgeDao purgeDao;
-  private final DefaultPeriodCleaner periodCleaner;
-
-  public ProjectPurgeTask(PurgeDao purgeDao, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler) {
-    this.purgeDao = purgeDao;
-    this.periodCleaner = periodCleaner;
-    this.profiler = profiler;
-  }
-
-  public ProjectPurgeTask purge(DbSession session, PurgeConfiguration configuration, Settings settings) {
-    long start = System.currentTimeMillis();
-    profiler.reset();
-    cleanHistoricalData(session, configuration.rootProjectId(), settings);
-    doPurge(session, configuration);
-    if (settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
-      long duration = System.currentTimeMillis() - start;
-      LOG.info("\n -------- Profiling for purge: " + TimeUtils.formatDuration(duration) + " --------\n");
-      profiler.dump(duration, LOG);
-      LOG.info("\n -------- End of profiling for purge --------\n");
-    }
-    return this;
-  }
-
-  private void cleanHistoricalData(DbSession session, long resourceId, Settings settings) {
-    try {
-      periodCleaner.clean(session, resourceId, settings);
-    } catch (Exception e) {
-      // purge errors must no fail the batch
-      LOG.error("Fail to clean historical data [id=" + resourceId + "]", e);
-    }
-  }
-
-  private void doPurge(DbSession session, PurgeConfiguration configuration) {
-    try {
-      purgeDao.purge(session, configuration);
-    } catch (Exception e) {
-      // purge errors must no fail the report analysis
-      LOG.error("Fail to purge data [id=" + configuration.rootProjectId() + "]", e);
-    }
-  }
-
-  public List<String> findUuidsToDisable(DbSession session, Long projectId) {
-    return purgeDao.selectPurgeableFiles(session, projectId);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/package-info.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/package-info.java
deleted file mode 100644 (file)
index 8a7156f..0000000
+++ /dev/null
@@ -1,24 +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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.core.computation.dbcleaner;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleaner.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleaner.java
deleted file mode 100644 (file)
index e87214d..0000000
+++ /dev/null
@@ -1,88 +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.core.computation.dbcleaner.period;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.config.Settings;
-import org.sonar.api.task.TaskExtension;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeSnapshotQuery;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.List;
-
-public class DefaultPeriodCleaner implements TaskExtension, ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(DefaultPeriodCleaner.class);
-  private PurgeDao purgeDao;
-  private Settings settings;
-  private MyBatis mybatis;
-
-  public DefaultPeriodCleaner(PurgeDao purgeDao, Settings settings, MyBatis mybatis) {
-    this.purgeDao = purgeDao;
-    this.settings = settings;
-    this.mybatis = mybatis;
-  }
-
-  public void clean(long projectId) {
-    clean(projectId, settings);
-  }
-
-  public void clean(long projectId, Settings settings) {
-    DbSession session = mybatis.openSession(true);
-    try {
-      doClean(projectId, new Filters(settings).all(), session);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public void clean(DbSession session, long projectId, Settings settings) {
-    doClean(projectId, new Filters(settings).all(), session);
-  }
-
-  @VisibleForTesting
-  void doClean(long projectId, List<Filter> filters, DbSession session) {
-    List<PurgeableSnapshotDto> history = selectProjectSnapshots(projectId, session);
-    for (Filter filter : filters) {
-      filter.log();
-      delete(filter.filter(history), session);
-    }
-  }
-
-  private void delete(List<PurgeableSnapshotDto> snapshots, DbSession session) {
-    for (PurgeableSnapshotDto snapshot : snapshots) {
-      LOG.info("<- Delete snapshot: " + DateUtils.formatDateTime(snapshot.getDate()) + " [" + snapshot.getSnapshotId() + "]");
-      purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setRootSnapshotId(snapshot.getSnapshotId()), session);
-      purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setId(snapshot.getSnapshotId()), session);
-    }
-  }
-
-  private List<PurgeableSnapshotDto> selectProjectSnapshots(long resourceId, DbSession session) {
-    return purgeDao.selectPurgeableSnapshots(resourceId, session);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilter.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilter.java
deleted file mode 100644 (file)
index 25dcb40..0000000
+++ /dev/null
@@ -1,53 +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.core.computation.dbcleaner.period;
-
-import com.google.common.collect.Lists;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Date;
-import java.util.List;
-
-class DeleteAllFilter implements Filter {
-  private final Date before;
-
-  public DeleteAllFilter(Date before) {
-    this.before = before;
-  }
-
-  @Override
-  public List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> history) {
-    List<PurgeableSnapshotDto> result = Lists.newArrayList();
-    for (PurgeableSnapshotDto snapshot : history) {
-      if (snapshot.getDate().before(before)) {
-        result.add(snapshot);
-      }
-    }
-    return result;
-  }
-
-  @Override
-  public void log() {
-    LoggerFactory.getLogger(getClass()).info("-> Delete data prior to: " + DateUtils.formatDate(before));
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filter.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filter.java
deleted file mode 100644 (file)
index ef4a375..0000000
+++ /dev/null
@@ -1,31 +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.core.computation.dbcleaner.period;
-
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.List;
-
-interface Filter {
-  List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> snapshots);
-
-  void log();
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filters.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filters.java
deleted file mode 100644 (file)
index 8e59596..0000000
+++ /dev/null
@@ -1,60 +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.core.computation.dbcleaner.period;
-
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.api.config.Settings;
-import org.sonar.core.computation.dbcleaner.DbCleanerConstants;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-
-class Filters {
-  private final List<Filter> all = Lists.newArrayList();
-
-  Filters(Settings settings) {
-    Date dateToStartKeepingOneSnapshotByDay = getDateFromHours(settings, DbCleanerConstants.HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY);
-    Date dateToStartKeepingOneSnapshotByWeek = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK);
-    Date dateToStartKeepingOneSnapshotByMonth = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH);
-    Date dateToStartDeletingAllSnapshots = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS);
-
-    all.add(new KeepOneFilter(dateToStartKeepingOneSnapshotByWeek, dateToStartKeepingOneSnapshotByDay, Calendar.DAY_OF_YEAR, "day"));
-    all.add(new KeepOneFilter(dateToStartKeepingOneSnapshotByMonth, dateToStartKeepingOneSnapshotByWeek, Calendar.WEEK_OF_YEAR, "week"));
-    all.add(new KeepOneFilter(dateToStartDeletingAllSnapshots, dateToStartKeepingOneSnapshotByMonth, Calendar.MONTH, "month"));
-    all.add(new DeleteAllFilter(dateToStartDeletingAllSnapshots));
-  }
-
-  static Date getDateFromWeeks(Settings settings, String propertyKey) {
-    int weeks = settings.getInt(propertyKey);
-    return DateUtils.addWeeks(new Date(), -weeks);
-  }
-
-  static Date getDateFromHours(Settings settings, String propertyKey) {
-    int hours = settings.getInt(propertyKey);
-    return DateUtils.addHours(new Date(), -hours);
-  }
-
-  List<Filter> all() {
-    return all;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Interval.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Interval.java
deleted file mode 100644 (file)
index 5676a85..0000000
+++ /dev/null
@@ -1,74 +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.core.computation.dbcleaner.period;
-
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.List;
-
-final class Interval {
-  List<PurgeableSnapshotDto> snapshots = Lists.newArrayList();
-
-  void add(PurgeableSnapshotDto snapshot) {
-    snapshots.add(snapshot);
-  }
-
-  List<PurgeableSnapshotDto> get() {
-    return snapshots;
-  }
-
-  int count() {
-    return snapshots.size();
-  }
-
-  static List<Interval> group(List<PurgeableSnapshotDto> snapshots, Date start, Date end, int calendarField) {
-    List<Interval> intervals = Lists.newArrayList();
-
-    GregorianCalendar calendar = new GregorianCalendar();
-    int lastYear = -1;
-    int lastFieldValue = -1;
-    Interval currentInterval = null;
-
-    for (PurgeableSnapshotDto snapshot : snapshots) {
-      if (!DateUtils.isSameDay(start, snapshot.getDate()) && snapshot.getDate().after(start) &&
-        (snapshot.getDate().before(end) || DateUtils.isSameDay(end, snapshot.getDate()))) {
-        calendar.setTime(snapshot.getDate());
-        int currentFieldValue = calendar.get(calendarField);
-        int currentYear = calendar.get(Calendar.YEAR);
-        if (lastYear!=currentYear || lastFieldValue != currentFieldValue) {
-          currentInterval = new Interval();
-          intervals.add(currentInterval);
-        }
-        lastFieldValue = currentFieldValue;
-        lastYear = currentYear;
-        if (currentInterval != null) {
-          currentInterval.add(snapshot);
-        }
-      }
-    }
-    return intervals;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilter.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilter.java
deleted file mode 100644 (file)
index 419add8..0000000
+++ /dev/null
@@ -1,89 +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.core.computation.dbcleaner.period;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Date;
-import java.util.List;
-
-class KeepOneFilter implements Filter {
-
-  private final Date start;
-  private final Date end;
-  private final int dateField;
-  private final String label;
-
-  KeepOneFilter(Date start, Date end, int calendarField, String label) {
-    this.start = start;
-    this.end = end;
-    this.dateField = calendarField;
-    this.label = label;
-  }
-
-  @Override
-  public List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> history) {
-    List<Interval> intervals = Interval.group(history, start, end, dateField);
-    List<PurgeableSnapshotDto> result = Lists.newArrayList();
-    for (Interval interval : intervals) {
-      appendSnapshotsToDelete(interval, result);
-    }
-
-    return result;
-  }
-
-  @Override
-  public void log() {
-    LoggerFactory.getLogger(getClass()).info("-> Keep one snapshot per " + label + " between " + DateUtils.formatDate(start) + " and " + DateUtils.formatDate(end));
-  }
-
-  private void appendSnapshotsToDelete(Interval interval, List<PurgeableSnapshotDto> toDelete) {
-    if (interval.count() > 1) {
-      List<PurgeableSnapshotDto> deletables = Lists.newArrayList();
-      List<PurgeableSnapshotDto> toKeep = Lists.newArrayList();
-      for (PurgeableSnapshotDto snapshot : interval.get()) {
-        if (isDeletable(snapshot)) {
-          deletables.add(snapshot);
-        } else {
-          toKeep.add(snapshot);
-        }
-      }
-
-      if (!toKeep.isEmpty()) {
-        toDelete.addAll(deletables);
-
-      } else if (deletables.size() > 1) {
-        // keep one snapshot
-        toDelete.addAll(deletables.subList(1, deletables.size()));
-      }
-    }
-  }
-
-  @VisibleForTesting
-  static boolean isDeletable(PurgeableSnapshotDto snapshot) {
-    return !snapshot.isLast() && !snapshot.hasEvents();
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/package-info.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/package-info.java
deleted file mode 100644 (file)
index 283ef7f..0000000
+++ /dev/null
@@ -1,24 +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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.core.computation.dbcleaner.period;
-
-import javax.annotation.ParametersAreNonnullByDefault;
index d10afcf4cf991c99a839563ed8e13d1b153c0da6..0bb4bb69e0a0ef0ffd3470be6087d56a87614742 100644 (file)
@@ -24,7 +24,7 @@ import com.google.common.collect.Lists;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.resources.Qualifiers;
-import org.sonar.core.computation.dbcleaner.DataCleanerProperties;
+import org.sonar.server.computation.dbcleaner.DataCleanerProperties;
 
 import java.util.List;
 
index d3fc9c1c4bd78dd554faf627a1d19f0e16c064b0..37886b3073288e1151e38b2e9e508c5b367859f3 100644 (file)
@@ -24,7 +24,7 @@ import org.apache.commons.lang.time.DateUtils;
 import org.sonar.api.config.Settings;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.utils.System2;
-import org.sonar.core.computation.dbcleaner.DbCleanerConstants;
+import org.sonar.server.computation.dbcleaner.DbCleanerConstants;
 
 import javax.annotation.CheckForNull;
 
index 8cad98c10c5d700e82ab3614d5332e71bb5a78f9..53fc44ede3a5931db46b657a73a6c3ef910f9839 100644 (file)
@@ -23,5 +23,5 @@ package org.sonar.plugins.dbcleaner.api;
  * @deprecated (is used by the plugin views only. Will rely on the implementation when views analysis views moved on the server side)
  */
 @Deprecated
-public interface DbCleanerConstants extends org.sonar.core.computation.dbcleaner.DbCleanerConstants {
+public interface DbCleanerConstants extends org.sonar.server.computation.dbcleaner.DbCleanerConstants {
 }
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DataCleanerProperties.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DataCleanerProperties.java
new file mode 100644 (file)
index 0000000..902a363
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.dbcleaner;
+
+import org.sonar.api.CoreProperties;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.resources.Qualifiers;
+
+import java.util.Arrays;
+import java.util.List;
+
+public final class DataCleanerProperties {
+
+  private DataCleanerProperties() {
+  }
+
+  public static List<PropertyDefinition> all() {
+    return Arrays.asList(
+      PropertyDefinition.builder(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY)
+        .defaultValue("true")
+        .name("Clean directory/package history")
+        .description("If set to true, no history is kept at directory/package level. Setting this to false can cause database bloat.")
+        .type(PropertyType.BOOLEAN)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(1)
+        .build(),
+
+      PropertyDefinition.builder(DbCleanerConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES)
+        .defaultValue("30")
+        .name("Delete closed issues after")
+        .description("Issues that have been closed for more than this number of days will be deleted.")
+        .type(PropertyType.INTEGER)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(2)
+        .build(),
+
+      PropertyDefinition.builder(DbCleanerConstants.HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY)
+        .defaultValue("24")
+        .name("Keep only one snapshot a day after")
+        .description("After this number of hours, if there are several snapshots during the same day, "
+          + "the DbCleaner keeps the most recent one and fully deletes the other ones.")
+        .type(PropertyType.INTEGER)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(3)
+        .build(),
+
+      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK)
+        .defaultValue("4")
+        .name("Keep only one snapshot a week after")
+        .description("After this number of weeks, if there are several snapshots during the same week, "
+          + "the DbCleaner keeps the most recent one and fully deletes the other ones")
+        .type(PropertyType.INTEGER)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(4)
+        .build(),
+
+      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH)
+        .defaultValue("52")
+        .name("Keep only one snapshot a month after")
+        .description("After this number of weeks, if there are several snapshots during the same month, "
+          + "the DbCleaner keeps the most recent one and fully deletes the other ones.")
+        .type(PropertyType.INTEGER)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(5)
+        .build(),
+
+      PropertyDefinition.builder(DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS)
+        .defaultValue("260")
+        .name("Delete all snapshots after")
+        .description("After this number of weeks, all snapshots are fully deleted.")
+        .type(PropertyType.INTEGER)
+        .onQualifiers(Qualifiers.PROJECT)
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
+        .index(6)
+        .build()
+      );
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DbCleanerConstants.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DbCleanerConstants.java
new file mode 100644 (file)
index 0000000..fbd853e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.dbcleaner;
+
+public interface DbCleanerConstants {
+
+  String PLUGIN_KEY = "dbcleaner";
+  String PLUGIN_NAME = "DbCleaner";
+  String PROPERTY_CLEAN_DIRECTORY = "sonar.dbcleaner.cleanDirectory";
+
+  String HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY = "sonar.dbcleaner.hoursBeforeKeepingOnlyOneSnapshotByDay";
+  String WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK = "sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByWeek";
+  String WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH = "sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByMonth";
+  String WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS = "sonar.dbcleaner.weeksBeforeDeletingAllSnapshots";
+  String DAYS_BEFORE_DELETING_CLOSED_ISSUES = "sonar.dbcleaner.daysBeforeDeletingClosedIssues";
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTask.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTask.java
new file mode 100644 (file)
index 0000000..188164e
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.dbcleaner;
+
+import com.google.common.annotations.VisibleForTesting;
+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.TimeUtils;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.core.purge.IdUuidPair;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeProfiler;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.ResourceDto;
+import org.sonar.plugins.dbcleaner.api.PurgeTask;
+
+import static org.sonar.core.purge.PurgeConfiguration.newDefaultPurgeConfiguration;
+
+/**
+ * @since 2.14
+ */
+public class DefaultPurgeTask implements PurgeTask {
+  private static final Logger LOG = LoggerFactory.getLogger(DefaultPurgeTask.class);
+  private final PurgeProfiler profiler;
+  private final PurgeDao purgeDao;
+  private final ResourceDao resourceDao;
+  private final Settings settings;
+  private final DefaultPeriodCleaner periodCleaner;
+
+  public DefaultPurgeTask(PurgeDao purgeDao, ResourceDao resourceDao, Settings settings, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler) {
+    this.purgeDao = purgeDao;
+    this.resourceDao = resourceDao;
+    this.settings = settings;
+    this.periodCleaner = periodCleaner;
+    this.profiler = profiler;
+  }
+
+  @Override
+  public DefaultPurgeTask delete(long resourceId) {
+    ResourceDto project = resourceDao.getResource(resourceId);
+    purgeDao.deleteResourceTree(new IdUuidPair(project.getId(), project.getUuid()));
+    return this;
+  }
+
+  @VisibleForTesting
+  boolean isNotViewNorSubview(String resourceQualifier) {
+    return !(Qualifiers.VIEW.equals(resourceQualifier) || Qualifiers.SUBVIEW.equals(resourceQualifier));
+  }
+
+  @Override
+  public DefaultPurgeTask purge(long resourceId) {
+    long start = System.currentTimeMillis();
+    String resourceQualifier = resourceDao.getResource(resourceId).getQualifier();
+    if (isNotViewNorSubview(resourceQualifier)) {
+      profiler.reset();
+      cleanHistoricalData(resourceId);
+      doPurge(resourceId);
+      if (settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
+        long duration = System.currentTimeMillis() - start;
+        LOG.info("\n -------- Profiling for purge: " + TimeUtils.formatDuration(duration) + " --------\n");
+        profiler.dump(duration, LOG);
+        LOG.info("\n -------- End of profiling for purge --------\n");
+      }
+    }
+    return this;
+  }
+
+  private void cleanHistoricalData(long resourceId) {
+    try {
+      periodCleaner.clean(resourceId);
+    } catch (Exception e) {
+      // purge errors must no fail the batch
+      LOG.error("Fail to clean historical data [id=" + resourceId + "]", e);
+    }
+  }
+
+  private void doPurge(long resourceId) {
+    try {
+      purgeDao.purge(newPurgeConfigurationOnResource(resourceId));
+    } catch (Exception e) {
+      // purge errors must no fail the report analysis
+      LOG.error("Fail to purge data [id=" + resourceId + "]", e);
+    }
+  }
+
+  public PurgeConfiguration newPurgeConfigurationOnResource(long resourceId) {
+    return newDefaultPurgeConfiguration(settings, resourceId);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/package-info.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/package-info.java
new file mode 100644 (file)
index 0000000..f3a8c77
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.dbcleaner;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleaner.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleaner.java
new file mode 100644 (file)
index 0000000..0fcf523
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.config.Settings;
+import org.sonar.api.task.TaskExtension;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeSnapshotQuery;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.List;
+
+public class DefaultPeriodCleaner implements TaskExtension, ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(DefaultPeriodCleaner.class);
+  private PurgeDao purgeDao;
+  private Settings settings;
+  private MyBatis mybatis;
+
+  public DefaultPeriodCleaner(PurgeDao purgeDao, Settings settings, MyBatis mybatis) {
+    this.purgeDao = purgeDao;
+    this.settings = settings;
+    this.mybatis = mybatis;
+  }
+
+  public void clean(long projectId) {
+    clean(projectId, settings);
+  }
+
+  public void clean(long projectId, Settings settings) {
+    DbSession session = mybatis.openSession(true);
+    try {
+      doClean(projectId, new Filters(settings).all(), session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void clean(DbSession session, long projectId, Settings settings) {
+    doClean(projectId, new Filters(settings).all(), session);
+  }
+
+  @VisibleForTesting
+  void doClean(long projectId, List<Filter> filters, DbSession session) {
+    List<PurgeableSnapshotDto> history = selectProjectSnapshots(projectId, session);
+    for (Filter filter : filters) {
+      filter.log();
+      delete(filter.filter(history), session);
+    }
+  }
+
+  private void delete(List<PurgeableSnapshotDto> snapshots, DbSession session) {
+    for (PurgeableSnapshotDto snapshot : snapshots) {
+      LOG.info("<- Delete snapshot: " + DateUtils.formatDateTime(snapshot.getDate()) + " [" + snapshot.getSnapshotId() + "]");
+      purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setRootSnapshotId(snapshot.getSnapshotId()), session);
+      purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setId(snapshot.getSnapshotId()), session);
+    }
+  }
+
+  private List<PurgeableSnapshotDto> selectProjectSnapshots(long resourceId, DbSession session) {
+    return purgeDao.selectPurgeableSnapshots(resourceId, session);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilter.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilter.java
new file mode 100644 (file)
index 0000000..83c8a9e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.collect.Lists;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.Date;
+import java.util.List;
+
+class DeleteAllFilter implements Filter {
+  private final Date before;
+
+  public DeleteAllFilter(Date before) {
+    this.before = before;
+  }
+
+  @Override
+  public List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> history) {
+    List<PurgeableSnapshotDto> result = Lists.newArrayList();
+    for (PurgeableSnapshotDto snapshot : history) {
+      if (snapshot.getDate().before(before)) {
+        result.add(snapshot);
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public void log() {
+    LoggerFactory.getLogger(getClass()).info("-> Delete data prior to: " + DateUtils.formatDate(before));
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filter.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filter.java
new file mode 100644 (file)
index 0000000..c4bf00a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.dbcleaner.period;
+
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.List;
+
+interface Filter {
+  List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> snapshots);
+
+  void log();
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filters.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Filters.java
new file mode 100644 (file)
index 0000000..929316c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.time.DateUtils;
+import org.sonar.api.config.Settings;
+import org.sonar.server.computation.dbcleaner.DbCleanerConstants;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+class Filters {
+  private final List<Filter> all = Lists.newArrayList();
+
+  Filters(Settings settings) {
+    Date dateToStartKeepingOneSnapshotByDay = getDateFromHours(settings, DbCleanerConstants.HOURS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_DAY);
+    Date dateToStartKeepingOneSnapshotByWeek = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK);
+    Date dateToStartKeepingOneSnapshotByMonth = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH);
+    Date dateToStartDeletingAllSnapshots = getDateFromWeeks(settings, DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS);
+
+    all.add(new KeepOneFilter(dateToStartKeepingOneSnapshotByWeek, dateToStartKeepingOneSnapshotByDay, Calendar.DAY_OF_YEAR, "day"));
+    all.add(new KeepOneFilter(dateToStartKeepingOneSnapshotByMonth, dateToStartKeepingOneSnapshotByWeek, Calendar.WEEK_OF_YEAR, "week"));
+    all.add(new KeepOneFilter(dateToStartDeletingAllSnapshots, dateToStartKeepingOneSnapshotByMonth, Calendar.MONTH, "month"));
+    all.add(new DeleteAllFilter(dateToStartDeletingAllSnapshots));
+  }
+
+  static Date getDateFromWeeks(Settings settings, String propertyKey) {
+    int weeks = settings.getInt(propertyKey);
+    return DateUtils.addWeeks(new Date(), -weeks);
+  }
+
+  static Date getDateFromHours(Settings settings, String propertyKey) {
+    int hours = settings.getInt(propertyKey);
+    return DateUtils.addHours(new Date(), -hours);
+  }
+
+  List<Filter> all() {
+    return all;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Interval.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/Interval.java
new file mode 100644 (file)
index 0000000..a4ef804
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.time.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+final class Interval {
+  List<PurgeableSnapshotDto> snapshots = Lists.newArrayList();
+
+  void add(PurgeableSnapshotDto snapshot) {
+    snapshots.add(snapshot);
+  }
+
+  List<PurgeableSnapshotDto> get() {
+    return snapshots;
+  }
+
+  int count() {
+    return snapshots.size();
+  }
+
+  static List<Interval> group(List<PurgeableSnapshotDto> snapshots, Date start, Date end, int calendarField) {
+    List<Interval> intervals = Lists.newArrayList();
+
+    GregorianCalendar calendar = new GregorianCalendar();
+    int lastYear = -1;
+    int lastFieldValue = -1;
+    Interval currentInterval = null;
+
+    for (PurgeableSnapshotDto snapshot : snapshots) {
+      if (!DateUtils.isSameDay(start, snapshot.getDate()) && snapshot.getDate().after(start) &&
+        (snapshot.getDate().before(end) || DateUtils.isSameDay(end, snapshot.getDate()))) {
+        calendar.setTime(snapshot.getDate());
+        int currentFieldValue = calendar.get(calendarField);
+        int currentYear = calendar.get(Calendar.YEAR);
+        if (lastYear!=currentYear || lastFieldValue != currentFieldValue) {
+          currentInterval = new Interval();
+          intervals.add(currentInterval);
+        }
+        lastFieldValue = currentFieldValue;
+        lastYear = currentYear;
+        if (currentInterval != null) {
+          currentInterval.add(snapshot);
+        }
+      }
+    }
+    return intervals;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilter.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilter.java
new file mode 100644 (file)
index 0000000..32bda2c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.Date;
+import java.util.List;
+
+class KeepOneFilter implements Filter {
+
+  private final Date start;
+  private final Date end;
+  private final int dateField;
+  private final String label;
+
+  KeepOneFilter(Date start, Date end, int calendarField, String label) {
+    this.start = start;
+    this.end = end;
+    this.dateField = calendarField;
+    this.label = label;
+  }
+
+  @Override
+  public List<PurgeableSnapshotDto> filter(List<PurgeableSnapshotDto> history) {
+    List<Interval> intervals = Interval.group(history, start, end, dateField);
+    List<PurgeableSnapshotDto> result = Lists.newArrayList();
+    for (Interval interval : intervals) {
+      appendSnapshotsToDelete(interval, result);
+    }
+
+    return result;
+  }
+
+  @Override
+  public void log() {
+    LoggerFactory.getLogger(getClass()).info("-> Keep one snapshot per " + label + " between " + DateUtils.formatDate(start) + " and " + DateUtils.formatDate(end));
+  }
+
+  private void appendSnapshotsToDelete(Interval interval, List<PurgeableSnapshotDto> toDelete) {
+    if (interval.count() > 1) {
+      List<PurgeableSnapshotDto> deletables = Lists.newArrayList();
+      List<PurgeableSnapshotDto> toKeep = Lists.newArrayList();
+      for (PurgeableSnapshotDto snapshot : interval.get()) {
+        if (isDeletable(snapshot)) {
+          deletables.add(snapshot);
+        } else {
+          toKeep.add(snapshot);
+        }
+      }
+
+      if (!toKeep.isEmpty()) {
+        toDelete.addAll(deletables);
+
+      } else if (deletables.size() > 1) {
+        // keep one snapshot
+        toDelete.addAll(deletables.subList(1, deletables.size()));
+      }
+    }
+  }
+
+  @VisibleForTesting
+  static boolean isDeletable(PurgeableSnapshotDto snapshot) {
+    return !snapshot.isLast() && !snapshot.hasEvents();
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/package-info.java b/sonar-core/src/main/java/org/sonar/server/computation/dbcleaner/period/package-info.java
new file mode 100644 (file)
index 0000000..1f547e8
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.dbcleaner.period;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DataCleanerPropertiesTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DataCleanerPropertiesTest.java
deleted file mode 100644 (file)
index da34eb6..0000000
+++ /dev/null
@@ -1,33 +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.core.computation.dbcleaner;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class DataCleanerPropertiesTest {
-
-  @Test
-  public void shouldGetExtensions() {
-    assertThat(DataCleanerProperties.all()).hasSize(6);
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerTestUtils.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerTestUtils.java
deleted file mode 100644 (file)
index 392e58c..0000000
+++ /dev/null
@@ -1,45 +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.core.computation.dbcleaner;
-
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-public final class DbCleanerTestUtils {
-
-  private DbCleanerTestUtils() {
-  }
-
-  public static PurgeableSnapshotDto createSnapshotWithDate(long snapshotId, String date) {
-    PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
-    snapshot.setSnapshotId(snapshotId);
-    snapshot.setDate(DateUtils.parseDate(date));
-    return snapshot;
-  }
-
-  public static PurgeableSnapshotDto createSnapshotWithDateTime(long snapshotId, String datetime) {
-    PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
-    snapshot.setSnapshotId(snapshotId);
-    snapshot.setDate(DateUtils.parseDateTime(datetime));
-    return snapshot;
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTaskTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTaskTest.java
deleted file mode 100644 (file)
index c03d4ad..0000000
+++ /dev/null
@@ -1,149 +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.core.computation.dbcleaner;
-
-import ch.qos.logback.classic.Logger;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
-import org.sonar.core.purge.IdUuidPair;
-import org.sonar.core.purge.PurgeConfiguration;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeProfiler;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
-
-public class DefaultPurgeTaskTest {
-
-  private DefaultPurgeTask sut;
-  private ResourceDao resourceDao;
-  private PurgeDao purgeDao;
-  private Settings settings;
-  private DefaultPeriodCleaner periodCleaner;
-  private PurgeProfiler profiler;
-
-  @Before
-  public void before() throws Exception {
-    this.purgeDao = mock(PurgeDao.class);
-    this.resourceDao = mock(ResourceDao.class);
-    when(resourceDao.getResource(anyLong())).thenReturn(new ResourceDto().setQualifier(Qualifiers.PROJECT));
-
-    this.settings = mock(Settings.class);
-    this.periodCleaner = mock(DefaultPeriodCleaner.class);
-    this.profiler = mock(PurgeProfiler.class);
-
-    this.sut = new DefaultPurgeTask(purgeDao, resourceDao, settings, periodCleaner, profiler);
-  }
-
-  @Test
-  public void shouldNotDeleteHistoricalDataOfDirectories() {
-    PurgeDao purgeDao = mock(PurgeDao.class);
-    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
-    settings.setProperty(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY, "false");
-    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
-
-    task.purge(1L);
-
-    verify(purgeDao).purge(argThat(new ArgumentMatcher<PurgeConfiguration>() {
-      @Override
-      public boolean matches(Object o) {
-        PurgeConfiguration conf = (PurgeConfiguration) o;
-        return conf.rootProjectId() == 1L && conf.scopesWithoutHistoricalData().length == 1 && conf.scopesWithoutHistoricalData()[0].equals(Scopes.FILE);
-      }
-    }));
-  }
-
-  @Test
-  public void shouldDeleteHistoricalDataOfDirectoriesByDefault() {
-    PurgeDao purgeDao = mock(PurgeDao.class);
-    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
-    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
-
-    task.purge(1L);
-
-    verify(purgeDao).purge(argThat(new ArgumentMatcher<PurgeConfiguration>() {
-      @Override
-      public boolean matches(Object o) {
-        PurgeConfiguration conf = (PurgeConfiguration) o;
-        return conf.rootProjectId() == 1L &&
-          conf.scopesWithoutHistoricalData().length == 2 &&
-          conf.scopesWithoutHistoricalData()[0].equals(Scopes.DIRECTORY) &&
-          conf.scopesWithoutHistoricalData()[1].equals(Scopes.FILE);
-      }
-    }));
-  }
-
-  @Test
-  public void shouldNotFailOnErrors() {
-    PurgeDao purgeDao = mock(PurgeDao.class);
-    when(purgeDao.purge(any(PurgeConfiguration.class))).thenThrow(new RuntimeException());
-    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, new Settings(), mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
-
-    task.purge(1L);
-
-    verify(purgeDao, times(1)).purge(any(PurgeConfiguration.class));
-  }
-
-  @Test
-  public void shouldDumpProfiling() {
-    PurgeConfiguration conf = new PurgeConfiguration(1L, new String[0], 30);
-    PurgeDao purgeDao = mock(PurgeDao.class);
-    when(purgeDao.purge(conf)).thenThrow(new RuntimeException());
-    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
-    settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, true);
-    PurgeProfiler profiler = mock(PurgeProfiler.class);
-
-    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), profiler);
-    task.purge(1L);
-
-    verify(profiler).dump(anyLong(), any(Logger.class));
-  }
-
-  @Test
-  public void recognize_view_and_subview() {
-    boolean viewCheck = sut.isNotViewNorSubview(Qualifiers.VIEW);
-    boolean subViewCheck = sut.isNotViewNorSubview(Qualifiers.SUBVIEW);
-
-    assertThat(viewCheck).isFalse();
-    assertThat(subViewCheck).isFalse();
-  }
-
-  @Test
-  public void call_dao_delete_when_deleting() throws Exception {
-    when(resourceDao.getResource(123L)).thenReturn(new ResourceDto().setId(123L).setUuid("A"));
-
-    sut.delete(123L);
-
-    verify(purgeDao, times(1)).deleteResourceTree(any(IdUuidPair.class));
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTaskTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/ProjectPurgeTaskTest.java
deleted file mode 100644 (file)
index de25c31..0000000
+++ /dev/null
@@ -1,91 +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.core.computation.dbcleaner;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.purge.PurgeConfiguration;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeProfiler;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.*;
-
-public class ProjectPurgeTaskTest {
-
-  private ProjectPurgeTask sut;
-  private PurgeDao dao;
-  private PurgeProfiler profiler;
-  private DefaultPeriodCleaner periodCleaner;
-
-  @Before
-  public void before() throws Exception {
-    this.dao = mock(PurgeDao.class);
-    this.profiler = mock(PurgeProfiler.class);
-    this.periodCleaner = mock(DefaultPeriodCleaner.class);
-
-    this.sut = new ProjectPurgeTask(dao, periodCleaner, profiler);
-  }
-
-  @Test
-  public void no_profiling_when_property_is_false() throws Exception {
-    Settings settings = mock(Settings.class);
-    when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(false);
-
-    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), settings);
-
-    verify(profiler, never()).dump(anyLong(), any(Logger.class));
-  }
-
-  @Test
-  public void profiling_when_property_is_true() throws Exception {
-    Settings settings = mock(Settings.class);
-    when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(true);
-
-    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), settings);
-
-    verify(profiler, times(1)).dump(anyLong(), any(Logger.class));
-  }
-
-  @Test
-  public void if_dao_purge_fails_it_should_not_interrupt_program_execution() throws Exception {
-    doThrow(RuntimeException.class).when(dao).purge(any(DbSession.class), any(PurgeConfiguration.class));
-
-    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), mock(Settings.class));
-
-    verify(dao, times(1)).purge(any(DbSession.class), any(PurgeConfiguration.class));
-  }
-
-  @Test
-  public void if_profiler_cleaning_fails_it_should_not_interrupt_program_execution() throws Exception {
-    doThrow(RuntimeException.class).when(periodCleaner).clean(any(DbSession.class), anyLong(), any(Settings.class));
-
-    sut.purge(mock(DbSession.class), mock(PurgeConfiguration.class), mock(Settings.class));
-
-    verify(periodCleaner, times(1)).clean(any(DbSession.class), anyLong(), any(Settings.class));
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleanerTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleanerTest.java
deleted file mode 100644 (file)
index 759dac5..0000000
+++ /dev/null
@@ -1,96 +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.core.computation.dbcleaner.period;
-
-import org.apache.commons.lang.ObjectUtils;
-import org.hamcrest.BaseMatcher;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.config.Settings;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.purge.PurgeDao;
-import org.sonar.core.purge.PurgeSnapshotQuery;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Arrays;
-import java.util.Date;
-
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultPeriodCleanerTest {
-
-  @Test
-  public void doClean() {
-    PurgeDao dao = mock(PurgeDao.class);
-    DbSession session = mock(DbSession.class);
-    when(dao.selectPurgeableSnapshots(123L, session)).thenReturn(Arrays.asList(
-      new PurgeableSnapshotDto().setSnapshotId(999L).setDate(new Date())));
-    Filter filter1 = newLazyFilter();
-    Filter filter2 = newLazyFilter();
-
-    DefaultPeriodCleaner cleaner = new DefaultPeriodCleaner(dao, mock(Settings.class), mock(MyBatis.class));
-    cleaner.doClean(123L, Arrays.asList(filter1, filter2), session);
-
-    verify(filter1).log();
-    verify(filter2).log();
-    verify(dao, times(2)).deleteSnapshots(argThat(newRootSnapshotQuery()), eq(session));
-    verify(dao, times(2)).deleteSnapshots(argThat(newSnapshotIdQuery()), eq(session));
-  }
-
-  private BaseMatcher<PurgeSnapshotQuery> newRootSnapshotQuery() {
-    return new ArgumentMatcher<PurgeSnapshotQuery>() {
-      @Override
-      public boolean matches(Object o) {
-        PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
-        return ObjectUtils.equals(query.getRootSnapshotId(), 999L);
-      }
-    };
-  }
-
-  private BaseMatcher<PurgeSnapshotQuery> newSnapshotIdQuery() {
-    return new ArgumentMatcher<PurgeSnapshotQuery>() {
-      @Override
-      public boolean matches(Object o) {
-        PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
-        return ObjectUtils.equals(query.getId(), 999L);
-      }
-    };
-  }
-
-  private Filter newLazyFilter() {
-    Filter filter1 = mock(Filter.class);
-    when(filter1.filter(anyListOf(PurgeableSnapshotDto.class))).thenAnswer(new Answer<Object>() {
-      public Object answer(InvocationOnMock invocation) throws Throwable {
-        return invocation.getArguments()[0];
-      }
-    });
-    return filter1;
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilterTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilterTest.java
deleted file mode 100644 (file)
index 2a84512..0000000
+++ /dev/null
@@ -1,47 +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.core.computation.dbcleaner.period;
-
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.computation.dbcleaner.DbCleanerTestUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class DeleteAllFilterTest {
-
-  @Test
-  public void shouldDeleteAllSnapshotsPriorToDate() {
-    Filter filter = new DeleteAllFilter(DateUtils.parseDate("2011-12-25"));
-
-    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.asList(
-      DbCleanerTestUtils.createSnapshotWithDate(1L, "2010-01-01"),
-      DbCleanerTestUtils.createSnapshotWithDate(2L, "2010-12-25"),
-      DbCleanerTestUtils.createSnapshotWithDate(3L, "2012-01-01")
-      ));
-
-    assertThat(toDelete).onProperty("snapshotId").containsOnly(1L, 2L);
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/IntervalTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/IntervalTest.java
deleted file mode 100644 (file)
index a9c5aec..0000000
+++ /dev/null
@@ -1,108 +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.core.computation.dbcleaner.period;
-
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.List;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.sonar.core.computation.dbcleaner.DbCleanerTestUtils.createSnapshotWithDate;
-import static org.sonar.core.computation.dbcleaner.DbCleanerTestUtils.createSnapshotWithDateTime;
-
-public class IntervalTest {
-  static int calendarField(Interval interval, int field) {
-    if (interval.count() == 0) {
-      return -1;
-    }
-
-    PurgeableSnapshotDto first = interval.get().iterator().next();
-    GregorianCalendar cal = new GregorianCalendar();
-    cal.setTime(first.getDate());
-    return cal.get(field);
-  }
-
-  @Test
-  public void shouldGroupByIntervals() {
-    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
-      createSnapshotWithDate(1L, "2011-04-03"),
-
-      createSnapshotWithDate(2L, "2011-05-01"),
-      createSnapshotWithDate(3L, "2011-05-19"),
-
-      createSnapshotWithDate(4L, "2011-06-02"),
-      createSnapshotWithDate(5L, "2011-06-20"),
-
-      createSnapshotWithDate(6L, "2012-06-29") // out of scope
-      );
-
-    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2010-01-01"), DateUtils.parseDate("2011-12-31"), Calendar.MONTH);
-    assertThat(intervals.size(), is(3));
-
-    assertThat(intervals.get(0).count(), is(1));
-    assertThat(calendarField(intervals.get(0), Calendar.MONTH), is(Calendar.APRIL));
-
-    assertThat(intervals.get(1).count(), is(2));
-    assertThat(calendarField(intervals.get(1), Calendar.MONTH), is(Calendar.MAY));
-
-    assertThat(intervals.get(2).count(), is(2));
-    assertThat(calendarField(intervals.get(2), Calendar.MONTH), is(Calendar.JUNE));
-  }
-
-  @Test
-  public void shouldNotJoinMonthsOfDifferentYears() {
-    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
-      createSnapshotWithDate(1L, "2010-04-03"),
-      createSnapshotWithDate(2L, "2011-04-13")
-      );
-
-    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2010-01-01"), DateUtils.parseDate("2011-12-31"), Calendar.MONTH);
-    assertThat(intervals.size(), is(2));
-
-    assertThat(intervals.get(0).count(), is(1));
-    assertThat(calendarField(intervals.get(0), Calendar.MONTH), is(Calendar.APRIL));
-    assertThat(calendarField(intervals.get(0), Calendar.YEAR), is(2010));
-
-    assertThat(intervals.get(1).count(), is(1));
-    assertThat(calendarField(intervals.get(1), Calendar.MONTH), is(Calendar.APRIL));
-    assertThat(calendarField(intervals.get(1), Calendar.YEAR), is(2011));
-  }
-
-  @Test
-  public void shouldIgnoreTimeWhenGroupingByIntervals() {
-    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
-      createSnapshotWithDateTime(1L, "2011-05-25T16:16:48+0100"),
-      createSnapshotWithDateTime(2L, "2012-01-26T16:16:48+0100"),
-      createSnapshotWithDateTime(3L, "2012-01-27T16:16:48+0100")
-      );
-
-    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2011-05-25"), DateUtils.parseDate("2012-01-26"), Calendar.MONTH);
-    assertThat(intervals.size(), is(1));
-    assertThat(intervals.get(0).count(), is(1));
-    assertThat(intervals.get(0).get().get(0).getSnapshotId(), is(2L));
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilterTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilterTest.java
deleted file mode 100644 (file)
index 8e855f9..0000000
+++ /dev/null
@@ -1,95 +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.core.computation.dbcleaner.period;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.purge.PurgeableSnapshotDto;
-
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.sonar.core.computation.dbcleaner.DbCleanerTestUtils.createSnapshotWithDate;
-
-public class KeepOneFilterTest {
-
-  private static List<Long> snapshotIds(List<PurgeableSnapshotDto> snapshotDtos) {
-    return newArrayList(Iterables.transform(snapshotDtos, new Function<PurgeableSnapshotDto, Long>() {
-      @Override
-      public Long apply(@Nullable PurgeableSnapshotDto input) {
-        return input != null ? input.getSnapshotId() : null;
-      }
-    }));
-  }
-
-  @Test
-  public void shouldOnlyOneSnapshotPerInterval() {
-    Filter filter = new KeepOneFilter(DateUtils.parseDate("2011-03-25"), DateUtils.parseDate("2011-08-25"), Calendar.MONTH, "month");
-
-    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.<PurgeableSnapshotDto>asList(
-      createSnapshotWithDate(1L, "2010-01-01"), // out of scope -> keep
-      createSnapshotWithDate(2L, "2011-05-01"), // may -> keep
-      createSnapshotWithDate(3L, "2011-05-02"), // may -> to be deleted
-      createSnapshotWithDate(4L, "2011-05-19"), // may -> to be deleted
-      createSnapshotWithDate(5L, "2011-06-01"), // june -> keep
-      createSnapshotWithDate(6L, "2012-01-01") // out of scope -> keep
-      ));
-
-    assertThat(toDelete).hasSize(2);
-
-    List<Long> snapshotIds = snapshotIds(toDelete);
-    assertThat(snapshotIds).contains(3L);
-    assertThat(snapshotIds.contains(4L));
-  }
-
-  @Test
-  public void shouldKeepNonDeletableSnapshots() {
-    Filter filter = new KeepOneFilter(DateUtils.parseDate("2011-03-25"), DateUtils.parseDate("2011-08-25"), Calendar.MONTH, "month");
-
-    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.<PurgeableSnapshotDto>asList(
-      createSnapshotWithDate(1L, "2011-05-01"), // to be deleted
-      createSnapshotWithDate(2L, "2011-05-02").setLast(true),
-      createSnapshotWithDate(3L, "2011-05-19").setHasEvents(true).setLast(false),
-      createSnapshotWithDate(4L, "2011-05-23") // to be deleted
-      ));
-
-    assertThat(toDelete).hasSize(2);
-
-    List<Long> snapshotIds = snapshotIds(toDelete);
-    assertThat(snapshotIds).contains(1L);
-    assertThat(snapshotIds.contains(4L));
-  }
-
-  @Test
-  public void test_isDeletable() {
-    assertThat(KeepOneFilter.isDeletable(createSnapshotWithDate(1L, "2011-05-01"))).isTrue();
-    assertThat(KeepOneFilter.isDeletable(createSnapshotWithDate(1L, "2011-05-01").setLast(true))).isFalse();
-    assertThat(KeepOneFilter.isDeletable(createSnapshotWithDate(1L, "2011-05-01").setHasEvents(true))).isFalse();
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DataCleanerPropertiesTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DataCleanerPropertiesTest.java
new file mode 100644 (file)
index 0000000..645256d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.dbcleaner;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DataCleanerPropertiesTest {
+
+  @Test
+  public void shouldGetExtensions() {
+    assertThat(DataCleanerProperties.all()).hasSize(6);
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DbCleanerTestUtils.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DbCleanerTestUtils.java
new file mode 100644 (file)
index 0000000..6a62915
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.dbcleaner;
+
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+public final class DbCleanerTestUtils {
+
+  private DbCleanerTestUtils() {
+  }
+
+  public static PurgeableSnapshotDto createSnapshotWithDate(long snapshotId, String date) {
+    PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
+    snapshot.setSnapshotId(snapshotId);
+    snapshot.setDate(DateUtils.parseDate(date));
+    return snapshot;
+  }
+
+  public static PurgeableSnapshotDto createSnapshotWithDateTime(long snapshotId, String datetime) {
+    PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
+    snapshot.setSnapshotId(snapshotId);
+    snapshot.setDate(DateUtils.parseDateTime(datetime));
+    return snapshot;
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTaskTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/DefaultPurgeTaskTest.java
new file mode 100644 (file)
index 0000000..1ca4ffe
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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.dbcleaner;
+
+import ch.qos.logback.classic.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.server.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.core.purge.IdUuidPair;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeProfiler;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.ResourceDto;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.*;
+
+public class DefaultPurgeTaskTest {
+
+  private DefaultPurgeTask sut;
+  private ResourceDao resourceDao;
+  private PurgeDao purgeDao;
+  private Settings settings;
+  private DefaultPeriodCleaner periodCleaner;
+  private PurgeProfiler profiler;
+
+  @Before
+  public void before() throws Exception {
+    this.purgeDao = mock(PurgeDao.class);
+    this.resourceDao = mock(ResourceDao.class);
+    when(resourceDao.getResource(anyLong())).thenReturn(new ResourceDto().setQualifier(Qualifiers.PROJECT));
+
+    this.settings = mock(Settings.class);
+    this.periodCleaner = mock(DefaultPeriodCleaner.class);
+    this.profiler = mock(PurgeProfiler.class);
+
+    this.sut = new DefaultPurgeTask(purgeDao, resourceDao, settings, periodCleaner, profiler);
+  }
+
+  @Test
+  public void shouldNotDeleteHistoricalDataOfDirectories() {
+    PurgeDao purgeDao = mock(PurgeDao.class);
+    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
+    settings.setProperty(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY, "false");
+    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
+
+    task.purge(1L);
+
+    verify(purgeDao).purge(argThat(new ArgumentMatcher<PurgeConfiguration>() {
+      @Override
+      public boolean matches(Object o) {
+        PurgeConfiguration conf = (PurgeConfiguration) o;
+        return conf.rootProjectId() == 1L && conf.scopesWithoutHistoricalData().length == 1 && conf.scopesWithoutHistoricalData()[0].equals(Scopes.FILE);
+      }
+    }));
+  }
+
+  @Test
+  public void shouldDeleteHistoricalDataOfDirectoriesByDefault() {
+    PurgeDao purgeDao = mock(PurgeDao.class);
+    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
+    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
+
+    task.purge(1L);
+
+    verify(purgeDao).purge(argThat(new ArgumentMatcher<PurgeConfiguration>() {
+      @Override
+      public boolean matches(Object o) {
+        PurgeConfiguration conf = (PurgeConfiguration) o;
+        return conf.rootProjectId() == 1L &&
+          conf.scopesWithoutHistoricalData().length == 2 &&
+          conf.scopesWithoutHistoricalData()[0].equals(Scopes.DIRECTORY) &&
+          conf.scopesWithoutHistoricalData()[1].equals(Scopes.FILE);
+      }
+    }));
+  }
+
+  @Test
+  public void shouldNotFailOnErrors() {
+    PurgeDao purgeDao = mock(PurgeDao.class);
+    when(purgeDao.purge(any(PurgeConfiguration.class))).thenThrow(new RuntimeException());
+    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, new Settings(), mock(DefaultPeriodCleaner.class), mock(PurgeProfiler.class));
+
+    task.purge(1L);
+
+    verify(purgeDao, times(1)).purge(any(PurgeConfiguration.class));
+  }
+
+  @Test
+  public void shouldDumpProfiling() {
+    PurgeConfiguration conf = new PurgeConfiguration(1L, new String[0], 30);
+    PurgeDao purgeDao = mock(PurgeDao.class);
+    when(purgeDao.purge(conf)).thenThrow(new RuntimeException());
+    Settings settings = new Settings(new PropertyDefinitions(DataCleanerProperties.all()));
+    settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, true);
+    PurgeProfiler profiler = mock(PurgeProfiler.class);
+
+    DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, resourceDao, settings, mock(DefaultPeriodCleaner.class), profiler);
+    task.purge(1L);
+
+    verify(profiler).dump(anyLong(), any(Logger.class));
+  }
+
+  @Test
+  public void recognize_view_and_subview() {
+    boolean viewCheck = sut.isNotViewNorSubview(Qualifiers.VIEW);
+    boolean subViewCheck = sut.isNotViewNorSubview(Qualifiers.SUBVIEW);
+
+    assertThat(viewCheck).isFalse();
+    assertThat(subViewCheck).isFalse();
+  }
+
+  @Test
+  public void call_dao_delete_when_deleting() throws Exception {
+    when(resourceDao.getResource(123L)).thenReturn(new ResourceDto().setId(123L).setUuid("A"));
+
+    sut.delete(123L);
+
+    verify(purgeDao, times(1)).deleteResourceTree(any(IdUuidPair.class));
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleanerTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DefaultPeriodCleanerTest.java
new file mode 100644 (file)
index 0000000..e5de501
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.dbcleaner.period;
+
+import org.apache.commons.lang.ObjectUtils;
+import org.hamcrest.BaseMatcher;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.config.Settings;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeSnapshotQuery;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultPeriodCleanerTest {
+
+  @Test
+  public void doClean() {
+    PurgeDao dao = mock(PurgeDao.class);
+    DbSession session = mock(DbSession.class);
+    when(dao.selectPurgeableSnapshots(123L, session)).thenReturn(Arrays.asList(
+      new PurgeableSnapshotDto().setSnapshotId(999L).setDate(new Date())));
+    Filter filter1 = newLazyFilter();
+    Filter filter2 = newLazyFilter();
+
+    DefaultPeriodCleaner cleaner = new DefaultPeriodCleaner(dao, mock(Settings.class), mock(MyBatis.class));
+    cleaner.doClean(123L, Arrays.asList(filter1, filter2), session);
+
+    verify(filter1).log();
+    verify(filter2).log();
+    verify(dao, times(2)).deleteSnapshots(argThat(newRootSnapshotQuery()), eq(session));
+    verify(dao, times(2)).deleteSnapshots(argThat(newSnapshotIdQuery()), eq(session));
+  }
+
+  private BaseMatcher<PurgeSnapshotQuery> newRootSnapshotQuery() {
+    return new ArgumentMatcher<PurgeSnapshotQuery>() {
+      @Override
+      public boolean matches(Object o) {
+        PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
+        return ObjectUtils.equals(query.getRootSnapshotId(), 999L);
+      }
+    };
+  }
+
+  private BaseMatcher<PurgeSnapshotQuery> newSnapshotIdQuery() {
+    return new ArgumentMatcher<PurgeSnapshotQuery>() {
+      @Override
+      public boolean matches(Object o) {
+        PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
+        return ObjectUtils.equals(query.getId(), 999L);
+      }
+    };
+  }
+
+  private Filter newLazyFilter() {
+    Filter filter1 = mock(Filter.class);
+    when(filter1.filter(anyListOf(PurgeableSnapshotDto.class))).thenAnswer(new Answer<Object>() {
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return invocation.getArguments()[0];
+      }
+    });
+    return filter1;
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilterTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/DeleteAllFilterTest.java
new file mode 100644 (file)
index 0000000..6882a38
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.dbcleaner.period;
+
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.server.computation.dbcleaner.DbCleanerTestUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DeleteAllFilterTest {
+
+  @Test
+  public void shouldDeleteAllSnapshotsPriorToDate() {
+    Filter filter = new DeleteAllFilter(DateUtils.parseDate("2011-12-25"));
+
+    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.asList(
+      DbCleanerTestUtils.createSnapshotWithDate(1L, "2010-01-01"),
+      DbCleanerTestUtils.createSnapshotWithDate(2L, "2010-12-25"),
+      DbCleanerTestUtils.createSnapshotWithDate(3L, "2012-01-01")
+      ));
+
+    assertThat(toDelete).onProperty("snapshotId").containsOnly(1L, 2L);
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/IntervalTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/IntervalTest.java
new file mode 100644 (file)
index 0000000..94a3edd
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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.dbcleaner.period;
+
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+import org.sonar.server.computation.dbcleaner.DbCleanerTestUtils;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class IntervalTest {
+  static int calendarField(Interval interval, int field) {
+    if (interval.count() == 0) {
+      return -1;
+    }
+
+    PurgeableSnapshotDto first = interval.get().iterator().next();
+    GregorianCalendar cal = new GregorianCalendar();
+    cal.setTime(first.getDate());
+    return cal.get(field);
+  }
+
+  @Test
+  public void shouldGroupByIntervals() {
+    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
+      DbCleanerTestUtils.createSnapshotWithDate(1L, "2011-04-03"),
+
+      DbCleanerTestUtils.createSnapshotWithDate(2L, "2011-05-01"),
+      DbCleanerTestUtils.createSnapshotWithDate(3L, "2011-05-19"),
+
+      DbCleanerTestUtils.createSnapshotWithDate(4L, "2011-06-02"),
+      DbCleanerTestUtils.createSnapshotWithDate(5L, "2011-06-20"),
+
+      DbCleanerTestUtils.createSnapshotWithDate(6L, "2012-06-29") // out of scope
+      );
+
+    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2010-01-01"), DateUtils.parseDate("2011-12-31"), Calendar.MONTH);
+    assertThat(intervals.size(), is(3));
+
+    assertThat(intervals.get(0).count(), is(1));
+    assertThat(calendarField(intervals.get(0), Calendar.MONTH), is(Calendar.APRIL));
+
+    assertThat(intervals.get(1).count(), is(2));
+    assertThat(calendarField(intervals.get(1), Calendar.MONTH), is(Calendar.MAY));
+
+    assertThat(intervals.get(2).count(), is(2));
+    assertThat(calendarField(intervals.get(2), Calendar.MONTH), is(Calendar.JUNE));
+  }
+
+  @Test
+  public void shouldNotJoinMonthsOfDifferentYears() {
+    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
+      DbCleanerTestUtils.createSnapshotWithDate(1L, "2010-04-03"),
+      DbCleanerTestUtils.createSnapshotWithDate(2L, "2011-04-13")
+      );
+
+    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2010-01-01"), DateUtils.parseDate("2011-12-31"), Calendar.MONTH);
+    assertThat(intervals.size(), is(2));
+
+    assertThat(intervals.get(0).count(), is(1));
+    assertThat(calendarField(intervals.get(0), Calendar.MONTH), is(Calendar.APRIL));
+    assertThat(calendarField(intervals.get(0), Calendar.YEAR), is(2010));
+
+    assertThat(intervals.get(1).count(), is(1));
+    assertThat(calendarField(intervals.get(1), Calendar.MONTH), is(Calendar.APRIL));
+    assertThat(calendarField(intervals.get(1), Calendar.YEAR), is(2011));
+  }
+
+  @Test
+  public void shouldIgnoreTimeWhenGroupingByIntervals() {
+    List<PurgeableSnapshotDto> snapshots = Arrays.asList(
+      DbCleanerTestUtils.createSnapshotWithDateTime(1L, "2011-05-25T16:16:48+0100"),
+      DbCleanerTestUtils.createSnapshotWithDateTime(2L, "2012-01-26T16:16:48+0100"),
+      DbCleanerTestUtils.createSnapshotWithDateTime(3L, "2012-01-27T16:16:48+0100")
+      );
+
+    List<Interval> intervals = Interval.group(snapshots, DateUtils.parseDate("2011-05-25"), DateUtils.parseDate("2012-01-26"), Calendar.MONTH);
+    assertThat(intervals.size(), is(1));
+    assertThat(intervals.get(0).count(), is(1));
+    assertThat(intervals.get(0).get().get(0).getSnapshotId(), is(2L));
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilterTest.java b/sonar-core/src/test/java/org/sonar/server/computation/dbcleaner/period/KeepOneFilterTest.java
new file mode 100644 (file)
index 0000000..58ffe5a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.dbcleaner.period;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.purge.PurgeableSnapshotDto;
+import org.sonar.server.computation.dbcleaner.DbCleanerTestUtils;
+
+import javax.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class KeepOneFilterTest {
+
+  private static List<Long> snapshotIds(List<PurgeableSnapshotDto> snapshotDtos) {
+    return newArrayList(Iterables.transform(snapshotDtos, new Function<PurgeableSnapshotDto, Long>() {
+      @Override
+      public Long apply(@Nullable PurgeableSnapshotDto input) {
+        return input != null ? input.getSnapshotId() : null;
+      }
+    }));
+  }
+
+  @Test
+  public void shouldOnlyOneSnapshotPerInterval() {
+    Filter filter = new KeepOneFilter(DateUtils.parseDate("2011-03-25"), DateUtils.parseDate("2011-08-25"), Calendar.MONTH, "month");
+
+    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.<PurgeableSnapshotDto>asList(
+      DbCleanerTestUtils.createSnapshotWithDate(1L, "2010-01-01"), // out of scope -> keep
+      DbCleanerTestUtils.createSnapshotWithDate(2L, "2011-05-01"), // may -> keep
+      DbCleanerTestUtils.createSnapshotWithDate(3L, "2011-05-02"), // may -> to be deleted
+      DbCleanerTestUtils.createSnapshotWithDate(4L, "2011-05-19"), // may -> to be deleted
+      DbCleanerTestUtils.createSnapshotWithDate(5L, "2011-06-01"), // june -> keep
+      DbCleanerTestUtils.createSnapshotWithDate(6L, "2012-01-01") // out of scope -> keep
+      ));
+
+    assertThat(toDelete).hasSize(2);
+
+    List<Long> snapshotIds = snapshotIds(toDelete);
+    assertThat(snapshotIds).contains(3L);
+    assertThat(snapshotIds.contains(4L));
+  }
+
+  @Test
+  public void shouldKeepNonDeletableSnapshots() {
+    Filter filter = new KeepOneFilter(DateUtils.parseDate("2011-03-25"), DateUtils.parseDate("2011-08-25"), Calendar.MONTH, "month");
+
+    List<PurgeableSnapshotDto> toDelete = filter.filter(Arrays.<PurgeableSnapshotDto>asList(
+      DbCleanerTestUtils.createSnapshotWithDate(1L, "2011-05-01"), // to be deleted
+      DbCleanerTestUtils.createSnapshotWithDate(2L, "2011-05-02").setLast(true),
+      DbCleanerTestUtils.createSnapshotWithDate(3L, "2011-05-19").setHasEvents(true).setLast(false),
+      DbCleanerTestUtils.createSnapshotWithDate(4L, "2011-05-23") // to be deleted
+      ));
+
+    assertThat(toDelete).hasSize(2);
+
+    List<Long> snapshotIds = snapshotIds(toDelete);
+    assertThat(snapshotIds).contains(1L);
+    assertThat(snapshotIds.contains(4L));
+  }
+
+  @Test
+  public void test_isDeletable() {
+    assertThat(KeepOneFilter.isDeletable(DbCleanerTestUtils.createSnapshotWithDate(1L, "2011-05-01"))).isTrue();
+    assertThat(KeepOneFilter.isDeletable(DbCleanerTestUtils.createSnapshotWithDate(1L, "2011-05-01").setLast(true))).isFalse();
+    assertThat(KeepOneFilter.isDeletable(DbCleanerTestUtils.createSnapshotWithDate(1L, "2011-05-01").setHasEvents(true))).isFalse();
+  }
+
+}