S16 - some transactional hardening
All checks were successful
Build, test and publish / verify (push) Successful in 7m32s
All checks were successful
Build, test and publish / verify (push) Successful in 7m32s
This commit is contained in:
@@ -136,6 +136,71 @@ class SchedulingRunsTest {
|
||||
schools.endScheduling(schools.beginScheduling(school, show.getId()).showId());
|
||||
}
|
||||
|
||||
public @Test void databaseRecoveryPersistsPendingFailureWithoutRestart() throws Exception {
|
||||
final Show show = show();
|
||||
final var entered = new CountDownLatch(1);
|
||||
final var release = new CountDownLatch(1);
|
||||
final var persistence = new OutagePersistence();
|
||||
final var runs = new SchedulingRuns(schools, blocking(entered, release));
|
||||
final java.lang.reflect.Field field = SchedulingRuns.class.getDeclaredField("persistence");
|
||||
field.setAccessible(true);
|
||||
field.set(runs, persistence);
|
||||
try {
|
||||
final SchedulingRun started = runs.start(school, show.getId());
|
||||
assertTrue(entered.await(10, TimeUnit.SECONDS));
|
||||
persistence.available.set(false);
|
||||
release.countDown();
|
||||
assertTrue(persistence.unavailable.await(10, TimeUnit.SECONDS));
|
||||
assertEquals(started, persistence.stored.get());
|
||||
assertEquals(started, runs.status(school, show.getId()));
|
||||
assertThrows(ManagementException.class, () -> runs.start(school, show.getId()));
|
||||
persistence.available.set(true);
|
||||
final SchedulingRun completed = await(runs, show);
|
||||
assertEquals(SchedulingState.SOLVER_FAILED, completed.state());
|
||||
assertEquals(started.runId(), completed.runId());
|
||||
assertEquals(completed, persistence.stored.get());
|
||||
schools.endScheduling(schools.beginScheduling(school, show.getId()).showId());
|
||||
} finally {
|
||||
persistence.available.set(true);
|
||||
release.countDown();
|
||||
runs.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class OutagePersistence extends SchedulingPersistence {
|
||||
private final CountDownLatch unavailable = new CountDownLatch(2);
|
||||
private final java.util.concurrent.atomic.AtomicBoolean available =
|
||||
new java.util.concurrent.atomic.AtomicBoolean(true);
|
||||
private final AtomicReference<SchedulingRun> stored = new AtomicReference<>();
|
||||
|
||||
private OutagePersistence() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
public @Override <T> T work(final java.util.concurrent.Callable<T> action) {
|
||||
if (!available.get()) {
|
||||
unavailable.countDown();
|
||||
throw new nl.agilecc.agiledancers.repository.StorageException(new IllegalStateException("offline"));
|
||||
}
|
||||
try {
|
||||
return action.call();
|
||||
} catch (final RuntimeException failure) {
|
||||
throw failure;
|
||||
} catch (final Exception failure) {
|
||||
throw new IllegalStateException(failure);
|
||||
}
|
||||
}
|
||||
|
||||
public @Override void accepted(final SchedulingRun run, final Runnable launch, final Runnable rollback) {
|
||||
save(run, launch);
|
||||
}
|
||||
|
||||
public @Override void save(final SchedulingRun run, final Runnable publication) {
|
||||
stored.set(run);
|
||||
publication.run();
|
||||
}
|
||||
}
|
||||
|
||||
private Show show() {
|
||||
final long group = schools.createGroup(
|
||||
school, new GroupDetails("Group", DanceGroupType.REGULAR, 0, 99, Set.of()))
|
||||
|
||||
Reference in New Issue
Block a user