CDS: Real snapshot log trimming changes
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / SnapshotManagerTest.java
1 package org.opendaylight.controller.cluster.raft;
2
3 import static org.junit.Assert.assertArrayEquals;
4 import static org.junit.Assert.assertEquals;
5 import static org.junit.Assert.assertFalse;
6 import static org.junit.Assert.assertTrue;
7 import static org.mockito.Matchers.any;
8 import static org.mockito.Matchers.anyLong;
9 import static org.mockito.Mockito.doReturn;
10 import static org.mockito.Mockito.doThrow;
11 import static org.mockito.Mockito.mock;
12 import static org.mockito.Mockito.never;
13 import static org.mockito.Mockito.reset;
14 import static org.mockito.Mockito.times;
15 import static org.mockito.Mockito.verify;
16 import akka.actor.ActorRef;
17 import akka.japi.Procedure;
18 import akka.persistence.SnapshotSelectionCriteria;
19 import akka.testkit.TestActorRef;
20 import com.google.common.collect.ImmutableMap;
21 import java.util.Arrays;
22 import java.util.HashMap;
23 import org.junit.After;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.ArgumentCaptor;
27 import org.mockito.Mock;
28 import org.mockito.MockitoAnnotations;
29 import org.opendaylight.controller.cluster.DataPersistenceProvider;
30 import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
31 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
32 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
33 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
34 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
35 import org.slf4j.LoggerFactory;
36
37 public class SnapshotManagerTest extends AbstractActorTest {
38
39     @Mock
40     private RaftActorContext mockRaftActorContext;
41
42     @Mock
43     private ConfigParams mockConfigParams;
44
45     @Mock
46     private ReplicatedLog mockReplicatedLog;
47
48     @Mock
49     private DataPersistenceProvider mockDataPersistenceProvider;
50
51     @Mock
52     private RaftActorBehavior mockRaftActorBehavior;
53
54     @Mock
55     private Procedure<Void> mockProcedure;
56
57     private SnapshotManager snapshotManager;
58
59     private TestActorFactory factory;
60
61     private TestActorRef<MessageCollectorActor> actorRef;
62
63     @Before
64     public void setUp(){
65         MockitoAnnotations.initMocks(this);
66
67         doReturn(new HashMap<>()).when(mockRaftActorContext).getPeerAddresses();
68         doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
69         doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
70         doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
71         doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
72         doReturn("123").when(mockRaftActorContext).getId();
73         doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
74         doReturn("123").when(mockRaftActorBehavior).getLeaderId();
75
76         ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
77         doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
78         doReturn(5L).when(mockElectionTerm).getCurrentTerm();
79
80         snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
81         factory = new TestActorFactory(getSystem());
82
83         actorRef = factory.createTestActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
84         doReturn(actorRef).when(mockRaftActorContext).getActor();
85
86         snapshotManager.setCreateSnapshotCallable(mockProcedure);
87     }
88
89     @After
90     public void tearDown(){
91         factory.close();
92     }
93
94     @Test
95     public void testConstruction(){
96         assertEquals(false, snapshotManager.isCapturing());
97     }
98
99     @Test
100     public void testCaptureToInstall() throws Exception {
101
102         // Force capturing toInstall = true
103         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1, 0,
104                 new MockRaftActorContext.MockPayload()), 0, "follower-1");
105
106         assertEquals(true, snapshotManager.isCapturing());
107
108         verify(mockProcedure).apply(null);
109
110         CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
111
112         // LastIndex and LastTerm are picked up from the lastLogEntry
113         assertEquals(0L, captureSnapshot.getLastIndex());
114         assertEquals(1L, captureSnapshot.getLastTerm());
115
116         // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
117         assertEquals(0L, captureSnapshot.getLastAppliedIndex());
118         assertEquals(1L, captureSnapshot.getLastAppliedTerm());
119
120         //
121         assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
122         assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
123         actorRef.underlyingActor().clear();
124     }
125
126     @Test
127     public void testCapture() throws Exception {
128         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
129                 new MockRaftActorContext.MockPayload()), 9);
130
131         assertTrue(capture);
132
133         assertEquals(true, snapshotManager.isCapturing());
134
135         verify(mockProcedure).apply(null);
136
137         CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
138
139         // LastIndex and LastTerm are picked up from the lastLogEntry
140         assertEquals(9L, captureSnapshot.getLastIndex());
141         assertEquals(1L, captureSnapshot.getLastTerm());
142
143         // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
144         assertEquals(9L, captureSnapshot.getLastAppliedIndex());
145         assertEquals(1L, captureSnapshot.getLastAppliedTerm());
146
147         //
148         assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
149         assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
150
151         actorRef.underlyingActor().clear();
152
153     }
154
155     @Test
156     public void testCaptureWithCreateProcedureError () throws Exception {
157         doThrow(new Exception("mock")).when(mockProcedure).apply(null);
158
159         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
160                 new MockRaftActorContext.MockPayload()), 9);
161
162         assertFalse(capture);
163
164         assertEquals(false, snapshotManager.isCapturing());
165
166         verify(mockProcedure).apply(null);
167     }
168
169     @Test
170     public void testIllegalCapture() throws Exception {
171         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
172                 new MockRaftActorContext.MockPayload()), 9);
173
174         assertTrue(capture);
175
176         verify(mockProcedure).apply(null);
177
178         reset(mockProcedure);
179
180         // This will not cause snapshot capture to start again
181         capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
182                 new MockRaftActorContext.MockPayload()), 9);
183
184         assertFalse(capture);
185
186         verify(mockProcedure, never()).apply(null);
187     }
188
189     @Test
190     public void testPersistWhenReplicatedToAllIndexMinusOne(){
191         doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
192         doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
193
194         doReturn(ImmutableMap.builder().put("follower-1", "").build()).when(mockRaftActorContext).getPeerAddresses();
195
196         doReturn(8L).when(mockRaftActorContext).getLastApplied();
197
198         MockRaftActorContext.MockReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(
199                 3L, 9L, new MockRaftActorContext.MockPayload());
200
201         MockRaftActorContext.MockReplicatedLogEntry lastAppliedEntry = new MockRaftActorContext.MockReplicatedLogEntry(
202                 2L, 8L, new MockRaftActorContext.MockPayload());
203
204         doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
205         doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
206
207         // when replicatedToAllIndex = -1
208         snapshotManager.capture(lastLogEntry, -1);
209
210         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
211         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
212
213         ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
214         verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
215
216         Snapshot snapshot = snapshotArgumentCaptor.getValue();
217
218         assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
219         assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
220         assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
221         assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
222         assertArrayEquals("getState", bytes, snapshot.getState());
223         assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
224
225         verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
226     }
227
228     @Test
229     public void testPersistWhenReplicatedToAllIndexNotMinus(){
230         doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
231         doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
232         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
233         doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
234         doReturn(6L).when(replicatedLogEntry).getTerm();
235         doReturn(9L).when(replicatedLogEntry).getIndex();
236
237         // when replicatedToAllIndex != -1
238         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
239                 new MockRaftActorContext.MockPayload()), 9);
240
241         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
242         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
243
244         ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
245         verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
246
247         Snapshot snapshot = snapshotArgumentCaptor.getValue();
248
249         assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
250         assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
251         assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
252         assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
253         assertArrayEquals("getState", bytes, snapshot.getState());
254         assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
255
256         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
257
258         verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
259     }
260
261     @Test
262     public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold(){
263         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
264
265         // when replicatedToAllIndex = -1
266         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
267                 new MockRaftActorContext.MockPayload()), -1);
268
269         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
270
271         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
272
273         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
274
275         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
276     }
277
278     @Test
279     public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
280         doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
281         doReturn(100).when(mockReplicatedLog).dataSize();
282
283         doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
284         doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
285
286         long replicatedToAllIndex = 1;
287         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
288         doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
289         doReturn(6L).when(replicatedLogEntry).getTerm();
290         doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
291
292         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
293                 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
294
295         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, 2000000L);
296
297         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
298
299         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
300
301         verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
302     }
303
304     @Test
305     public void testPersistSendInstallSnapshot(){
306         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
307
308         // when replicatedToAllIndex = -1
309         boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
310                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
311
312         assertTrue(capture);
313
314         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
315
316         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
317
318         assertEquals(true, snapshotManager.isCapturing());
319
320         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
321
322         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
323
324         ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
325                 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
326
327         verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
328
329         SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
330
331         assertTrue(Arrays.equals(bytes, sendInstallSnapshot.getSnapshot().getState()));
332     }
333
334     @Test
335     public void testCallingPersistWithoutCaptureWillDoNothing(){
336         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
337
338         verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
339
340         verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
341
342         verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
343     }
344     @Test
345     public void testCallingPersistTwiceWillDoNoHarm(){
346         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
347
348         // when replicatedToAllIndex = -1
349         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
350                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
351
352         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
353
354         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
355
356         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
357
358         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
359
360         verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
361     }
362
363     @Test
364     public void testCommit(){
365         doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
366
367         // when replicatedToAllIndex = -1
368         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
369                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
370
371         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
372
373         assertEquals(true, snapshotManager.isCapturing());
374
375         snapshotManager.commit(100L, mockRaftActorBehavior);
376
377         assertEquals(false, snapshotManager.isCapturing());
378
379         verify(mockReplicatedLog).snapshotCommit();
380
381         verify(mockDataPersistenceProvider).deleteMessages(50L);
382
383         ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor = ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
384
385         verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
386
387         assertEquals(90, criteriaCaptor.getValue().maxSequenceNr()); // sequenceNumber = 100
388                                                                      // config snapShotBatchCount = 10
389                                                                      // therefore maxSequenceNumber = 90
390     }
391
392     @Test
393     public void testCommitBeforePersist(){
394         // when replicatedToAllIndex = -1
395         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
396                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
397
398         snapshotManager.commit(100L, mockRaftActorBehavior);
399
400         verify(mockReplicatedLog, never()).snapshotCommit();
401
402         verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
403
404         verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
405
406     }
407
408     @Test
409     public void testCommitBeforeCapture(){
410         snapshotManager.commit(100L, mockRaftActorBehavior);
411
412         verify(mockReplicatedLog, never()).snapshotCommit();
413
414         verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
415
416         verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
417
418     }
419
420     @Test
421     public void testCallingCommitMultipleTimesCausesNoHarm(){
422         doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
423
424         // when replicatedToAllIndex = -1
425         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
426                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
427
428         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
429
430         snapshotManager.commit(100L, mockRaftActorBehavior);
431
432         snapshotManager.commit(100L, mockRaftActorBehavior);
433
434         verify(mockReplicatedLog, times(1)).snapshotCommit();
435
436         verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
437
438         verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
439     }
440
441     @Test
442     public void testRollback(){
443         // when replicatedToAllIndex = -1
444         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
445                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
446
447         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
448
449         snapshotManager.rollback();
450
451         verify(mockReplicatedLog).snapshotRollback();
452     }
453
454
455     @Test
456     public void testRollbackBeforePersist(){
457         // when replicatedToAllIndex = -1
458         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
459                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
460
461         snapshotManager.rollback();
462
463         verify(mockReplicatedLog, never()).snapshotRollback();
464     }
465
466     @Test
467     public void testRollbackBeforeCapture(){
468         snapshotManager.rollback();
469
470         verify(mockReplicatedLog, never()).snapshotRollback();
471     }
472
473     @Test
474     public void testCallingRollbackMultipleTimesCausesNoHarm(){
475         // when replicatedToAllIndex = -1
476         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
477                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
478
479         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
480
481         snapshotManager.rollback();
482
483         snapshotManager.rollback();
484
485         verify(mockReplicatedLog, times(1)).snapshotRollback();
486     }
487
488     @Test
489     public void testTrimLogWhenTrimIndexLessThanLastApplied() {
490         doReturn(20L).when(mockRaftActorContext).getLastApplied();
491
492         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
493         doReturn(true).when(mockReplicatedLog).isPresent(10);
494         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
495         doReturn(5L).when(replicatedLogEntry).getTerm();
496
497         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
498         assertEquals("return index", 10L, retIndex);
499
500         verify(mockReplicatedLog).snapshotPreCommit(10, 5);
501         verify(mockReplicatedLog).snapshotCommit();
502
503         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
504     }
505
506     @Test
507     public void testTrimLogWhenLastAppliedNotSet() {
508         doReturn(-1L).when(mockRaftActorContext).getLastApplied();
509
510         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
511         doReturn(true).when(mockReplicatedLog).isPresent(10);
512         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
513         doReturn(5L).when(replicatedLogEntry).getTerm();
514
515         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
516         assertEquals("return index", -1L, retIndex);
517
518         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
519         verify(mockReplicatedLog, never()).snapshotCommit();
520
521         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
522     }
523
524     @Test
525     public void testTrimLogWhenLastAppliedZero() {
526         doReturn(0L).when(mockRaftActorContext).getLastApplied();
527
528         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
529         doReturn(true).when(mockReplicatedLog).isPresent(10);
530         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
531         doReturn(5L).when(replicatedLogEntry).getTerm();
532
533         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
534         assertEquals("return index", -1L, retIndex);
535
536         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
537         verify(mockReplicatedLog, never()).snapshotCommit();
538
539         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
540     }
541
542     @Test
543     public void testTrimLogWhenTrimIndexNotPresent() {
544         doReturn(20L).when(mockRaftActorContext).getLastApplied();
545
546         doReturn(false).when(mockReplicatedLog).isPresent(10);
547
548         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
549         assertEquals("return index", -1L, retIndex);
550
551         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
552         verify(mockReplicatedLog, never()).snapshotCommit();
553
554         // Trim index is greater than replicatedToAllIndex so should update it.
555         verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
556     }
557
558     @Test
559     public void testTrimLogAfterCapture(){
560         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
561                 new MockRaftActorContext.MockPayload()), 9);
562
563         assertTrue(capture);
564
565         assertEquals(true, snapshotManager.isCapturing());
566
567         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
568         doReturn(20L).when(mockRaftActorContext).getLastApplied();
569         doReturn(true).when(mockReplicatedLog).isPresent(10);
570         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
571         doReturn(5L).when(replicatedLogEntry).getTerm();
572
573         snapshotManager.trimLog(10, mockRaftActorBehavior);
574
575         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
576         verify(mockReplicatedLog, never()).snapshotCommit();
577
578     }
579
580     @Test
581     public void testTrimLogAfterCaptureToInstall(){
582         boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
583                 new MockRaftActorContext.MockPayload()), 9, "follower-1");
584
585         assertTrue(capture);
586
587         assertEquals(true, snapshotManager.isCapturing());
588
589         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
590         doReturn(20L).when(mockRaftActorContext).getLastApplied();
591         doReturn(true).when(mockReplicatedLog).isPresent(10);
592         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
593         doReturn(5L).when(replicatedLogEntry).getTerm();
594
595         snapshotManager.trimLog(10, mockRaftActorBehavior);
596
597         verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
598         verify(mockReplicatedLog, never()).snapshotCommit();
599
600     }
601
602     @Test
603     public void testLastAppliedTermInformationReader() {
604
605         LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
606
607         doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
608         doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
609
610         ReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(6L, 9L,
611                 new MockRaftActorContext.MockPayload());
612
613         // No followers and valid lastLogEntry
614         reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
615
616         assertEquals("getTerm", 6L, reader.getTerm());
617         assertEquals("getIndex", 9L, reader.getIndex());
618
619         // No followers and null lastLogEntry
620         reader.init(mockReplicatedLog, 1L, null, false);
621
622         assertEquals("getTerm", -1L, reader.getTerm());
623         assertEquals("getIndex", -1L, reader.getIndex());
624
625         // Followers and valid originalIndex entry
626         doReturn(new MockRaftActorContext.MockReplicatedLogEntry(5L, 8L,
627                 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
628         reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
629
630         assertEquals("getTerm", 5L, reader.getTerm());
631         assertEquals("getIndex", 8L, reader.getIndex());
632
633         // Followers and null originalIndex entry and valid snapshot index
634         reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
635
636         assertEquals("getTerm", 4L, reader.getTerm());
637         assertEquals("getIndex", 7L, reader.getIndex());
638
639         // Followers and null originalIndex entry and invalid snapshot index
640         doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
641         reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
642
643         assertEquals("getTerm", -1L, reader.getTerm());
644         assertEquals("getIndex", -1L, reader.getIndex());
645     }
646 }