@Test
public void shouldReturnSnapshotFollowedByLogEntriesInResponseToRepeatedGetNextCommittedCallsWithInitialIndexToSearchFromAsZeroAndOverlapBetweenLogAndSnapshot() throws Exception {

    // we have a snapshot that contains data to index 9 (inclusive)
    SnapshotsStore.ExtendedSnapshot storedSnapshot = new UnitTestSnapshot(9L, 2);
    // we have a log that contains entries from index 7 onwards
    LogEntry unappliedEntries[] = {
            CLIENT(7, 2, new UnitTestCommand()),
            NOOP(8, 2),
            NOOP(9, 3),
            CLIENT(10, 3, new UnitTestCommand()),
            CLIENT(11, 3, new UnitTestCommand()),
    };
    final LogEntry[] entries = new LogEntry[] {
            unappliedEntries[0],
            unappliedEntries[1],
            unappliedEntries[2],
            unappliedEntries[3],
            unappliedEntries[4], // <------ we've committed up to here
            CLIENT(12, 3, new UnitTestCommand())
    };
    clearLog(); // clear out the log completely - we don't even want the sentinel
    insertIntoLog(entries);
    // set the current term
    // shouldn't matter if it's greater than the last term in the log
    long currentTerm = 5;
    store.setCurrentTerm(currentTerm);
    // set the committed index
    long commitIndex = 11;
    store.setCommitIndex(commitIndex);
    // have the snapshot store return the snapshot
    when(snapshotsStore.getLatestSnapshot()).thenReturn(storedSnapshot);
    //
    // situation is as follows:
    //
    //                                             +----------- COMMITTED
    //                                             V
    //                       ------------------------------
    //    .... EMPTY ....   | 07 | 08 | 09 | 10 | 11 | 12 | (LOG)
    //                      ------------------------------
    //  ------------------------------------
    // |         LAST APPLIED = 9          | (SNAPSHOT)
    // ------------------------------------
    //  ^
    //  +----------- INDEX TO SEARCH FROM = 0
    //
    Committed committed;
    // OK, now, let's start by saying that the last index we applied was '0' (IOW, we have no state and have to start from scratch)
    // we should get the snapshot back
    committed = algorithm.getNextCommitted(0);
    checkMatchingSnapshot(committed, storedSnapshot);
    // when we make the second call we should ignore the
    // overlapping log region
    // and return the first log entry with new info
    // i.e. the entry at index 10
    committed = algorithm.getNextCommitted(committed.getIndex()); // index = 9
    checkMatchingCommittedLogEntry(committed, unappliedEntries[3]);
    // when we make the third call we should get the last committed unapplied log entry
    committed = algorithm.getNextCommitted(committed.getIndex()); // index = 10
    checkMatchingCommittedLogEntry(committed, unappliedEntries[4]);
    // if we make a fourth call we should get nothing since there are no committed unapplied entries left
    committed = algorithm.getNextCommitted(committed.getIndex()); // index = 11
    assertThat(committed, nullValue());
    // algorithm should have exactly the same state at the end
    assertThatLogContains(entries);
    assertThatTermAndCommitIndexHaveValues(currentTerm, commitIndex);
}