1 package org.opendaylight.controller.cluster.raft;
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;
37 public class SnapshotManagerTest extends AbstractActorTest {
40 private RaftActorContext mockRaftActorContext;
43 private ConfigParams mockConfigParams;
46 private ReplicatedLog mockReplicatedLog;
49 private DataPersistenceProvider mockDataPersistenceProvider;
52 private RaftActorBehavior mockRaftActorBehavior;
55 private Procedure<Void> mockProcedure;
57 private SnapshotManager snapshotManager;
59 private TestActorFactory factory;
61 private TestActorRef<MessageCollectorActor> actorRef;
65 MockitoAnnotations.initMocks(this);
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();
75 ElectionTerm mockElectionTerm = mock(ElectionTerm.class);
76 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
77 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
79 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
80 factory = new TestActorFactory(getSystem());
82 actorRef = factory.createTestActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
83 doReturn(actorRef).when(mockRaftActorContext).getActor();
85 snapshotManager.setCreateSnapshotCallable(mockProcedure);
89 public void tearDown(){
94 public void testConstruction(){
95 assertEquals(false, snapshotManager.isCapturing());
99 public void testCaptureToInstall() throws Exception {
101 // Force capturing toInstall = true
102 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1, 0,
103 new MockRaftActorContext.MockPayload()), 0, "follower-1");
105 assertEquals(true, snapshotManager.isCapturing());
107 verify(mockProcedure).apply(null);
109 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
111 // LastIndex and LastTerm are picked up from the lastLogEntry
112 assertEquals(0L, captureSnapshot.getLastIndex());
113 assertEquals(1L, captureSnapshot.getLastTerm());
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());
120 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
121 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
122 actorRef.underlyingActor().clear();
126 public void testCapture() throws Exception {
127 boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
128 new MockRaftActorContext.MockPayload()), 9);
132 assertEquals(true, snapshotManager.isCapturing());
134 verify(mockProcedure).apply(null);
136 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
138 // LastIndex and LastTerm are picked up from the lastLogEntry
139 assertEquals(9L, captureSnapshot.getLastIndex());
140 assertEquals(1L, captureSnapshot.getLastTerm());
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());
147 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
148 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
150 actorRef.underlyingActor().clear();
155 public void testCaptureWithCreateProcedureError () throws Exception {
156 doThrow(new Exception("mock")).when(mockProcedure).apply(null);
158 boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
159 new MockRaftActorContext.MockPayload()), 9);
161 assertFalse(capture);
163 assertEquals(false, snapshotManager.isCapturing());
165 verify(mockProcedure).apply(null);
169 public void testIllegalCapture() throws Exception {
170 boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
171 new MockRaftActorContext.MockPayload()), 9);
175 verify(mockProcedure).apply(null);
177 reset(mockProcedure);
179 // This will not cause snapshot capture to start again
180 capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
181 new MockRaftActorContext.MockPayload()), 9);
183 assertFalse(capture);
185 verify(mockProcedure, never()).apply(null);
189 public void testPersistWhenReplicatedToAllIndexMinusOne(){
190 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
191 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
193 doReturn(ImmutableMap.builder().put("follower-1", "").build()).when(mockRaftActorContext).getPeerAddresses();
195 doReturn(8L).when(mockRaftActorContext).getLastApplied();
197 MockRaftActorContext.MockReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(
198 3L, 9L, new MockRaftActorContext.MockPayload());
200 MockRaftActorContext.MockReplicatedLogEntry lastAppliedEntry = new MockRaftActorContext.MockReplicatedLogEntry(
201 2L, 8L, new MockRaftActorContext.MockPayload());
203 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
204 doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
206 // when replicatedToAllIndex = -1
207 snapshotManager.capture(lastLogEntry, -1);
209 byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
210 snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
212 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
213 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
215 Snapshot snapshot = snapshotArgumentCaptor.getValue();
217 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
218 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
219 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
220 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
221 assertArrayEquals("getState", bytes, snapshot.getState());
222 assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
224 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
228 public void testPersistWhenReplicatedToAllIndexNotMinus(){
229 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
230 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
231 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
232 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
233 doReturn(6L).when(replicatedLogEntry).getTerm();
234 doReturn(9L).when(replicatedLogEntry).getIndex();
236 // when replicatedToAllIndex != -1
237 snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
238 new MockRaftActorContext.MockPayload()), 9);
240 byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
241 snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
243 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
244 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
246 Snapshot snapshot = snapshotArgumentCaptor.getValue();
248 assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
249 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
250 assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
251 assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
252 assertArrayEquals("getState", bytes, snapshot.getState());
253 assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
255 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
257 verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
262 public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold(){
263 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
265 // when replicatedToAllIndex = -1
266 snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(6,9,
267 new MockRaftActorContext.MockPayload()), -1);
269 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
271 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
273 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
277 public void testPersistSendInstallSnapshot(){
278 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
280 // when replicatedToAllIndex = -1
281 boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
282 new MockRaftActorContext.MockPayload()), -1, "follower-1");
286 byte[] bytes = new byte[] {1,2,3,4,5,6,7,8,9,10};
288 snapshotManager.persist(bytes, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
290 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
292 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
294 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
295 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
297 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
299 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
301 assertTrue(Arrays.equals(bytes, sendInstallSnapshot.getSnapshot().toByteArray()));
305 public void testCallingPersistWithoutCaptureWillDoNothing(){
306 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
308 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
310 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
312 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
315 public void testCallingPersistTwiceWillDoNoHarm(){
316 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
318 // when replicatedToAllIndex = -1
319 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
320 new MockRaftActorContext.MockPayload()), -1, "follower-1");
322 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
324 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
326 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
328 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
330 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
334 public void testCommit(){
335 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
337 // when replicatedToAllIndex = -1
338 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
339 new MockRaftActorContext.MockPayload()), -1, "follower-1");
341 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
343 snapshotManager.commit(100L);
345 verify(mockReplicatedLog).snapshotCommit();
347 verify(mockDataPersistenceProvider).deleteMessages(50L);
349 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor = ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
351 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
353 assertEquals(90, criteriaCaptor.getValue().maxSequenceNr()); // sequenceNumber = 100
354 // config snapShotBatchCount = 10
355 // therefore maxSequenceNumber = 90
359 public void testCommitBeforePersist(){
360 // when replicatedToAllIndex = -1
361 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
362 new MockRaftActorContext.MockPayload()), -1, "follower-1");
364 snapshotManager.commit(100L);
366 verify(mockReplicatedLog, never()).snapshotCommit();
368 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
370 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
375 public void testCommitBeforeCapture(){
376 snapshotManager.commit(100L);
378 verify(mockReplicatedLog, never()).snapshotCommit();
380 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
382 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
387 public void testCallingCommitMultipleTimesCausesNoHarm(){
388 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
390 // when replicatedToAllIndex = -1
391 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
392 new MockRaftActorContext.MockPayload()), -1, "follower-1");
394 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
396 snapshotManager.commit(100L);
398 snapshotManager.commit(100L);
400 verify(mockReplicatedLog, times(1)).snapshotCommit();
402 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
404 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
408 public void testRollback(){
409 // when replicatedToAllIndex = -1
410 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
411 new MockRaftActorContext.MockPayload()), -1, "follower-1");
413 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
415 snapshotManager.rollback();
417 verify(mockReplicatedLog).snapshotRollback();
422 public void testRollbackBeforePersist(){
423 // when replicatedToAllIndex = -1
424 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
425 new MockRaftActorContext.MockPayload()), -1, "follower-1");
427 snapshotManager.rollback();
429 verify(mockReplicatedLog, never()).snapshotRollback();
433 public void testRollbackBeforeCapture(){
434 snapshotManager.rollback();
436 verify(mockReplicatedLog, never()).snapshotRollback();
440 public void testCallingRollbackMultipleTimesCausesNoHarm(){
441 // when replicatedToAllIndex = -1
442 snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(6, 9,
443 new MockRaftActorContext.MockPayload()), -1, "follower-1");
445 snapshotManager.persist(new byte[]{}, mockRaftActorBehavior, Runtime.getRuntime().totalMemory());
447 snapshotManager.rollback();
449 snapshotManager.rollback();
451 verify(mockReplicatedLog, times(1)).snapshotRollback();
455 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
456 doReturn(20L).when(mockRaftActorContext).getLastApplied();
458 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
459 doReturn(true).when(mockReplicatedLog).isPresent(10);
460 doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
461 doReturn(5L).when(replicatedLogEntry).getTerm();
463 long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
464 assertEquals("return index", 10L, retIndex);
466 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
467 verify(mockReplicatedLog).snapshotCommit();
469 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
473 public void testTrimLogWhenLastAppliedNotSet() {
474 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
476 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
477 doReturn(true).when(mockReplicatedLog).isPresent(10);
478 doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
479 doReturn(5L).when(replicatedLogEntry).getTerm();
481 long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
482 assertEquals("return index", -1L, retIndex);
484 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
485 verify(mockReplicatedLog, never()).snapshotCommit();
487 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
491 public void testTrimLogWhenLastAppliedZero() {
492 doReturn(0L).when(mockRaftActorContext).getLastApplied();
494 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
495 doReturn(true).when(mockReplicatedLog).isPresent(10);
496 doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
497 doReturn(5L).when(replicatedLogEntry).getTerm();
499 long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
500 assertEquals("return index", -1L, retIndex);
502 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
503 verify(mockReplicatedLog, never()).snapshotCommit();
505 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
509 public void testTrimLogWhenTrimIndexNotPresent() {
510 doReturn(20L).when(mockRaftActorContext).getLastApplied();
512 doReturn(false).when(mockReplicatedLog).isPresent(10);
514 long retIndex = snapshotManager.trimLog(10, mockRaftActorBehavior);
515 assertEquals("return index", -1L, retIndex);
517 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
518 verify(mockReplicatedLog, never()).snapshotCommit();
520 // Trim index is greater than replicatedToAllIndex so should update it.
521 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
525 public void testTrimLogAfterCapture(){
526 boolean capture = snapshotManager.capture(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
527 new MockRaftActorContext.MockPayload()), 9);
531 assertEquals(true, snapshotManager.isCapturing());
533 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
534 doReturn(20L).when(mockRaftActorContext).getLastApplied();
535 doReturn(true).when(mockReplicatedLog).isPresent(10);
536 doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
537 doReturn(5L).when(replicatedLogEntry).getTerm();
539 snapshotManager.trimLog(10, mockRaftActorBehavior);
541 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
542 verify(mockReplicatedLog, never()).snapshotCommit();
547 public void testTrimLogAfterCaptureToInstall(){
548 boolean capture = snapshotManager.captureToInstall(new MockRaftActorContext.MockReplicatedLogEntry(1,9,
549 new MockRaftActorContext.MockPayload()), 9, "follower-1");
553 assertEquals(true, snapshotManager.isCapturing());
555 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
556 doReturn(20L).when(mockRaftActorContext).getLastApplied();
557 doReturn(true).when(mockReplicatedLog).isPresent(10);
558 doReturn(replicatedLogEntry).when((mockReplicatedLog)).get(10);
559 doReturn(5L).when(replicatedLogEntry).getTerm();
561 snapshotManager.trimLog(10, mockRaftActorBehavior);
563 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
564 verify(mockReplicatedLog, never()).snapshotCommit();
569 public void testLastAppliedTermInformationReader() {
571 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
573 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
574 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
576 ReplicatedLogEntry lastLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(6L, 9L,
577 new MockRaftActorContext.MockPayload());
579 // No followers and valid lastLogEntry
580 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
582 assertEquals("getTerm", 6L, reader.getTerm());
583 assertEquals("getIndex", 9L, reader.getIndex());
585 // No followers and null lastLogEntry
586 reader.init(mockReplicatedLog, 1L, null, false);
588 assertEquals("getTerm", -1L, reader.getTerm());
589 assertEquals("getIndex", -1L, reader.getIndex());
591 // Followers and valid originalIndex entry
592 doReturn(new MockRaftActorContext.MockReplicatedLogEntry(5L, 8L,
593 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
594 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
596 assertEquals("getTerm", 5L, reader.getTerm());
597 assertEquals("getIndex", 8L, reader.getIndex());
599 // Followers and null originalIndex entry and valid snapshot index
600 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
602 assertEquals("getTerm", 4L, reader.getTerm());
603 assertEquals("getIndex", 7L, reader.getIndex());
605 // Followers and null originalIndex entry and invalid snapshot index
606 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
607 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
609 assertEquals("getTerm", -1L, reader.getTerm());
610 assertEquals("getIndex", -1L, reader.getIndex());