void write(ByteBuffer buf) throws Exception {
    // This is a mock class, that is going to be used for very specific tests. The tests should not call this method
    // before readInto() is called nor should it call it with a buffer with invalid size. However, this method guards
    // against these situations anyway to fail the tests immediately when this class is incorrectly used.
    int toRead = buf.remaining();
    if (writableChannel == null || toRead + readSoFar > size) {
      throw new IllegalStateException("Cannot push data");
    }
    if (beBad) {
      Exception exception = new Exception("Channel encountered an error");
      returnedFuture.done(null, exception);
      if (callback != null) {
        callback.onCompletion(null, exception);
      }
      return;
    }
    writableChannel.write(buf, null).get();
    readSoFar += toRead;
    if (readSoFar == size) {
      if (sendZeroSizedBuffers) {
        // Send a final zero sized buffer.
        sendZeroAndWait();
      }
      returnedFuture.done(size, null);
      callback.onCompletion(size, null);
    } else {
      if (sendZeroSizedBuffers && random.nextInt(2) % 2 == 0) {
        // Send a zero-sized blob with 50% probability.
        sendZeroAndWait();
      }
    }
  }
write this buffer into the associated {@link AsyncWritableChannel} and return only after the latter has
completely read it.
@param buf the buf to write.
@throws Exception if the future await throws an exception.
ambry-router/src/test/java/com/github/ambry/router/PutManagerTest.java