### Question:
CheckPointScheduler extends LifecycleAdapter { @Override public void start() { handle = scheduler.schedule( Group.CHECKPOINT, job, recurringPeriodMillis, MILLISECONDS ); } CheckPointScheduler( CheckPointer checkPointer, IOLimiter ioLimiter, JobScheduler scheduler, long recurringPeriodMillis,
            DatabaseHealth health ); @Override void start(); @Override void stop();  }### Answer:
@Test public void shouldScheduleTheCheckPointerJobOnStart() { CheckPointScheduler scheduler = new CheckPointScheduler( checkPointer, ioLimiter, jobScheduler, 20L, health ); assertNull( jobScheduler.getJob() ); scheduler.start(); assertNotNull( jobScheduler.getJob() ); verify( jobScheduler, times( 1 ) ).schedule( eq( Group.CHECKPOINT ), any( Runnable.class ), eq( 20L ), eq( TimeUnit.MILLISECONDS ) ); }
@Test public void shouldRescheduleTheJobAfterARun() throws Throwable { CheckPointScheduler scheduler = new CheckPointScheduler( checkPointer, ioLimiter, jobScheduler, 20L, health ); assertNull( jobScheduler.getJob() ); scheduler.start(); Runnable scheduledJob = jobScheduler.getJob(); assertNotNull( scheduledJob ); jobScheduler.runJob(); verify( jobScheduler, times( 2 ) ).schedule( eq( Group.CHECKPOINT ), any( Runnable.class ), eq( 20L ), eq( TimeUnit.MILLISECONDS ) ); verify( checkPointer, times( 1 ) ).checkPointIfNeeded( any( TriggerInfo.class ) ); assertEquals( scheduledJob, jobScheduler.getJob() ); }
@Test public void shouldContinueThroughSporadicFailures() { ControlledCheckPointer checkPointer = new ControlledCheckPointer(); CheckPointScheduler scheduler = new CheckPointScheduler( checkPointer, ioLimiter, jobScheduler, 1, health ); scheduler.start(); for ( int i = 0; i < CheckPointScheduler.MAX_CONSECUTIVE_FAILURES_TOLERANCE * 2; i++ ) { checkPointer.fail = true; jobScheduler.runJob(); verifyZeroInteractions( health ); checkPointer.fail = false; jobScheduler.runJob(); verifyZeroInteractions( health ); } }
@Test public void shouldCausePanicAfterSomeFailures() throws Throwable { RuntimeException[] failures = new RuntimeException[] { new RuntimeException( "First" ), new RuntimeException( "Second" ), new RuntimeException( "Third" ) }; when( checkPointer.checkPointIfNeeded( any( TriggerInfo.class ) ) ).thenThrow( failures ); CheckPointScheduler scheduler = new CheckPointScheduler( checkPointer, ioLimiter, jobScheduler, 1, health ); scheduler.start(); for ( int i = 0; i < CheckPointScheduler.MAX_CONSECUTIVE_FAILURES_TOLERANCE - 1; i++ ) { jobScheduler.runJob(); verifyZeroInteractions( health ); } try { jobScheduler.runJob(); fail( "Should have failed" ); } catch ( UnderlyingStorageException e ) { assertEquals( Iterators.asSet( failures ), Iterators.asSet( e.getSuppressed() ) ); verify( health ).panic( e ); } }