@Test
  public void testChunkFillerSleep() throws Exception {
    router = getNonBlockingRouter();
    // At this time there are no put operations, so the ChunkFillerThread will eventually go into WAITING state.
    Thread chunkFillerThread = TestUtils.getThreadByThisName("ChunkFillerThread");
    Assert.assertTrue("ChunkFillerThread should have gone to WAITING state as there are no active operations",
        waitForThreadState(chunkFillerThread, Thread.State.WAITING));
    int blobSize = chunkSize * 2;
    RequestAndResult requestAndResult = new RequestAndResult(blobSize);
    requestAndResultsList.add(requestAndResult);
    MockReadableStreamChannel putChannel = new MockReadableStreamChannel(blobSize, false);
    CompletableFuture<String> future =
        router.putBlob(requestAndResult.putBlobProperties, requestAndResult.putUserMetadata, putChannel,
            requestAndResult.options);
    ByteBuffer src = ByteBuffer.wrap(requestAndResult.putContent);
    // There will be two chunks written to the underlying writable channel, and so two events will be fired.
    int writeSize = blobSize / 2;
    ByteBuffer buf1 = ByteBuffer.allocate(writeSize);
    src.get(buf1.array());
    putChannel.write(buf1);
    // The first write will wake up (or will have woken up) the ChunkFiller thread and it will not go to WAITING until
    // the operation is complete as an attempt to fill chunks will be done by the ChunkFiller in every iteration
    // until the operation is complete.
    Assert.assertTrue(
        "ChunkFillerThread should have gone to RUNNABLE state as there is an active operation that is not yet complete",
        waitForThreadState(chunkFillerThread, Thread.State.RUNNABLE));
    ByteBuffer buf2 = ByteBuffer.allocate(writeSize);
    src.get(buf2.array());
    putChannel.write(buf2);
    // At this time all writes have finished, so the ChunkFiller thread will eventually go (or will have already gone)
    // to WAITING due to this write.
    Assert.assertTrue(
        "ChunkFillerThread should have gone to WAITING state as the only active operation is now complete",
        waitForThreadState(chunkFillerThread, Thread.State.WAITING));
    try {
      future.get(MAX_WAIT_MS, TimeUnit.MILLISECONDS);
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
      Assert.fail("Operation should not take too long to complete");
    }
    requestAndResult.result = future;
    assertSuccess();
    assertCloseCleanup();
  }
Test to verify that the chunk filler goes to sleep when there are no active operations and is woken up when
operations become active.
@throws Exception
ambry-router/src/test/java/com/github/ambry/router/PutManagerTest.java