### Question:
ThrottlingSyncSource implements SyncSource { @Override public SafeFuture<Void> requestBlocksByRange( final UInt64 startSlot, final UInt64 count, final UInt64 step, final ResponseStreamListener<SignedBeaconBlock> listener) { if (rateTracker.wantToRequestObjects(count.longValue()) > 0) { LOG.debug("Sending request for {} blocks", count); return delegate.requestBlocksByRange(startSlot, count, step, listener); } else { return asyncRunner.runAfterDelay( () -> requestBlocksByRange(startSlot, count, step, listener), 3, TimeUnit.SECONDS); } } ThrottlingSyncSource(
      final AsyncRunner asyncRunner,
      final TimeProvider timeProvider,
      final SyncSource delegate,
      final int maxBlocksPerMinute); @Override SafeFuture<Void> requestBlocksByRange(
      final UInt64 startSlot,
      final UInt64 count,
      final UInt64 step,
      final ResponseStreamListener<SignedBeaconBlock> listener); @Override SafeFuture<Void> disconnectCleanly(final DisconnectReason reason); @Override String toString();  }### Answer:
@Test void shouldRequestBlocksImmediatelyIfRateLimitNotExceeded() { final UInt64 count = UInt64.valueOf(MAX_BLOCKS_PER_MINUTE - 1); ignoreFuture(source.requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); ignoreFuture(source.requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); }
@Test void shouldDelayRequestIfBlockLimitAlreadyExceeded() { final UInt64 count = UInt64.valueOf(MAX_BLOCKS_PER_MINUTE); ignoreFuture(source.requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); ignoreFuture(source.requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); verifyNoMoreInteractions(delegate); timeProvider.advanceTimeBySeconds(61); asyncRunner.executeQueuedActions(); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); }
@Test void shouldContinueDelayingIfRequestStillExceeded() { final UInt64 count = UInt64.valueOf(MAX_BLOCKS_PER_MINUTE); ignoreFuture(source.requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); ignoreFuture(source.requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.ZERO, count, ONE, listener)); verifyNoMoreInteractions(delegate); timeProvider.advanceTimeBySeconds(30); asyncRunner.executeQueuedActions(); verifyNoMoreInteractions(delegate); timeProvider.advanceTimeBySeconds(31); asyncRunner.executeQueuedActions(); ignoreFuture(verify(delegate).requestBlocksByRange(UInt64.valueOf(100), count, ONE, listener)); }