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