### Question:
RaftLogShipper { public synchronized void onMatch( long newMatchIndex, LeaderContext leaderContext ) { boolean progress = newMatchIndex > matchIndex; if ( newMatchIndex > matchIndex ) { matchIndex = newMatchIndex; } else { log.warn( "%s: match index not progressing. This should be transient.", statusAsString() ); } switch ( mode ) { case MISMATCH: if ( sendNextBatchAfterMatch( leaderContext ) ) { log.info( "%s: caught up after mismatch, moving to PIPELINE mode", statusAsString() ); mode = PIPELINE; } else { log.info( "%s: starting catch up after mismatch, moving to CATCHUP mode", statusAsString() ); mode = Mode.CATCHUP; } break; case CATCHUP: if ( matchIndex >= lastSentIndex ) { if ( sendNextBatchAfterMatch( leaderContext ) ) { log.info( "%s: caught up, moving to PIPELINE mode", statusAsString() ); mode = PIPELINE; } } break; case PIPELINE: if ( matchIndex == lastSentIndex ) { abortTimeout(); } else if ( progress ) { scheduleTimeout( retryTimeMillis ); } break; default: throw new IllegalStateException( "Unknown mode: " + mode ); } lastLeaderContext = leaderContext; } RaftLogShipper( Outbound<MemberId, RaftMessages.RaftMessage> outbound, LogProvider logProvider,
                    ReadableRaftLog raftLog, Clock clock, TimerService timerService,
                    MemberId leader, MemberId follower, long leaderTerm, long leaderCommit, long retryTimeMillis,
                    int catchupBatchSize, int maxAllowedShippingLag, InFlightCache inFlightCache ); Object identity(); synchronized void start(); synchronized void stop(); synchronized void onMismatch( long lastRemoteAppendIndex, LeaderContext leaderContext ); synchronized void onMatch( long newMatchIndex, LeaderContext leaderContext ); synchronized void onNewEntries( long prevLogIndex, long prevLogTerm, RaftLogEntry[] newLogEntries,
                                           LeaderContext leaderContext ); synchronized void onCommitUpdate( LeaderContext leaderContext );  }### Answer:
@Test public void shouldSendLogCompactionInfoToFollowerOnMatchIfEntryHasBeenPrunedAway() throws Exception { raftLog.append( entry0 ); raftLog.append( entry1 ); raftLog.append( entry2 ); raftLog.append( entry3 ); startLogShipper(); outbound.clear(); raftLog.prune( 2 ); logShipper.onMatch( 1, new LeaderContext( 0, 0 ) ); assertTrue( outbound.hasAnyEntriesTo( follower ) ); assertThat( outbound.sentTo( follower ), hasMessage( new RaftMessages.LogCompactionInfo( leader, 0, 2 ) ) ); }