2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.cluster.raft;
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.Matchers.anyObject;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.doThrow;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.reset;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
27 import akka.actor.ActorRef;
28 import akka.persistence.SnapshotSelectionCriteria;
29 import akka.testkit.TestActorRef;
30 import java.io.OutputStream;
31 import java.util.Arrays;
32 import java.util.Optional;
33 import java.util.function.Consumer;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.Mock;
39 import org.mockito.MockitoAnnotations;
40 import org.opendaylight.controller.cluster.DataPersistenceProvider;
41 import org.opendaylight.controller.cluster.io.FileBackedOutputStreamFactory;
42 import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
43 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
44 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
45 import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete;
46 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
47 import org.opendaylight.controller.cluster.raft.persisted.ByteState;
48 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
49 import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
50 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
51 import org.slf4j.LoggerFactory;
53 public class SnapshotManagerTest extends AbstractActorTest {
56 private RaftActorContext mockRaftActorContext;
59 private ConfigParams mockConfigParams;
62 private ReplicatedLog mockReplicatedLog;
65 private DataPersistenceProvider mockDataPersistenceProvider;
68 private RaftActorBehavior mockRaftActorBehavior;
71 private Consumer<Optional<OutputStream>> mockProcedure;
74 private ElectionTerm mockElectionTerm;
76 private SnapshotManager snapshotManager;
78 private TestActorFactory factory;
80 private TestActorRef<MessageCollectorActor> actorRef;
84 MockitoAnnotations.initMocks(this);
86 doReturn(false).when(mockRaftActorContext).hasFollowers();
87 doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
88 doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
89 doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
90 doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
91 doReturn("123").when(mockRaftActorContext).getId();
92 doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
93 doReturn(mockRaftActorBehavior).when(mockRaftActorContext).getCurrentBehavior();
94 doReturn("123").when(mockRaftActorBehavior).getLeaderId();
96 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
97 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
98 doReturn("member5").when(mockElectionTerm).getVotedFor();
100 doReturn(new FileBackedOutputStreamFactory(10000000, "target"))
101 .when(mockRaftActorContext).getFileBackedOutputStreamFactory();
103 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
104 factory = new TestActorFactory(getSystem());
106 actorRef = factory.createTestActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
107 doReturn(actorRef).when(mockRaftActorContext).getActor();
109 snapshotManager.setCreateSnapshotConsumer(mockProcedure);
113 public void tearDown() {
118 public void testConstruction() {
119 assertEquals(false, snapshotManager.isCapturing());
122 @SuppressWarnings({ "unchecked", "rawtypes" })
124 public void testCaptureToInstall() throws Exception {
126 // Force capturing toInstall = true
127 snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(0, 1,
128 new MockRaftActorContext.MockPayload()), 0, "follower-1");
130 assertEquals(true, snapshotManager.isCapturing());
132 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
133 verify(mockProcedure).accept(outputStream.capture());
134 assertEquals("isPresent", true, outputStream.getValue().isPresent());
136 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
138 // LastIndex and LastTerm are picked up from the lastLogEntry
139 assertEquals(0L, 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(0L, captureSnapshot.getLastAppliedIndex());
144 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
147 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
148 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
149 actorRef.underlyingActor().clear();
152 @SuppressWarnings({ "rawtypes", "unchecked" })
154 public void testCapture() throws Exception {
155 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
156 new MockRaftActorContext.MockPayload()), 9);
160 assertEquals(true, snapshotManager.isCapturing());
162 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
163 verify(mockProcedure).accept(outputStream.capture());
164 assertEquals("isPresent", false, outputStream.getValue().isPresent());
166 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
168 // LastIndex and LastTerm are picked up from the lastLogEntry
169 assertEquals(9L, captureSnapshot.getLastIndex());
170 assertEquals(1L, captureSnapshot.getLastTerm());
172 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
173 assertEquals(9L, captureSnapshot.getLastAppliedIndex());
174 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
177 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
178 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
180 actorRef.underlyingActor().clear();
184 @SuppressWarnings({ "unchecked", "rawtypes" })
186 public void testCaptureWithNullLastLogEntry() throws Exception {
187 boolean capture = snapshotManager.capture(null, 1);
191 assertEquals(true, snapshotManager.isCapturing());
193 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
194 verify(mockProcedure).accept(outputStream.capture());
195 assertEquals("isPresent", false, outputStream.getValue().isPresent());
197 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
199 // LastIndex and LastTerm are picked up from the lastLogEntry
200 assertEquals(-1L, captureSnapshot.getLastIndex());
201 assertEquals(-1L, captureSnapshot.getLastTerm());
203 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
204 assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
205 assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
208 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
209 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
210 actorRef.underlyingActor().clear();
215 public void testCaptureWithCreateProcedureError() throws Exception {
216 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(anyObject());
218 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
219 new MockRaftActorContext.MockPayload()), 9);
221 assertFalse(capture);
223 assertEquals(false, snapshotManager.isCapturing());
225 verify(mockProcedure).accept(anyObject());
228 @SuppressWarnings("unchecked")
230 public void testIllegalCapture() throws Exception {
231 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
232 new MockRaftActorContext.MockPayload()), 9);
236 verify(mockProcedure).accept(anyObject());
238 reset(mockProcedure);
240 // This will not cause snapshot capture to start again
241 capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
242 new MockRaftActorContext.MockPayload()), 9);
244 assertFalse(capture);
246 verify(mockProcedure, never()).accept(anyObject());
250 public void testPersistWhenReplicatedToAllIndexMinusOne() throws Exception {
251 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
252 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
254 doReturn(true).when(mockRaftActorContext).hasFollowers();
256 doReturn(8L).when(mockRaftActorContext).getLastApplied();
258 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 3L, new MockRaftActorContext.MockPayload());
260 ReplicatedLogEntry lastAppliedEntry = new SimpleReplicatedLogEntry(
261 8L, 2L, new MockRaftActorContext.MockPayload());
263 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
264 doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
266 // when replicatedToAllIndex = -1
267 snapshotManager.capture(lastLogEntry, -1);
269 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
270 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
272 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
273 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
275 Snapshot snapshot = snapshotArgumentCaptor.getValue();
277 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
278 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
279 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
280 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
281 assertEquals("getState", snapshotState, snapshot.getState());
282 assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
283 assertEquals("electionTerm", mockElectionTerm.getCurrentTerm(), snapshot.getElectionTerm());
284 assertEquals("electionVotedFor", mockElectionTerm.getVotedFor(), snapshot.getElectionVotedFor());
286 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
290 public void testPersistWhenReplicatedToAllIndexNotMinus() throws Exception {
291 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
292 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
293 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
294 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
295 doReturn(6L).when(replicatedLogEntry).getTerm();
296 doReturn(9L).when(replicatedLogEntry).getIndex();
298 // when replicatedToAllIndex != -1
299 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), 9);
301 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
302 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
304 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
305 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
307 Snapshot snapshot = snapshotArgumentCaptor.getValue();
309 assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
310 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
311 assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
312 assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
313 assertEquals("getState", snapshotState, snapshot.getState());
314 assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
316 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
318 verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
322 public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold() {
323 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
325 // when replicatedToAllIndex = -1
326 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
328 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
330 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
332 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
334 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
338 public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
339 doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
340 doReturn(100).when(mockReplicatedLog).dataSize();
342 doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
343 doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
345 long replicatedToAllIndex = 1;
346 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
347 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
348 doReturn(6L).when(replicatedLogEntry).getTerm();
349 doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
351 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6,
352 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
354 snapshotManager.persist(ByteState.empty(), Optional.empty(), 2000000L);
356 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
358 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
360 verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
363 @SuppressWarnings({ "rawtypes", "unchecked" })
365 public void testPersistSendInstallSnapshot() throws Exception {
366 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
367 doNothing().when(mockProcedure).accept(anyObject());
369 // when replicatedToAllIndex = -1
370 boolean capture = snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(9, 6,
371 new MockRaftActorContext.MockPayload()), -1, "follower-1");
375 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
377 ArgumentCaptor<Optional> installSnapshotStreamCapture = ArgumentCaptor.forClass(Optional.class);
378 verify(mockProcedure).accept(installSnapshotStreamCapture.capture());
380 Optional<OutputStream> installSnapshotStream = installSnapshotStreamCapture.getValue();
381 assertEquals("isPresent", true, installSnapshotStream.isPresent());
383 installSnapshotStream.get().write(snapshotState.getBytes());
385 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
387 assertEquals(true, snapshotManager.isCapturing());
389 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
391 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
393 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
394 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
396 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
398 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
400 assertEquals("state", snapshotState, sendInstallSnapshot.getSnapshot().getState());
401 assertArrayEquals("state", snapshotState.getBytes(), sendInstallSnapshot.getSnapshotBytes().read());
405 public void testCallingPersistWithoutCaptureWillDoNothing() {
406 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
408 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
410 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
412 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
416 public void testCallingPersistTwiceWillDoNoHarm() {
417 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
419 // when replicatedToAllIndex = -1
420 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
422 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
424 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
426 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
428 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
432 public void testCommit() {
433 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
435 // when replicatedToAllIndex = -1
436 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
438 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
440 assertEquals(true, snapshotManager.isCapturing());
442 snapshotManager.commit(100L, 1234L);
444 assertEquals(false, snapshotManager.isCapturing());
446 verify(mockReplicatedLog).snapshotCommit();
448 verify(mockDataPersistenceProvider).deleteMessages(50L);
450 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor =
451 ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
453 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
455 assertEquals(100L, criteriaCaptor.getValue().maxSequenceNr());
456 assertEquals(1233L, criteriaCaptor.getValue().maxTimestamp());
458 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
462 public void testCommitBeforePersist() {
463 // when replicatedToAllIndex = -1
464 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
466 snapshotManager.commit(100L, 0);
468 verify(mockReplicatedLog, never()).snapshotCommit();
470 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
472 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
477 public void testCommitBeforeCapture() {
478 snapshotManager.commit(100L, 0);
480 verify(mockReplicatedLog, never()).snapshotCommit();
482 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
484 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
489 public void testCallingCommitMultipleTimesCausesNoHarm() {
490 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
492 // when replicatedToAllIndex = -1
493 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
495 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
497 snapshotManager.commit(100L, 0);
499 snapshotManager.commit(100L, 0);
501 verify(mockReplicatedLog, times(1)).snapshotCommit();
503 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
505 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
509 public void testRollback() {
510 // when replicatedToAllIndex = -1
511 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
513 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
515 snapshotManager.rollback();
517 verify(mockReplicatedLog).snapshotRollback();
519 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
524 public void testRollbackBeforePersist() {
525 // when replicatedToAllIndex = -1
526 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
528 snapshotManager.rollback();
530 verify(mockReplicatedLog, never()).snapshotRollback();
534 public void testRollbackBeforeCapture() {
535 snapshotManager.rollback();
537 verify(mockReplicatedLog, never()).snapshotRollback();
541 public void testCallingRollbackMultipleTimesCausesNoHarm() {
542 // when replicatedToAllIndex = -1
543 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
545 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
547 snapshotManager.rollback();
549 snapshotManager.rollback();
551 verify(mockReplicatedLog, times(1)).snapshotRollback();
555 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
556 doReturn(20L).when(mockRaftActorContext).getLastApplied();
558 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
559 doReturn(true).when(mockReplicatedLog).isPresent(10);
560 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
561 doReturn(5L).when(replicatedLogEntry).getTerm();
563 long retIndex = snapshotManager.trimLog(10);
564 assertEquals("return index", 10L, retIndex);
566 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
567 verify(mockReplicatedLog).snapshotCommit();
569 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
573 public void testTrimLogWhenLastAppliedNotSet() {
574 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
576 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
577 doReturn(true).when(mockReplicatedLog).isPresent(10);
578 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
579 doReturn(5L).when(replicatedLogEntry).getTerm();
581 long retIndex = snapshotManager.trimLog(10);
582 assertEquals("return index", -1L, retIndex);
584 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
585 verify(mockReplicatedLog, never()).snapshotCommit();
587 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
591 public void testTrimLogWhenLastAppliedZero() {
592 doReturn(0L).when(mockRaftActorContext).getLastApplied();
594 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
595 doReturn(true).when(mockReplicatedLog).isPresent(10);
596 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
597 doReturn(5L).when(replicatedLogEntry).getTerm();
599 long retIndex = snapshotManager.trimLog(10);
600 assertEquals("return index", -1L, retIndex);
602 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
603 verify(mockReplicatedLog, never()).snapshotCommit();
605 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
609 public void testTrimLogWhenTrimIndexNotPresent() {
610 doReturn(20L).when(mockRaftActorContext).getLastApplied();
612 doReturn(false).when(mockReplicatedLog).isPresent(10);
614 long retIndex = snapshotManager.trimLog(10);
615 assertEquals("return index", -1L, retIndex);
617 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
618 verify(mockReplicatedLog, never()).snapshotCommit();
620 // Trim index is greater than replicatedToAllIndex so should update it.
621 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
625 public void testTrimLogAfterCapture() {
626 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
627 new MockRaftActorContext.MockPayload()), 9);
631 assertEquals(true, snapshotManager.isCapturing());
633 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
634 doReturn(20L).when(mockRaftActorContext).getLastApplied();
635 doReturn(true).when(mockReplicatedLog).isPresent(10);
636 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
637 doReturn(5L).when(replicatedLogEntry).getTerm();
639 snapshotManager.trimLog(10);
641 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
642 verify(mockReplicatedLog, never()).snapshotCommit();
647 public void testTrimLogAfterCaptureToInstall() {
648 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
649 new MockRaftActorContext.MockPayload()), 9);
653 assertEquals(true, snapshotManager.isCapturing());
655 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
656 doReturn(20L).when(mockRaftActorContext).getLastApplied();
657 doReturn(true).when(mockReplicatedLog).isPresent(10);
658 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
659 doReturn(5L).when(replicatedLogEntry).getTerm();
661 snapshotManager.trimLog(10);
663 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
664 verify(mockReplicatedLog, never()).snapshotCommit();
669 public void testLastAppliedTermInformationReader() {
671 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
673 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
674 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
676 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
677 new MockRaftActorContext.MockPayload());
679 // No followers and valid lastLogEntry
680 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
682 assertEquals("getTerm", 6L, reader.getTerm());
683 assertEquals("getIndex", 9L, reader.getIndex());
685 // No followers and null lastLogEntry
686 reader.init(mockReplicatedLog, 1L, null, false);
688 assertEquals("getTerm", -1L, reader.getTerm());
689 assertEquals("getIndex", -1L, reader.getIndex());
691 // Followers and valid originalIndex entry
692 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
693 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
694 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
696 assertEquals("getTerm", 5L, reader.getTerm());
697 assertEquals("getIndex", 8L, reader.getIndex());
699 // Followers and null originalIndex entry and valid snapshot index
700 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
702 assertEquals("getTerm", 4L, reader.getTerm());
703 assertEquals("getIndex", 7L, reader.getIndex());
705 // Followers and null originalIndex entry and invalid snapshot index
706 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
707 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
709 assertEquals("getTerm", -1L, reader.getTerm());
710 assertEquals("getIndex", -1L, reader.getIndex());