class SQSPoller {

    public void poll(final int remainingTimeInMillis) {
        Instant cutoff = Instant.now(clock)
                .plusMillis(remainingTimeInMillis)
                .minusMillis(TIMEOUT_BUFFER_IN_MILLIS);
        messageDispatcher.reset();
        int estimatedCapacity;
        while ((estimatedCapacity = messageDispatcher.getEstimatedCapacity(cutoff)) > 0) {
            List<Message> toProcess = sqsProxy.receiveMessages(estimatedCapacity);

            if (toProcess.isEmpty()) {
                log.info("No messages received from queue. Returning until next polling cycle to save cost.");
                return;
            }

            messageDispatcher.dispatch(toProcess);
        }
    }

}

class SQSPollerTest {

    private static final Instant NOW;
    @Mock
    private SQSProxy sqsProxy;
    @Mock
    private MessageDispatcher messageDispatcher;
    private SQSPoller poller;

    @Test
    public void poll_noMessagesReceived() throws Exception {

        when(messageDispatcher.getEstimatedCapacity(any())).thenReturn(1);
        when(sqsProxy.receiveMessages(anyInt())).thenReturn(Collections.emptyList());

        poller.poll(SQSPoller.TIMEOUT_BUFFER_IN_MILLIS * 2);

        verify(messageDispatcher, never()).dispatch(any());
    }

}