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