MigraMongo { public MigraMongoStatus migrate() { final boolean lockAcquired = lockService.acquireLock(); if ( !lockAcquired) { return MigraMongoStatus.lockNotAcquired(); } try { final List<MongoMigrationScript> migrationScriptsToApply = findMigrationScriptsToApply(); return migrate(migrationScriptsToApply); } catch (MongoMigrationException e) { logger.error("Migration Exception caught while migrating", e); return e.getStatus(); } catch (Exception e) { logger.error("Unknown Exception caught while migrating", e); return MigraMongoStatus.error(e.getMessage()); } finally { lockService.releaseLock(); } } MigraMongo(
            MongoDatabase database,
            MigrationHistoryService migrationEntryService,
            LockService lockService,
            ScriptLookupService scriptLookupService); void setAsyncInitializerFunction(Runnable function); MigraMongoStatus dryRun(); MigraMongoStatus migrate(); MigraMongoStatus migrateAsync(); MigraMongoStatus status(String fromVersion); MigraMongoStatus repair(String fromVersion, String toVersion); MigraMongoStatus rerun(String fromVersion, String toVersion); List<MigrationEntry> getMigrationEntries(); void destroyLocks();  }
@Test public void shouldNotMigrateAnythingIfNoInitialScriptIsProvided() { final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(0)); }
@Test public void shouldMigrateInitialScriptWhenNoMigrationExists() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(1)); verify(mockInitialScript).migrate(mongoDatabase); }
@Test public void shouldMigrateInitialScriptAndOneNormalOneWhenNoMigrationExists() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final List<MongoMigrationScript> migrationScripts = Arrays.asList(mockMongoScript("1", "2")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(2)); verify(mockInitialScript).migrate(mongoDatabase); for (MongoMigrationScript ms : migrationScripts) { verify(ms).migrate(mongoDatabase); } }
@Test public void shouldMigrateInitialScriptAndThreeNormalOnesWhenNoMigrationExists() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final List<MongoMigrationScript> migrationScripts = Arrays .asList(mockMongoScript("1", "2"), mockMongoScript("2", "8"), mockMongoScript("8", "9")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(migrationScripts.size() + 1)); verify(mockInitialScript).migrate(mongoDatabase); for (MongoMigrationScript ms : migrationScripts) { verify(ms).migrate(mongoDatabase); } }
@Test public void shouldMigrateInitialScriptAndThreeNormalOnesWhenNoMigrationExistsAndSomeScriptsDoNotCorrespondWithExistingVersions() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final List<MongoMigrationScript> migrationScripts = Arrays .asList( mockMongoScript("1", "2"), mockMongoScript("2", "8"), mockMongoScript("A", "B"), mockMongoScript("B", "C"), mockMongoScript("8", "9")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(4)); verify(mockInitialScript).migrate(mongoDatabase); migrationScripts.stream().filter(ms -> ms.getMigrationInfo().getFromVersion().matches("[0-9]*")).forEach(ms -> { try { verify(ms).migrate(mongoDatabase); } catch (Exception e) { throw new RuntimeException("Exception while migrating", e); } }); }
@Test public void shouldNotMigrateIfFirstMigrationAlreadyExistsOnDB() throws Exception { mockLastEntry("1", "1"); final MigraMongoStatus status = migraMongo.migrate(); verify(lookupService, times(0)).findInitialScript(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(0)); }
@Test public void shouldMigrateIfInitialIsAlreadyOnDB() throws Exception { mockLastEntry("1", "1"); final List<MongoMigrationScript> migrationScripts = Arrays .asList(mockMongoScript("1", "2"), mockMongoScript("2", "8"), mockMongoScript("8", "9")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(migrationScripts.size())); for (MongoMigrationScript ms : migrationScripts) { verify(ms).migrate(mongoDatabase); } }
@Test public void shouldStopMigrationIfAnyScriptFails() throws Exception { mockLastEntry("1", "1"); final List<MongoMigrationScript> migrationScripts = Arrays .asList( mockMongoScript("1", "2"), mockMongoScript("2", "8", new RuntimeException("script failing")), mockMongoScript("8", "9")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.ERROR)); assertThat(status.migrationsApplied, hasSize(2)); assertThat( status.message, allOf( containsString("fromVersion '2'"), containsString("toVersion '8'"), containsString("script failing"))); verify(migrationScripts.get(0)).migrate(mongoDatabase); verify(migrationScripts.get(1)).migrate(mongoDatabase); verify(migrationScripts.get(2), never()).migrate(mongoDatabase); }
@Test public void shouldNotStartMigrationIfLastScriptIsInError() throws Exception { final MigrationRun mockLastEntry = mockLastEntry("1", "1"); mockLastEntry.setStatus(MigrationStatus.ERROR); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.ERROR)); assertThat(status.migrationsApplied, hasSize(0)); assertThat( status.message, allOf( containsString("Last Migration is in status ERROR"), containsString("fromVersion=1"), containsString("toVersion=1"))); verify(lookupService, times(0)).findMongoScripts(); }
@Test public void shouldMigrateIfACoupleOfMigrationsAreAlreadyOnDB() throws Exception { mockLastEntry("4", "5"); final List<MongoMigrationScript> migrationScripts = Arrays .asList( mockMongoScript("1", "2"), mockMongoScript("2", "8"), mockMongoScript("5", "7"), mockMongoScript("7", "8")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(2)); migrationScripts .stream() .filter(ms -> Integer.valueOf(ms.getMigrationInfo().getFromVersion()) >= 5) .forEach(ms -> { try { verify(ms).migrate(mongoDatabase); } catch (Exception e) { throw new RuntimeException("Exception while migrating", e); } }); }
@Test public void shouldNotMigrateIfNoNewMigrationScriptsAvailable() throws Exception { mockLastEntry("4", "5"); when(lookupService.findMongoScripts()).thenReturn(Collections.emptyList()); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(0)); }
@Test public void shouldFailIfThereAreMoreThanOneMigrationScriptsToApply() throws Exception { mockLastEntry("1", "1"); final List<MongoMigrationScript> migrationScripts = Arrays .asList(mockMongoScript("1", "2"), mockMongoScript("2", "8"), mockMongoScript("2", "9")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.ERROR)); assertThat(status.message, Matchers.startsWith("There is more than one script with fromVersion 2")); }
@Test public void shouldNotMigrateIfItCannotAcquireLock() { when(lockService.acquireLock()).thenReturn(false); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.LOCK_NOT_ACQUIRED)); }
@Test public void shouldReleaseLockWhenMigratingSync() { migraMongo.migrate(); verify(lockService).releaseLock(); }
@Test public void shouldNotExecuteMigrationScriptMarkedWithIncludedInInitialTrue() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final List<MongoMigrationScript> migrationScripts = Arrays .asList(mockMongoScript("1", "2", true), mockMongoScript("2", "3", false), mockMongoScript("3", "4", true)); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(migrationScripts.size() + 1)); verify(mockInitialScript).migrate(mongoDatabase); final Map<Boolean, List<MongoMigrationScript>> scriptsGrouppedByIncludedInInitial = migrationScripts .stream() .collect(Collectors.groupingBy(ms -> ms.includedInInitialMigrationScript())); for (MongoMigrationScript scriptIncludedInInitial : scriptsGrouppedByIncludedInInitial.get(true)) { verify(scriptIncludedInInitial, times(0)).migrate(mongoDatabase); } for (MongoMigrationScript scriptNotIncludedInInitial : scriptsGrouppedByIncludedInInitial.get(false)) { verify(scriptNotIncludedInInitial).migrate(mongoDatabase); } }
@Test public void shouldExecuteMigrationScriptMarkedWithIncludedInInitialTrueIfItsNotAnInitialMigration() throws Exception { mockLastMigrationApplied("0", "1"); final List<MongoMigrationScript> migrationScripts = Arrays .asList(mockMongoScript("1", "2"), mockMongoScript("2", "3"), mockMongoScript("3", "4")); when(lookupService.findMongoScripts()).thenReturn(migrationScripts); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(migrationScripts.size())); for (MongoMigrationScript migrationScript : migrationScripts) { verify(migrationScript).migrate(mongoDatabase); } }
@Test public void shouldMigrateInitialScriptEvenIfIncludedInInitialIsFalse() throws Exception { final InitialMongoMigrationScript mockInitialScript = mockInitialScript("1"); when(lookupService.findInitialScript()).thenReturn(mockInitialScript); final MigraMongoStatus status = migraMongo.migrate(); assertThat(status.status, is(MigrationStatus.OK)); assertThat(status.migrationsApplied, hasSize(1)); verify(mockInitialScript).migrate(mongoDatabase); }