Bug 3570: Persist snapshot on follower ApplySnapshot
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / SnapshotManagerTest.java
index 90272fec980f46ed99f85d23d2cd24b859eddd66..d94eb6b041a52631c5ca02684e0c24bc32b170e6 100644 (file)
@@ -1,29 +1,33 @@
 package org.opendaylight.controller.cluster.raft;
 
-import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import akka.actor.ActorRef;
 import akka.japi.Procedure;
 import akka.persistence.SnapshotSelectionCriteria;
 import akka.testkit.TestActorRef;
+import com.google.common.collect.ImmutableMap;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.cluster.DataPersistenceProvider;
+import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
@@ -65,14 +69,20 @@ public class SnapshotManagerTest extends AbstractActorTest {
         doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
         doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
         doReturn("123").when(mockRaftActorContext).getId();
+        doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
         doReturn("123").when(mockRaftActorBehavior).getLeaderId();
 
+        ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
+        doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
+        doReturn(5L).when(mockElectionTerm).getCurrentTerm();
+
         snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
         factory = new TestActorFactory(getSystem());
 
         actorRef = factory.createTestActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
         doReturn(actorRef).when(mockRaftActorContext).getActor();
 
+        snapshotManager.setCreateSnapshotCallable(mockProcedure);
     }
 
     @After
@@ -86,15 +96,17 @@ public class SnapshotManagerTest extends AbstractActorTest {
     }
 
     @Test
-    public void testCaptureToInstall(){
+    public void testCaptureToInstall() throws Exception {
 
         // Force capturing toInstall = true
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1, 0,
-                new MockRaftActorContext.MockPayload()), 0);
+                new MockRaftActorContext.MockPayload()), 0, "follower-1");
 
         assertEquals(true, snapshotManager.isCapturing());
 
-        CaptureSnapshot captureSnapshot = MessageCollectorActor.expectFirstMatching(actorRef, CaptureSnapshot.class);
+        verify(mockProcedure).apply(null);
+
+        CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
 
         // LastIndex and LastTerm are picked up from the lastLogEntry
         assertEquals(0L, captureSnapshot.getLastIndex());
@@ -111,13 +123,18 @@ public class SnapshotManagerTest extends AbstractActorTest {
     }
 
     @Test
-    public void testCapture(){
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+    public void testCapture() throws Exception {
+        boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
                 new MockRaftActorContext.MockPayload()), 9);
 
+        assertTrue(capture);
+
         assertEquals(true, snapshotManager.isCapturing());
 
-        CaptureSnapshot captureSnapshot = MessageCollectorActor.expectFirstMatching(actorRef, CaptureSnapshot.class);
+        verify(mockProcedure).apply(null);
+
+        CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
+
         // LastIndex and LastTerm are picked up from the lastLogEntry
         assertEquals(9L, captureSnapshot.getLastIndex());
         assertEquals(1L, captureSnapshot.getLastTerm());
@@ -135,103 +152,76 @@ public class SnapshotManagerTest extends AbstractActorTest {
     }
 
     @Test
-    public void testIllegalCapture() throws Exception {
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
-                new MockRaftActorContext.MockPayload()), 9);
-
-        List<CaptureSnapshot> allMatching = MessageCollectorActor.getAllMatching(actorRef, CaptureSnapshot.class);
+    public void testCaptureWithCreateProcedureError () throws Exception {
+        doThrow(new Exception("mock")).when(mockProcedure).apply(null);
 
-        assertEquals(1, allMatching.size());
-
-        // This will not cause snapshot capture to start again
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+        boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
                 new MockRaftActorContext.MockPayload()), 9);
 
-        allMatching = MessageCollectorActor.getAllMatching(actorRef, CaptureSnapshot.class);
+        assertFalse(capture);
 
-        assertEquals(1, allMatching.size());
+        assertEquals(false, snapshotManager.isCapturing());
+
+        verify(mockProcedure).apply(null);
     }
 
     @Test
-    public void testPersistWhenReplicatedToAllIndexMinusOne(){
-        doReturn("123").when(mockRaftActorContext).getId();
-        doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
-        doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
-
-        // when replicatedToAllIndex = -1
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
-                new MockRaftActorContext.MockPayload()), -1);
-
-        snapshotManager.create(mockProcedure);
-
-        byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
-        snapshotManager.persist(mockDataPersistenceProvider, bytes, mockRaftActorBehavior);
-
-        ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
-        verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
-
-        Snapshot snapshot = snapshotArgumentCaptor.getValue();
+    public void testIllegalCapture() throws Exception {
+        boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+                new MockRaftActorContext.MockPayload()), 9);
 
-        assertEquals(6, snapshot.getLastAppliedTerm());
-        assertEquals(9, snapshot.getLastAppliedIndex());
-        assertEquals(9, snapshot.getLastIndex());
-        assertEquals(6, snapshot.getLastTerm());
-        assertEquals(10, snapshot.getState().length);
-        assertTrue(Arrays.equals(bytes, snapshot.getState()));
-        assertEquals(0, snapshot.getUnAppliedEntries().size());
+        assertTrue(capture);
 
-        verify(mockReplicatedLog).snapshotPreCommit(45L, 6L);
-    }
+        verify(mockProcedure).apply(null);
 
+        reset(mockProcedure);
 
-    @Test
-    public void testCreate() throws Exception {
-        // when replicatedToAllIndex = -1
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
-                new MockRaftActorContext.MockPayload()), -1);
+        // This will not cause snapshot capture to start again
+        capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+                new MockRaftActorContext.MockPayload()), 9);
 
-        snapshotManager.create(mockProcedure);
+        assertFalse(capture);
 
-        verify(mockProcedure).apply(null);
+        verify(mockProcedure, never()).apply(null);
     }
 
     @Test
-    public void testCallingCreateMultipleTimesCausesNoHarm() throws Exception {
-        // when replicatedToAllIndex = -1
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
-                new MockRaftActorContext.MockPayload()), -1);
+    public void testPersistWhenReplicatedToAllIndexMinusOne(){
+        doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
+        doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
 
-        snapshotManager.create(mockProcedure);
+        doReturn(ImmutableMap.builder().put("follower-1", "").build()).when(mockRaftActorContext).getPeerAddresses();
 
-        snapshotManager.create(mockProcedure);
+        doReturn(8L).when(mockRaftActorContext).getLastApplied();
 
-        verify(mockProcedure, times(1)).apply(null);
-    }
+        MockRaftActorContext.MockReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(
+                3L, 9L, new MockRaftActorContext.MockPayload());
 
-    @Test
-    public void testCallingCreateBeforeCapture() throws Exception {
-        snapshotManager.create(mockProcedure);
+        MockRaftActorContext.MockReplicatedLogEntry lastAppliedEntry = new MockRaftActorContext.MockReplicatedLogEntry(
+                2L, 8L, new MockRaftActorContext.MockPayload());
 
-        verify(mockProcedure, times(0)).apply(null);
-    }
+        doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
+        doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
 
-    @Test
-    public void testCallingCreateAfterPersist() throws Exception {
         // when replicatedToAllIndex = -1
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
-                new MockRaftActorContext.MockPayload()), -1);
+        snapshotManager.capture(lastLogEntry, -1);
 
-        snapshotManager.create(mockProcedure);
-
-        verify(mockProcedure, times(1)).apply(null);
+        byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
+        snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
+        verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
 
-        Mockito.reset(mockProcedure);
+        Snapshot snapshot = snapshotArgumentCaptor.getValue();
 
-        snapshotManager.create(mockProcedure);
+        assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
+        assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
+        assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
+        assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
+        assertArrayEquals("getState", bytes, snapshot.getState());
+        assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
 
-        verify(mockProcedure, never()).apply(null);
+        verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
     }
 
     @Test
@@ -247,11 +237,20 @@ public class SnapshotManagerTest extends AbstractActorTest {
         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
                 new MockRaftActorContext.MockPayload()), 9);
 
-        snapshotManager.create(mockProcedure);
+        byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
+        snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
+
+        ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
+        verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
 
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        Snapshot snapshot = snapshotArgumentCaptor.getValue();
 
-        verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
+        assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
+        assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
+        assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
+        assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
+        assertArrayEquals("getState", bytes, snapshot.getState());
+        assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
 
         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
 
@@ -267,15 +266,11 @@ public class SnapshotManagerTest extends AbstractActorTest {
         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
                 new MockRaftActorContext.MockPayload()), -1);
 
-        snapshotManager.create(mockProcedure);
-
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
 
         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
-
-        verify(mockRaftActorBehavior).setReplicatedToAllIndex(-1);
     }
 
     @Test
@@ -283,14 +278,14 @@ public class SnapshotManagerTest extends AbstractActorTest {
         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
 
         // when replicatedToAllIndex = -1
-        snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+        boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.create(mockProcedure);
+        assertTrue(capture);
 
         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
 
-        snapshotManager.persist(mockDataPersistenceProvider, bytes, mockRaftActorBehavior);
+        snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
 
@@ -308,7 +303,7 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     @Test
     public void testCallingPersistWithoutCaptureWillDoNothing(){
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
 
@@ -322,13 +317,11 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.create(mockProcedure);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
-
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
 
@@ -339,19 +332,19 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     @Test
     public void testCommit(){
+        doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
+
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
-
-        snapshotManager.create(mockProcedure);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
-        snapshotManager.commit(mockDataPersistenceProvider, 100L);
+        snapshotManager.commit(100L, mockRaftActorBehavior);
 
         verify(mockReplicatedLog).snapshotCommit();
 
-        verify(mockDataPersistenceProvider).deleteMessages(100L);
+        verify(mockDataPersistenceProvider).deleteMessages(50L);
 
         ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor = ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
 
@@ -366,9 +359,9 @@ public class SnapshotManagerTest extends AbstractActorTest {
     public void testCommitBeforePersist(){
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.commit(mockDataPersistenceProvider, 100L);
+        snapshotManager.commit(100L, mockRaftActorBehavior);
 
         verify(mockReplicatedLog, never()).snapshotCommit();
 
@@ -380,7 +373,7 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     @Test
     public void testCommitBeforeCapture(){
-        snapshotManager.commit(mockDataPersistenceProvider, 100L);
+        snapshotManager.commit(100L, mockRaftActorBehavior);
 
         verify(mockReplicatedLog, never()).snapshotCommit();
 
@@ -392,21 +385,21 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     @Test
     public void testCallingCommitMultipleTimesCausesNoHarm(){
+        doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
+
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.create(mockProcedure);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.commit(100L, mockRaftActorBehavior);
 
-        snapshotManager.commit(mockDataPersistenceProvider, 100L);
-
-        snapshotManager.commit(mockDataPersistenceProvider, 100L);
+        snapshotManager.commit(100L, mockRaftActorBehavior);
 
         verify(mockReplicatedLog, times(1)).snapshotCommit();
 
-        verify(mockDataPersistenceProvider, times(1)).deleteMessages(100L);
+        verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
 
         verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
     }
@@ -415,11 +408,9 @@ public class SnapshotManagerTest extends AbstractActorTest {
     public void testRollback(){
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.create(mockProcedure);
-
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         snapshotManager.rollback();
 
@@ -431,7 +422,7 @@ public class SnapshotManagerTest extends AbstractActorTest {
     public void testRollbackBeforePersist(){
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
         snapshotManager.rollback();
 
@@ -449,11 +440,9 @@ public class SnapshotManagerTest extends AbstractActorTest {
     public void testCallingRollbackMultipleTimesCausesNoHarm(){
         // when replicatedToAllIndex = -1
         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
-                new MockRaftActorContext.MockPayload()), -1);
+                new MockRaftActorContext.MockPayload()), -1, "follower-1");
 
-        snapshotManager.create(mockProcedure);
-
-        snapshotManager.persist(mockDataPersistenceProvider, new byte[]{}, mockRaftActorBehavior);
+        snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
 
         snapshotManager.rollback();
 
@@ -463,39 +452,91 @@ public class SnapshotManagerTest extends AbstractActorTest {
     }
 
     @Test
-    public void testTrimLog(){
-        ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
-        ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
+    public void testTrimLogWhenTrimIndexLessThanLastApplied() {
         doReturn(20L).when(mockRaftActorContext).getLastApplied();
+
+        ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
         doReturn(true).when(mockReplicatedLog).isPresent(10);
-        doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
-        doReturn(5L).when(mockElectionTerm).getCurrentTerm();
         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
         doReturn(5L).when(replicatedLogEntry).getTerm();
 
-        snapshotManager.trimLog(10);
+        long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
+        assertEquals("return index", 10L, retIndex);
 
         verify(mockReplicatedLog).snapshotPreCommit(10, 5);
         verify(mockReplicatedLog).snapshotCommit();
+
+        verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
+    }
+
+    @Test
+    public void testTrimLogWhenLastAppliedNotSet() {
+        doReturn(-1L).when(mockRaftActorContext).getLastApplied();
+
+        ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
+        doReturn(true).when(mockReplicatedLog).isPresent(10);
+        doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
+        doReturn(5L).when(replicatedLogEntry).getTerm();
+
+        long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
+        assertEquals("return index", -1L, retIndex);
+
+        verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
+        verify(mockReplicatedLog, never()).snapshotCommit();
+
+        verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
+    }
+
+    @Test
+    public void testTrimLogWhenLastAppliedZero() {
+        doReturn(0L).when(mockRaftActorContext).getLastApplied();
+
+        ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
+        doReturn(true).when(mockReplicatedLog).isPresent(10);
+        doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
+        doReturn(5L).when(replicatedLogEntry).getTerm();
+
+        long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
+        assertEquals("return index", -1L, retIndex);
+
+        verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
+        verify(mockReplicatedLog, never()).snapshotCommit();
+
+        verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
+    }
+
+    @Test
+    public void testTrimLogWhenTrimIndexNotPresent() {
+        doReturn(20L).when(mockRaftActorContext).getLastApplied();
+
+        doReturn(false).when(mockReplicatedLog).isPresent(10);
+
+        long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
+        assertEquals("return index", -1L, retIndex);
+
+        verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
+        verify(mockReplicatedLog, never()).snapshotCommit();
+
+        // Trim index is greater than replicatedToAllIndex so should update it.
+        verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
     }
 
     @Test
     public void testTrimLogAfterCapture(){
-        snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+        boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
                 new MockRaftActorContext.MockPayload()), 9);
 
+        assertTrue(capture);
+
         assertEquals(true, snapshotManager.isCapturing());
 
-        ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
         doReturn(20L).when(mockRaftActorContext).getLastApplied();
         doReturn(true).when(mockReplicatedLog).isPresent(10);
-        doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
-        doReturn(5L).when(mockElectionTerm).getCurrentTerm();
         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
         doReturn(5L).when(replicatedLogEntry).getTerm();
 
-        snapshotManager.trimLog(10);
+        snapshotManager.trimLog(10, mockRaftActorBehavior);
 
         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
         verify(mockReplicatedLog, never()).snapshotCommit();
@@ -504,25 +545,68 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     @Test
     public void testTrimLogAfterCaptureToInstall(){
-        snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
-                new MockRaftActorContext.MockPayload()), 9);
+        boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
+                new MockRaftActorContext.MockPayload()), 9, "follower-1");
+
+        assertTrue(capture);
 
         assertEquals(true, snapshotManager.isCapturing());
 
-        ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
         doReturn(20L).when(mockRaftActorContext).getLastApplied();
         doReturn(true).when(mockReplicatedLog).isPresent(10);
-        doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
-        doReturn(5L).when(mockElectionTerm).getCurrentTerm();
         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
         doReturn(5L).when(replicatedLogEntry).getTerm();
 
-        snapshotManager.trimLog(10);
+        snapshotManager.trimLog(10, mockRaftActorBehavior);
 
         verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
         verify(mockReplicatedLog, never()).snapshotCommit();
 
     }
 
+    @Test
+    public void testLastAppliedTermInformationReader() {
+
+        LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
+
+        doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
+        doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
+
+        ReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(6L, 9L,
+                new MockRaftActorContext.MockPayload());
+
+        // No followers and valid lastLogEntry
+        reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
+
+        assertEquals("getTerm", 6L, reader.getTerm());
+        assertEquals("getIndex", 9L, reader.getIndex());
+
+        // No followers and null lastLogEntry
+        reader.init(mockReplicatedLog, 1L, null, false);
+
+        assertEquals("getTerm", -1L, reader.getTerm());
+        assertEquals("getIndex", -1L, reader.getIndex());
+
+        // Followers and valid originalIndex entry
+        doReturn(new MockRaftActorContext.MockReplicatedLogEntry(5L, 8L,
+                new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
+        reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
+
+        assertEquals("getTerm", 5L, reader.getTerm());
+        assertEquals("getIndex", 8L, reader.getIndex());
+
+        // Followers and null originalIndex entry and valid snapshot index
+        reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
+
+        assertEquals("getTerm", 4L, reader.getTerm());
+        assertEquals("getIndex", 7L, reader.getIndex());
+
+        // Followers and null originalIndex entry and invalid snapshot index
+        doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
+        reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
+
+        assertEquals("getTerm", -1L, reader.getTerm());
+        assertEquals("getIndex", -1L, reader.getIndex());
+    }
 }
\ No newline at end of file