package de.is24.infrastructure.gridfs.http.repos; import de.is24.infrastructure.gridfs.http.category.LocalExecutionOnly; import de.is24.infrastructure.gridfs.http.domain.RepoEntry; import de.is24.infrastructure.gridfs.http.domain.RepoType; import de.is24.infrastructure.gridfs.http.domain.YumEntry; import de.is24.infrastructure.gridfs.http.domain.yum.YumPackage; import de.is24.infrastructure.gridfs.http.domain.yum.YumPackageLocation; import de.is24.infrastructure.gridfs.http.domain.yum.YumPackageTime; import de.is24.infrastructure.gridfs.http.domain.yum.YumPackageVersion; import de.is24.infrastructure.gridfs.http.mongo.IntegrationTestContext; import de.is24.infrastructure.gridfs.http.storage.FileDescriptor; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; import java.util.List; import static de.is24.infrastructure.gridfs.http.mongo.IntegrationTestContext.mongoTemplate; import static de.is24.infrastructure.gridfs.http.utils.RepositoryUtils.simpleInputStream; import static de.is24.infrastructure.gridfs.http.utils.RepositoryUtils.uniqueRepoName; import static java.lang.System.currentTimeMillis; import static java.util.stream.Collectors.toList; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertTrue; @Category(LocalExecutionOnly.class) public class RepoCleanerIT { private static final String NAME1 = "test-artifactus"; private static final String NAME2 = "artifactus-test"; private static final String NOARCH = "noarch"; private static final String SRC = "src"; private static final Integer CURRENT = getCurrent(); private static final Integer FIVE_DAYS_AGO = getFiveDaysAgo(); private static final YumEntry[] YUM_ENTRIES_TO_KEEP = { entry(NAME1, "1.0", "1", NOARCH, CURRENT, CURRENT), entry(NAME1, "2.0", "1", NOARCH, CURRENT, CURRENT), entry(NAME1, "0.1", "1", SRC, CURRENT, CURRENT), entry(NAME1, "0.2", "1", SRC, CURRENT, CURRENT), entry(NAME2, "1.1.1", "1", NOARCH, CURRENT, CURRENT), entry(NAME2, "1.1", "2", NOARCH, CURRENT, CURRENT), entry(NAME2, "1.1", "1", NOARCH, CURRENT, CURRENT) }; private static final YumEntry[] YUM_ENTRIES_TO_CLEAN_UP = { entry(NAME2, "1.0", "1", NOARCH, CURRENT, FIVE_DAYS_AGO), entry(NAME2, "0.9", "1", NOARCH, CURRENT, FIVE_DAYS_AGO) }; private static Integer getCurrent() { long current = new DateTime().withZoneRetainFields(DateTimeZone.UTC).getMillis() / 1000L ; return (int) current; } private static Integer getFiveDaysAgo() { long fiveDaysAgo = new DateTime().minusDays(5).withZoneRetainFields(DateTimeZone.UTC).getMillis() / 1000L; return (int) fiveDaysAgo; } @ClassRule public static IntegrationTestContext context = new IntegrationTestContext(); private String reponame; private RepoCleaner service; @Before public void setUp() throws Exception { reponame = uniqueRepoName(); service = new RepoCleaner(mongoTemplate(context.getMongo()), context.yumEntriesRepository(), context.fileStorageService(), context.repoService()); } @Test public void cleanupRepoByMaxDaysRpms() throws Exception { givenRepoEntryWithMaxKeep(0); givenRepoEntryWithMaxDays(3); givenRepoWithFilesToClean(); long startTime = currentTimeMillis(); assertThat(service.cleanup(reponame), is(true)); assertThatItemsHasBeenCleanedUp(); assertThatRepoEntryIsMarkedAsModified(startTime); assertThatGridFsFileIsMarkedAsDeleted(); } @Test public void cleanupRepoByMaxKeepRpms() throws Exception { givenRepoEntryWithMaxDays(0); givenRepoEntryWithMaxKeep(3); givenRepoWithFilesToClean(); long startTime = currentTimeMillis(); assertThat(service.cleanup(reponame), is(true)); assertThatItemsHasBeenCleanedUp(); assertThatRepoEntryIsMarkedAsModified(startTime); assertThatGridFsFileIsMarkedAsDeleted(); } @Test public void doNothingIfMaxKeepRpmsAndMaxDaysRpmsIsZero() throws Exception { givenRepoEntryWithMaxKeep(0); givenRepoEntryWithMaxDays(0); givenRepoWithFilesToClean(); assertThat(service.cleanup(reponame), is(false)); assertThatNoItemsHasBeenCleanedUp(); } private void assertThatRepoEntryIsMarkedAsModified(long startTime) { RepoEntry repoEntry = context.repoEntriesRepository().findFirstByName(reponame); assertThat(repoEntry.getLastModified().getTime(), greaterThan(startTime)); } private void assertThatGridFsFileIsMarkedAsDeleted() { for (YumEntry entryToDelete : YUM_ENTRIES_TO_CLEAN_UP) { assertTrue(context.fileStorageService().findBy(new FileDescriptor(entryToDelete)).isMarkedAsDeleted()); } } private void assertThatItemsHasBeenCleanedUp() { assertEntriesExist(YUM_ENTRIES_TO_KEEP); for (YumEntry entry : YUM_ENTRIES_TO_CLEAN_UP) { assertEntryDoesNotExist(entry); } } private void assertThatNoItemsHasBeenCleanedUp() { assertEntriesExist(YUM_ENTRIES_TO_KEEP); assertEntriesExist(YUM_ENTRIES_TO_CLEAN_UP); } private void assertEntriesExist(YumEntry[] entries) { for (YumEntry entry : entries) { assertEntryExists(entry); } } private void assertEntryDoesNotExist(YumEntry entry) { assertThat(findVersionsFor(entry.getYumPackage().getName()), not(hasItem(entry.getYumPackage().getVersion()))); } private void assertEntryExists(YumEntry entry) { assertThat(findVersionsFor(entry.getYumPackage().getName()), hasItem(entry.getYumPackage().getVersion())); } private List<YumPackageVersion> findVersionsFor(String artifactName) { List<YumEntry> entries = context.yumEntriesRepository().findByRepoAndYumPackageName(reponame, artifactName); return entries.stream().map(YumEntry::getYumPackage).map(YumPackage::getVersion).collect(toList()); } private void givenRepoEntryWithMaxKeep(int maxKeepRpms) { RepoEntry repoEntry = context.repoService().ensureEntry(reponame, (RepoType) null); repoEntry.setMaxKeepRpms(maxKeepRpms); context.repoEntriesRepository().save(repoEntry); } private void givenRepoEntryWithMaxDays(int maxDaysRpms) { RepoEntry repoEntry = context.repoService().ensureEntry(reponame, (RepoType) null); repoEntry.setMaxDaysRpms(maxDaysRpms); context.repoEntriesRepository().save(repoEntry); } private void givenRepoWithFilesToClean() { for (YumEntry entry : YUM_ENTRIES_TO_KEEP) { entry.setRepo(reponame); context.yumEntriesRepository().save(entry); } for (YumEntry entry : YUM_ENTRIES_TO_CLEAN_UP) { entry.setRepo(reponame); context.yumEntriesRepository().save(entry); context.gridFsTemplate().store(simpleInputStream(), entry.getFullRpmFilename()).save(); } } private static YumEntry entry(String name, String version, String release, String arch, Integer file, Integer build) { YumPackage yumPackage = new YumPackage(); yumPackage.setName(name); yumPackage.setArch(arch); yumPackage.setVersion(packageVersion(version, release)); yumPackage.setTime(packageTime(file, build)); YumPackageLocation location = new YumPackageLocation(); location.setHref(arch + "/" + name + "-" + version + "-" + release + "." + arch + ".rpm"); yumPackage.setLocation(location); return new YumEntry(null, null, yumPackage); } private static YumPackageTime packageTime(Integer file, Integer build) { YumPackageTime packageTime = new YumPackageTime(); packageTime.setFile(file); packageTime.setBuild(build); return packageTime; } private static YumPackageVersion packageVersion(String version, String release) { YumPackageVersion packageVersion = new YumPackageVersion(); packageVersion.setEpoch(0); packageVersion.setVer(version); packageVersion.setRel(release); return packageVersion; } }