### Question:
DefaultBlockScheduler extends AbstractBlockScheduler { @Override @VisibleForTesting public BlockCreationTimeResult getNextTimestamp(final BlockHeader parentHeader) { final long msSinceEpoch = clock.millis(); final long now = TimeUnit.SECONDS.convert(msSinceEpoch, TimeUnit.MILLISECONDS); final long parentTimestamp = parentHeader.getTimestamp(); final long nextHeaderTimestamp = Long.max(parentTimestamp + minimumSecondsSinceParent, now); final long earliestBlockTransmissionTime = nextHeaderTimestamp - acceptableClockDriftSeconds; final long msUntilBlocKTransmission = (earliestBlockTransmissionTime * 1000) - msSinceEpoch; return new BlockCreationTimeResult(nextHeaderTimestamp, Math.max(0, msUntilBlocKTransmission)); } DefaultBlockScheduler(
      final long minimumSecondsSinceParent,
      final long acceptableClockDriftSeconds,
      final Clock clock); @Override @VisibleForTesting BlockCreationTimeResult getNextTimestamp(final BlockHeader parentHeader);  }### Answer:
@Test public void canMineBlockOnLimitOfClockDrift() { final Clock clock = mock(Clock.class); final DefaultBlockScheduler scheduler = new DefaultBlockScheduler(interBlockSeconds, acceptableClockDrift, clock); final long parentBlockSystemTimeCreation = parentTimeStamp - acceptableClockDrift + 1; when(clock.millis()).thenReturn(parentBlockSystemTimeCreation * 1000); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader parentBlock = headerBuilder.timestamp(parentTimeStamp).buildHeader(); final AbstractBlockScheduler.BlockCreationTimeResult result = scheduler.getNextTimestamp(parentBlock); assertThat(result.getTimestampForHeader()).isEqualTo(parentTimeStamp + interBlockSeconds); assertThat(result.getMillisecondsUntilValid()).isEqualTo(0); }
@Test public void childBlockWithinClockDriftReportsTimeToValidOfZero() { final Clock clock = mock(Clock.class); final DefaultBlockScheduler scheduler = new DefaultBlockScheduler(interBlockSeconds, acceptableClockDrift, clock); when(clock.millis()).thenReturn(parentTimeStamp * 1000); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader parentBlock = headerBuilder.timestamp(parentTimeStamp).buildHeader(); final AbstractBlockScheduler.BlockCreationTimeResult result = scheduler.getNextTimestamp(parentBlock); assertThat(result.getMillisecondsUntilValid()).isEqualTo(0); }
@Test public void mustWaitForNextBlockIfTooFarAheadOfSystemTime() { final Clock clock = mock(Clock.class); final DefaultBlockScheduler scheduler = new DefaultBlockScheduler(interBlockSeconds, acceptableClockDrift, clock); when(clock.millis()).thenReturn((parentTimeStamp - acceptableClockDrift) * 1000); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader parentBlock = headerBuilder.timestamp(parentTimeStamp).buildHeader(); final AbstractBlockScheduler.BlockCreationTimeResult result = scheduler.getNextTimestamp(parentBlock); assertThat(result.getMillisecondsUntilValid()).isEqualTo(interBlockSeconds * 1000); }
@Test public void ifParentTimestampIsBehindCurrentTimeChildUsesCurrentTime() { final long secondsSinceEpoch = parentTimeStamp + 5L; final Clock clock = mock(Clock.class); final DefaultBlockScheduler scheduler = new DefaultBlockScheduler(interBlockSeconds, acceptableClockDrift, clock); when(clock.millis()).thenReturn(secondsSinceEpoch * 1000); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader parentBlock = headerBuilder.timestamp(parentTimeStamp).buildHeader(); final AbstractBlockScheduler.BlockCreationTimeResult result = scheduler.getNextTimestamp(parentBlock); assertThat(result.getTimestampForHeader()).isEqualTo(secondsSinceEpoch); }