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