Bug 2461 : Adding capture snapshot JMX operation.
[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 testCaptureWithNullLastLogEntry() throws Exception {
165         boolean capture = snapshotManager.capture(null, 1);
166
167         assertTrue(capture);
168
169         assertEquals(true, snapshotManager.isCapturing());
170
171         verify(mockProcedure).apply(null);
172
173         CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
174
175         System.out.println(captureSnapshot);
176
177         // LastIndex and LastTerm are picked up from the lastLogEntry
178         assertEquals(-1L, captureSnapshot.getLastIndex());
179         assertEquals(-1L, captureSnapshot.getLastTerm());
180
181         // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
182         assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
183         assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
184
185         //
186         assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
187         assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
188         actorRef.underlyingActor().clear();
189
190     }
191
192     @Test
193     public void testCaptureWithCreateProcedureError () throws Exception {
194         doThrow(new Exception("mock")).when(mockProcedure).apply(null);
195
196         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
197                 new MockRaftActorContext.MockPayload()), 9);
198
199         assertFalse(capture);
200
201         assertEquals(false, snapshotManager.isCapturing());
202
203         verify(mockProcedure).apply(null);
204     }
205
206     @Test
207     public void testIllegalCapture() throws Exception {
208         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
209                 new MockRaftActorContext.MockPayload()), 9);
210
211         assertTrue(capture);
212
213         verify(mockProcedure).apply(null);
214
215         reset(mockProcedure);
216
217         // This will not cause snapshot capture to start again
218         capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
219                 new MockRaftActorContext.MockPayload()), 9);
220
221         assertFalse(capture);
222
223         verify(mockProcedure, never()).apply(null);
224     }
225
226     @Test
227     public void testPersistWhenReplicatedToAllIndexMinusOne(){
228         doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
229         doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
230
231         doReturn(ImmutableMap.builder().put("follower-1", "").build()).when(mockRaftActorContext).getPeerAddresses();
232
233         doReturn(8L).when(mockRaftActorContext).getLastApplied();
234
235         MockRaftActorContext.MockReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(
236                 3L, 9L, new MockRaftActorContext.MockPayload());
237
238         MockRaftActorContext.MockReplicatedLogEntry lastAppliedEntry = new MockRaftActorContext.MockReplicatedLogEntry(
239                 2L, 8L, new MockRaftActorContext.MockPayload());
240
241         doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
242         doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
243
244         // when replicatedToAllIndex = -1
245         snapshotManager.capture(lastLogEntry, -1);
246
247         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
248         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
249
250         ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
251         verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
252
253         Snapshot snapshot = snapshotArgumentCaptor.getValue();
254
255         assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
256         assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
257         assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
258         assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
259         assertArrayEquals("getState", bytes, snapshot.getState());
260         assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
261
262         verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
263     }
264
265     @Test
266     public void testPersistWhenReplicatedToAllIndexNotMinus(){
267         doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
268         doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
269         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
270         doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
271         doReturn(6L).when(replicatedLogEntry).getTerm();
272         doReturn(9L).when(replicatedLogEntry).getIndex();
273
274         // when replicatedToAllIndex != -1
275         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
276                 new MockRaftActorContext.MockPayload()), 9);
277
278         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
279         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
280
281         ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
282         verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
283
284         Snapshot snapshot = snapshotArgumentCaptor.getValue();
285
286         assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
287         assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
288         assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
289         assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
290         assertArrayEquals("getState", bytes, snapshot.getState());
291         assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
292
293         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
294
295         verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
296     }
297
298     @Test
299     public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold(){
300         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
301
302         // when replicatedToAllIndex = -1
303         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
304                 new MockRaftActorContext.MockPayload()), -1);
305
306         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
307
308         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
309
310         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
311
312         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
313     }
314
315     @Test
316     public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
317         doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
318         doReturn(100).when(mockReplicatedLog).dataSize();
319
320         doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
321         doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
322
323         long replicatedToAllIndex = 1;
324         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
325         doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
326         doReturn(6L).when(replicatedLogEntry).getTerm();
327         doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
328
329         snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
330                 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
331
332         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, 2000000L);
333
334         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
335
336         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
337
338         verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
339     }
340
341     @Test
342     public void testPersistSendInstallSnapshot(){
343         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
344
345         // when replicatedToAllIndex = -1
346         boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
347                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
348
349         assertTrue(capture);
350
351         byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
352
353         snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
354
355         assertEquals(true, snapshotManager.isCapturing());
356
357         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
358
359         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
360
361         ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
362                 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
363
364         verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
365
366         SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
367
368         assertTrue(Arrays.equals(bytes, sendInstallSnapshot.getSnapshot().getState()));
369     }
370
371     @Test
372     public void testCallingPersistWithoutCaptureWillDoNothing(){
373         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
374
375         verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
376
377         verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
378
379         verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
380     }
381     @Test
382     public void testCallingPersistTwiceWillDoNoHarm(){
383         doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
384
385         // when replicatedToAllIndex = -1
386         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
387                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
388
389         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
390
391         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
392
393         verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
394
395         verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
396
397         verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
398     }
399
400     @Test
401     public void testCommit(){
402         doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
403
404         // when replicatedToAllIndex = -1
405         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
406                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
407
408         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
409
410         assertEquals(true, snapshotManager.isCapturing());
411
412         snapshotManager.commit(100L, mockRaftActorBehavior);
413
414         assertEquals(false, snapshotManager.isCapturing());
415
416         verify(mockReplicatedLog).snapshotCommit();
417
418         verify(mockDataPersistenceProvider).deleteMessages(50L);
419
420         ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor = ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
421
422         verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
423
424         assertEquals(90, criteriaCaptor.getValue().maxSequenceNr()); // sequenceNumber = 100
425                                                                      // config snapShotBatchCount = 10
426                                                                      // therefore maxSequenceNumber = 90
427     }
428
429     @Test
430     public void testCommitBeforePersist(){
431         // when replicatedToAllIndex = -1
432         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
433                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
434
435         snapshotManager.commit(100L, mockRaftActorBehavior);
436
437         verify(mockReplicatedLog, never()).snapshotCommit();
438
439         verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
440
441         verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
442
443     }
444
445     @Test
446     public void testCommitBeforeCapture(){
447         snapshotManager.commit(100L, mockRaftActorBehavior);
448
449         verify(mockReplicatedLog, never()).snapshotCommit();
450
451         verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
452
453         verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
454
455     }
456
457     @Test
458     public void testCallingCommitMultipleTimesCausesNoHarm(){
459         doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
460
461         // when replicatedToAllIndex = -1
462         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
463                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
464
465         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
466
467         snapshotManager.commit(100L, mockRaftActorBehavior);
468
469         snapshotManager.commit(100L, mockRaftActorBehavior);
470
471         verify(mockReplicatedLog, times(1)).snapshotCommit();
472
473         verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
474
475         verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
476     }
477
478     @Test
479     public void testRollback(){
480         // when replicatedToAllIndex = -1
481         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
482                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
483
484         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
485
486         snapshotManager.rollback();
487
488         verify(mockReplicatedLog).snapshotRollback();
489     }
490
491
492     @Test
493     public void testRollbackBeforePersist(){
494         // when replicatedToAllIndex = -1
495         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
496                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
497
498         snapshotManager.rollback();
499
500         verify(mockReplicatedLog, never()).snapshotRollback();
501     }
502
503     @Test
504     public void testRollbackBeforeCapture(){
505         snapshotManager.rollback();
506
507         verify(mockReplicatedLog, never()).snapshotRollback();
508     }
509
510     @Test
511     public void testCallingRollbackMultipleTimesCausesNoHarm(){
512         // when replicatedToAllIndex = -1
513         snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
514                 new MockRaftActorContext.MockPayload()), -1, "follower-1");
515
516         snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
517
518         snapshotManager.rollback();
519
520         snapshotManager.rollback();
521
522         verify(mockReplicatedLog, times(1)).snapshotRollback();
523     }
524
525     @Test
526     public void testTrimLogWhenTrimIndexLessThanLastApplied() {
527         doReturn(20L).when(mockRaftActorContext).getLastApplied();
528
529         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
530         doReturn(true).when(mockReplicatedLog).isPresent(10);
531         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
532         doReturn(5L).when(replicatedLogEntry).getTerm();
533
534         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
535         assertEquals("return index", 10L, retIndex);
536
537         verify(mockReplicatedLog).snapshotPreCommit(10, 5);
538         verify(mockReplicatedLog).snapshotCommit();
539
540         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
541     }
542
543     @Test
544     public void testTrimLogWhenLastAppliedNotSet() {
545         doReturn(-1L).when(mockRaftActorContext).getLastApplied();
546
547         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
548         doReturn(true).when(mockReplicatedLog).isPresent(10);
549         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
550         doReturn(5L).when(replicatedLogEntry).getTerm();
551
552         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
553         assertEquals("return index", -1L, retIndex);
554
555         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
556         verify(mockReplicatedLog, never()).snapshotCommit();
557
558         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
559     }
560
561     @Test
562     public void testTrimLogWhenLastAppliedZero() {
563         doReturn(0L).when(mockRaftActorContext).getLastApplied();
564
565         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
566         doReturn(true).when(mockReplicatedLog).isPresent(10);
567         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
568         doReturn(5L).when(replicatedLogEntry).getTerm();
569
570         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
571         assertEquals("return index", -1L, retIndex);
572
573         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
574         verify(mockReplicatedLog, never()).snapshotCommit();
575
576         verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
577     }
578
579     @Test
580     public void testTrimLogWhenTrimIndexNotPresent() {
581         doReturn(20L).when(mockRaftActorContext).getLastApplied();
582
583         doReturn(false).when(mockReplicatedLog).isPresent(10);
584
585         long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
586         assertEquals("return index", -1L, retIndex);
587
588         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
589         verify(mockReplicatedLog, never()).snapshotCommit();
590
591         // Trim index is greater than replicatedToAllIndex so should update it.
592         verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
593     }
594
595     @Test
596     public void testTrimLogAfterCapture(){
597         boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
598                 new MockRaftActorContext.MockPayload()), 9);
599
600         assertTrue(capture);
601
602         assertEquals(true, snapshotManager.isCapturing());
603
604         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
605         doReturn(20L).when(mockRaftActorContext).getLastApplied();
606         doReturn(true).when(mockReplicatedLog).isPresent(10);
607         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
608         doReturn(5L).when(replicatedLogEntry).getTerm();
609
610         snapshotManager.trimLog(10, mockRaftActorBehavior);
611
612         verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
613         verify(mockReplicatedLog, never()).snapshotCommit();
614
615     }
616
617     @Test
618     public void testTrimLogAfterCaptureToInstall(){
619         boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
620                 new MockRaftActorContext.MockPayload()), 9, "follower-1");
621
622         assertTrue(capture);
623
624         assertEquals(true, snapshotManager.isCapturing());
625
626         ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
627         doReturn(20L).when(mockRaftActorContext).getLastApplied();
628         doReturn(true).when(mockReplicatedLog).isPresent(10);
629         doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
630         doReturn(5L).when(replicatedLogEntry).getTerm();
631
632         snapshotManager.trimLog(10, mockRaftActorBehavior);
633
634         verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
635         verify(mockReplicatedLog, never()).snapshotCommit();
636
637     }
638
639     @Test
640     public void testLastAppliedTermInformationReader() {
641
642         LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
643
644         doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
645         doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
646
647         ReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(6L, 9L,
648                 new MockRaftActorContext.MockPayload());
649
650         // No followers and valid lastLogEntry
651         reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
652
653         assertEquals("getTerm", 6L, reader.getTerm());
654         assertEquals("getIndex", 9L, reader.getIndex());
655
656         // No followers and null lastLogEntry
657         reader.init(mockReplicatedLog, 1L, null, false);
658
659         assertEquals("getTerm", -1L, reader.getTerm());
660         assertEquals("getIndex", -1L, reader.getIndex());
661
662         // Followers and valid originalIndex entry
663         doReturn(new MockRaftActorContext.MockReplicatedLogEntry(5L, 8L,
664                 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
665         reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
666
667         assertEquals("getTerm", 5L, reader.getTerm());
668         assertEquals("getIndex", 8L, reader.getIndex());
669
670         // Followers and null originalIndex entry and valid snapshot index
671         reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
672
673         assertEquals("getTerm", 4L, reader.getTerm());
674         assertEquals("getIndex", 7L, reader.getIndex());
675
676         // Followers and null originalIndex entry and invalid snapshot index
677         doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
678         reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
679
680         assertEquals("getTerm", -1L, reader.getTerm());
681         assertEquals("getIndex", -1L, reader.getIndex());
682     }
683 }