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