diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2014-10-23 17:15:00 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2014-10-27 09:08:39 +0100 |
commit | 4c64f4f00be61229d4c4c8be8f8bec9b25df2bac (patch) | |
tree | b5844e988c063e80cb3cc6cede99d4f68a61fb7f /sonar-core/src | |
parent | 9c467f71a35ebb691acbb77bb1de3d825c4b109d (diff) | |
download | sonarqube-4c64f4f00be61229d4c4c8be8f8bec9b25df2bac.tar.gz sonarqube-4c64f4f00be61229d4c4c8be8f8bec9b25df2bac.zip |
SONAR-5628 - Compute Engine - Move DbCleaner
Diffstat (limited to 'sonar-core/src')
20 files changed, 1188 insertions, 11 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/computation/db/AnalysisReportDto.java b/sonar-core/src/main/java/org/sonar/core/computation/db/AnalysisReportDto.java index 82c4af9526d..1491a1ae19c 100644 --- a/sonar-core/src/main/java/org/sonar/core/computation/db/AnalysisReportDto.java +++ b/sonar-core/src/main/java/org/sonar/core/computation/db/AnalysisReportDto.java @@ -21,12 +21,16 @@ package org.sonar.core.computation.db; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; +import com.google.common.base.Strings; +import org.sonar.core.component.AuthorizedComponentDto; +import org.sonar.core.component.ComponentDto; import org.sonar.core.persistence.Dto; import javax.annotation.Nullable; import java.util.Date; +import static com.google.common.base.Preconditions.checkNotNull; import static org.sonar.core.computation.db.AnalysisReportDto.Status.FAILED; import static org.sonar.core.computation.db.AnalysisReportDto.Status.SUCCESS; @@ -34,12 +38,12 @@ public class AnalysisReportDto extends Dto<String> { private Long id; private String projectKey; - private String projectName; private Status status; private String data; private Long snapshotId; private Date startedAt; private Date finishedAt; + private ComponentDto project; public AnalysisReportDto() { super(); @@ -102,7 +106,6 @@ public class AnalysisReportDto extends Dto<String> { return Objects.toStringHelper(this) .add("id", getId()) .add("projectKey", getProjectKey()) - .add("projectName", getProjectName()) .add("status", getStatus()) .add("createdAt", getCreatedAt()) .add("startedAt", getStartedAt()) @@ -111,12 +114,11 @@ public class AnalysisReportDto extends Dto<String> { } public String getProjectName() { - return projectName; - } + if (project == null) { + return getProjectKey(); + } - public AnalysisReportDto setProjectName(String projectName) { - this.projectName = projectName; - return this; + return Strings.nullToEmpty(project.name()); } public Long getSnapshotId() { @@ -158,6 +160,15 @@ public class AnalysisReportDto extends Dto<String> { return this; } + public AuthorizedComponentDto getProject() { + return checkNotNull(project); + } + + public AnalysisReportDto setProject(ComponentDto project) { + this.project = project; + return this; + } + public enum Status { PENDING, WORKING, SUCCESS, FAILED; 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 new file mode 100644 index 00000000000..a577f632608 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerConstants.java @@ -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.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/DbCleanerProperties.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerProperties.java new file mode 100644 index 00000000000..744a8873657 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DbCleanerProperties.java @@ -0,0 +1,105 @@ +/* + * 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 DbCleanerProperties { + + 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/DefaultPurgeTask.java b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTask.java new file mode 100644 index 00000000000..4cd7799c297 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTask.java @@ -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.core.computation.dbcleaner; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.resources.Scopes; +import org.sonar.api.utils.TimeUtils; +import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner; +import org.sonar.core.purge.PurgeConfiguration; +import org.sonar.core.purge.PurgeDao; +import org.sonar.core.purge.PurgeProfiler; + +/** + * @since 2.14 + */ +public class DefaultPurgeTask { + private static final Logger LOG = LoggerFactory.getLogger(DefaultPurgeTask.class); + + private PurgeDao purgeDao; + private Settings settings; + private DefaultPeriodCleaner periodCleaner; + private final PurgeProfiler profiler; + + public DefaultPurgeTask(PurgeDao purgeDao, Settings settings, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler) { + this.purgeDao = purgeDao; + this.settings = settings; + this.periodCleaner = periodCleaner; + this.profiler = profiler; + } + + public DefaultPurgeTask delete(long resourceId) { + purgeDao.deleteResourceTree(resourceId); + return this; + } + + public DefaultPurgeTask purge(long resourceId) { + long start = System.currentTimeMillis(); + 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(newConf(resourceId)); + } catch (Exception e) { + // purge errors must no fail the batch + LOG.error("Fail to purge data [id=" + resourceId + "]", e); + } + } + + private PurgeConfiguration newConf(long resourceId) { + String[] scopes = new String[] {Scopes.FILE}; + if (settings.getBoolean(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY)) { + scopes = new String[] {Scopes.DIRECTORY, Scopes.FILE}; + } + return new PurgeConfiguration(resourceId, scopes, settings.getInt(DbCleanerConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES)); + } +} 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 new file mode 100644 index 00000000000..76b1238dc07 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleaner.java @@ -0,0 +1,75 @@ +/* + * 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.config.Settings; +import org.sonar.api.resources.Project; +import org.sonar.api.task.TaskExtension; +import org.sonar.api.utils.DateUtils; +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 { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultPeriodCleaner.class); + private PurgeDao purgeDao; + private Settings settings; + + public DefaultPeriodCleaner(PurgeDao purgeDao, Settings settings) { + this.purgeDao = purgeDao; + this.settings = settings; + } + + public void purge(Project project, int projectSnapshotId) { + clean(project.getId()); + } + + public void clean(long projectId) { + doClean(projectId, new Filters(settings).all()); + } + + @VisibleForTesting + void doClean(long projectId, List<Filter> filters) { + List<PurgeableSnapshotDto> history = selectProjectSnapshots(projectId); + for (Filter filter : filters) { + filter.log(); + delete(filter.filter(history)); + } + } + + private void delete(List<PurgeableSnapshotDto> snapshots) { + for (PurgeableSnapshotDto snapshot : snapshots) { + LOG.info("<- Delete snapshot: " + DateUtils.formatDateTime(snapshot.getDate()) + " [" + snapshot.getSnapshotId() + "]"); + purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setRootSnapshotId(snapshot.getSnapshotId())); + purgeDao.deleteSnapshots(PurgeSnapshotQuery.create().setId(snapshot.getSnapshotId())); + } + } + + private List<PurgeableSnapshotDto> selectProjectSnapshots(long resourceId) { + return purgeDao.selectPurgeableSnapshots(resourceId); + } +} 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 new file mode 100644 index 00000000000..25dcb409ea1 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilter.java @@ -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.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 new file mode 100644 index 00000000000..ef4a3753242 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filter.java @@ -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.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 new file mode 100644 index 00000000000..8e59596212c --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Filters.java @@ -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.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 new file mode 100644 index 00000000000..5676a858495 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/Interval.java @@ -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.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 new file mode 100644 index 00000000000..419add8383f --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilter.java @@ -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.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 new file mode 100644 index 00000000000..283ef7fa912 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/computation/dbcleaner/period/package-info.java @@ -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.core.computation.dbcleaner.period; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java index d98fddab931..b678394d38a 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java +++ b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java @@ -24,6 +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.DbCleanerProperties; import java.util.List; @@ -39,6 +40,7 @@ public class CorePropertyDefinitions { defs.addAll(ExclusionProperties.all()); defs.addAll(SecurityProperties.all()); defs.addAll(DebtProperties.all()); + defs.addAll(DbCleanerProperties.all()); defs.addAll(ImmutableList.of( // BATCH @@ -101,7 +103,7 @@ public class CorePropertyDefinitions { .category(CoreProperties.CATEGORY_GENERAL) .subCategory(CoreProperties.SUBCATEGORY_DIFFERENTIAL_VIEWS) .build() - )); + )); return defs; } } diff --git a/sonar-core/src/main/resources/org/sonar/core/computation/db/AnalysisReportMapper.xml b/sonar-core/src/main/resources/org/sonar/core/computation/db/AnalysisReportMapper.xml index e2166b7b36f..16613e4a946 100644 --- a/sonar-core/src/main/resources/org/sonar/core/computation/db/AnalysisReportMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/computation/db/AnalysisReportMapper.xml @@ -6,7 +6,6 @@ <!-- the data report is not brought back by default as it could be too big in memory --> ar.id, ar.project_key as projectKey, - ar.project_name as projectName, ar.report_status as status, ar.snapshot_id as snapshotId, ar.created_at as createdAt, @@ -17,9 +16,9 @@ <insert id="insert" parameterType="AnalysisReport" useGeneratedKeys="true"> insert into analysis_reports - (project_key, project_name, snapshot_id, report_status, report_data, created_at, updated_at, started_at, + (project_key, snapshot_id, report_status, report_data, created_at, updated_at, started_at, finished_at) - values (#{projectKey}, #{projectName}, #{snapshotId}, #{status}, #{data}, #{createdAt}, #{updatedAt}, #{startedAt}, + values (#{projectKey}, #{snapshotId}, #{status}, #{data}, #{createdAt}, #{updatedAt}, #{startedAt}, #{finishedAt}) </insert> diff --git a/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerPropertiesTest.java b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerPropertiesTest.java new file mode 100644 index 00000000000..4c4311aac3b --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerPropertiesTest.java @@ -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.core.computation.dbcleaner; + +import org.junit.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class DbCleanerPropertiesTest { + + @Test + public void shouldGetExtensions() { + assertThat(new DbCleanerProperties().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 new file mode 100644 index 00000000000..392e58c0f0b --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DbCleanerTestUtils.java @@ -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.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 new file mode 100644 index 00000000000..72359ee3dee --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/DefaultPurgeTaskTest.java @@ -0,0 +1,106 @@ +/* + * 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.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.Scopes; +import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner; +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.Matchers.argThat; +import static org.mockito.Mockito.*; + +public class DefaultPurgeTaskTest { + + @Test + public void shouldNotDeleteHistoricalDataOfDirectories() { + PurgeDao purgeDao = mock(PurgeDao.class); + Settings settings = new Settings(new PropertyDefinitions(DbCleanerProperties.all())); + settings.setProperty(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY, "false"); + DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, 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(DbCleanerProperties.all())); + DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, 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, 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(DbCleanerProperties.all())); + settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, true); + PurgeProfiler profiler = mock(PurgeProfiler.class); + + DefaultPurgeTask task = new DefaultPurgeTask(purgeDao, settings, mock(DefaultPeriodCleaner.class), profiler); + task.purge(1L); + + verify(profiler).dump(anyLong(), any(Logger.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 new file mode 100644 index 00000000000..0a5872041d2 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DefaultPeriodCleanerTest.java @@ -0,0 +1,90 @@ +/* + * 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.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.Mockito.*; + +public class DefaultPeriodCleanerTest { + + + @Test + public void doClean() { + PurgeDao dao = mock(PurgeDao.class); + when(dao.selectPurgeableSnapshots(123L)).thenReturn(Arrays.asList( + new PurgeableSnapshotDto().setSnapshotId(999L).setDate(new Date()))); + Filter filter1 = newLazyFilter(); + Filter filter2 = newLazyFilter(); + + DefaultPeriodCleaner cleaner = new DefaultPeriodCleaner(dao, mock(Settings.class)); + cleaner.doClean(123L, Arrays.asList(filter1, filter2)); + + verify(filter1).log(); + verify(filter2).log(); + verify(dao, times(2)).deleteSnapshots(argThat(newRootSnapshotQuery())); + verify(dao, times(2)).deleteSnapshots(argThat(newSnapshotIdQuery())); + } + + 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 new file mode 100644 index 00000000000..2a84512355e --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/DeleteAllFilterTest.java @@ -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.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 new file mode 100644 index 00000000000..a9c5aecc698 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/IntervalTest.java @@ -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.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 new file mode 100644 index 00000000000..8e855f987df --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/computation/dbcleaner/period/KeepOneFilterTest.java @@ -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.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(); + } + +} |