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.ArgumentMatchers.any;
16 import static org.mockito.ArgumentMatchers.anyLong;
17 import static org.mockito.Mockito.doNothing;
18 import static org.mockito.Mockito.doReturn;
19 import static org.mockito.Mockito.doThrow;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.never;
22 import static org.mockito.Mockito.reset;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
26 import akka.actor.ActorRef;
27 import akka.persistence.SnapshotSelectionCriteria;
28 import java.io.OutputStream;
29 import java.util.Arrays;
30 import java.util.Optional;
31 import java.util.function.Consumer;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.mockito.ArgumentCaptor;
37 import org.mockito.Mock;
38 import org.mockito.junit.MockitoJUnitRunner;
39 import org.opendaylight.controller.cluster.DataPersistenceProvider;
40 import org.opendaylight.controller.cluster.io.FileBackedOutputStreamFactory;
41 import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
42 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
43 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
44 import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete;
45 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
46 import org.opendaylight.controller.cluster.raft.persisted.ByteState;
47 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
48 import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
49 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
50 import org.slf4j.LoggerFactory;
52 @RunWith(MockitoJUnitRunner.StrictStubs.class)
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 ActorRef actorRef;
84 doReturn(false).when(mockRaftActorContext).hasFollowers();
85 doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
86 doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
87 doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
88 doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
89 doReturn("123").when(mockRaftActorContext).getId();
90 doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
91 doReturn(mockRaftActorBehavior).when(mockRaftActorContext).getCurrentBehavior();
92 doReturn("123").when(mockRaftActorBehavior).getLeaderId();
94 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
95 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
96 doReturn("member5").when(mockElectionTerm).getVotedFor();
98 doReturn(new FileBackedOutputStreamFactory(10000000, "target"))
99 .when(mockRaftActorContext).getFileBackedOutputStreamFactory();
101 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
102 factory = new TestActorFactory(getSystem());
104 actorRef = factory.createActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
105 doReturn(actorRef).when(mockRaftActorContext).getActor();
107 snapshotManager.setCreateSnapshotConsumer(mockProcedure);
111 public void tearDown() {
116 public void testConstruction() {
117 assertEquals(false, snapshotManager.isCapturing());
120 @SuppressWarnings({ "unchecked", "rawtypes" })
122 public void testCaptureToInstall() {
124 // Force capturing toInstall = true
125 snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(0, 1,
126 new MockRaftActorContext.MockPayload()), 0, "follower-1");
128 assertEquals(true, snapshotManager.isCapturing());
130 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
131 verify(mockProcedure).accept(outputStream.capture());
132 assertEquals("isPresent", true, outputStream.getValue().isPresent());
134 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
136 // LastIndex and LastTerm are picked up from the lastLogEntry
137 assertEquals(0L, captureSnapshot.getLastIndex());
138 assertEquals(1L, captureSnapshot.getLastTerm());
140 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
141 assertEquals(0L, captureSnapshot.getLastAppliedIndex());
142 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
145 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
146 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
147 MessageCollectorActor.clearMessages(actorRef);
150 @SuppressWarnings({ "rawtypes", "unchecked" })
152 public void testCapture() {
153 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
154 new MockRaftActorContext.MockPayload()), 9);
158 assertEquals(true, snapshotManager.isCapturing());
160 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
161 verify(mockProcedure).accept(outputStream.capture());
162 assertEquals("isPresent", false, outputStream.getValue().isPresent());
164 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
166 // LastIndex and LastTerm are picked up from the lastLogEntry
167 assertEquals(9L, captureSnapshot.getLastIndex());
168 assertEquals(1L, captureSnapshot.getLastTerm());
170 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
171 assertEquals(9L, captureSnapshot.getLastAppliedIndex());
172 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
175 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
176 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
178 MessageCollectorActor.clearMessages(actorRef);
181 @SuppressWarnings({ "unchecked", "rawtypes" })
183 public void testCaptureWithNullLastLogEntry() {
184 boolean capture = snapshotManager.capture(null, 1);
188 assertEquals(true, snapshotManager.isCapturing());
190 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
191 verify(mockProcedure).accept(outputStream.capture());
192 assertEquals("isPresent", false, outputStream.getValue().isPresent());
194 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
196 // LastIndex and LastTerm are picked up from the lastLogEntry
197 assertEquals(0, captureSnapshot.getLastIndex());
198 assertEquals(0, captureSnapshot.getLastTerm());
200 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
201 assertEquals(0, captureSnapshot.getLastAppliedIndex());
202 assertEquals(0, captureSnapshot.getLastAppliedTerm());
205 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
206 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
207 MessageCollectorActor.clearMessages(actorRef);
211 public void testCaptureWithCreateProcedureError() {
212 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(any());
214 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
215 new MockRaftActorContext.MockPayload()), 9);
217 assertFalse(capture);
219 assertEquals(false, snapshotManager.isCapturing());
221 verify(mockProcedure).accept(any());
224 @SuppressWarnings("unchecked")
226 public void testIllegalCapture() {
227 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
228 new MockRaftActorContext.MockPayload()), 9);
232 verify(mockProcedure).accept(any());
234 reset(mockProcedure);
236 // This will not cause snapshot capture to start again
237 capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
238 new MockRaftActorContext.MockPayload()), 9);
240 assertFalse(capture);
242 verify(mockProcedure, never()).accept(any());
246 public void testPersistWhenReplicatedToAllIndexMinusOne() {
247 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
248 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
250 doReturn(true).when(mockRaftActorContext).hasFollowers();
252 doReturn(8L).when(mockRaftActorContext).getLastApplied();
254 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 3L, new MockRaftActorContext.MockPayload());
256 ReplicatedLogEntry lastAppliedEntry = new SimpleReplicatedLogEntry(
257 8L, 2L, new MockRaftActorContext.MockPayload());
259 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
260 doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
262 // when replicatedToAllIndex = -1
263 snapshotManager.capture(lastLogEntry, -1);
265 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
266 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
268 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
269 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
271 Snapshot snapshot = snapshotArgumentCaptor.getValue();
273 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
274 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
275 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
276 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
277 assertEquals("getState", snapshotState, snapshot.getState());
278 assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
279 assertEquals("electionTerm", mockElectionTerm.getCurrentTerm(), snapshot.getElectionTerm());
280 assertEquals("electionVotedFor", mockElectionTerm.getVotedFor(), snapshot.getElectionVotedFor());
282 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
286 public void testPersistWhenReplicatedToAllIndexNotMinus() {
287 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
288 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
289 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
290 doReturn(null).when(mockReplicatedLog).get(0);
291 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
292 doReturn(6L).when(replicatedLogEntry).getTerm();
293 doReturn(9L).when(replicatedLogEntry).getIndex();
295 // when replicatedToAllIndex != -1
296 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), 9);
298 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
299 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
301 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
302 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
304 Snapshot snapshot = snapshotArgumentCaptor.getValue();
306 assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
307 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
308 assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
309 assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
310 assertEquals("getState", snapshotState, snapshot.getState());
311 assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
313 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
315 verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
319 public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold() {
320 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
322 // when replicatedToAllIndex = -1
323 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
325 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
327 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
329 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
331 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
335 public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
336 doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
337 doReturn(100).when(mockReplicatedLog).dataSize();
339 doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
340 doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
342 long replicatedToAllIndex = 1;
343 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
344 doReturn(null).when(mockReplicatedLog).get(0);
345 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
346 doReturn(6L).when(replicatedLogEntry).getTerm();
347 doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
349 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6,
350 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
352 snapshotManager.persist(ByteState.empty(), Optional.empty(), 2000000L);
354 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
356 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
358 verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
361 @SuppressWarnings({ "rawtypes", "unchecked" })
363 public void testPersistSendInstallSnapshot() throws Exception {
364 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
365 doNothing().when(mockProcedure).accept(any());
367 // when replicatedToAllIndex = -1
368 boolean capture = snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(9, 6,
369 new MockRaftActorContext.MockPayload()), -1, "follower-1");
373 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
375 ArgumentCaptor<Optional> installSnapshotStreamCapture = ArgumentCaptor.forClass(Optional.class);
376 verify(mockProcedure).accept(installSnapshotStreamCapture.capture());
378 Optional<OutputStream> installSnapshotStream = installSnapshotStreamCapture.getValue();
379 assertEquals("isPresent", true, installSnapshotStream.isPresent());
381 installSnapshotStream.get().write(snapshotState.getBytes());
383 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
385 assertEquals(true, snapshotManager.isCapturing());
387 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
389 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
391 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
392 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
394 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
396 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
398 assertEquals("state", snapshotState, sendInstallSnapshot.getSnapshot().getState());
399 assertArrayEquals("state", snapshotState.getBytes(), sendInstallSnapshot.getSnapshotBytes().read());
403 public void testCallingPersistWithoutCaptureWillDoNothing() {
404 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
406 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
408 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
410 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
414 public void testCallingPersistTwiceWillDoNoHarm() {
415 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
417 // when replicatedToAllIndex = -1
418 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
420 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
422 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
424 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
426 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
430 public void testCommit() {
431 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
433 // when replicatedToAllIndex = -1
434 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
436 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
438 assertEquals(true, snapshotManager.isCapturing());
440 snapshotManager.commit(100L, 1234L);
442 assertEquals(false, snapshotManager.isCapturing());
444 verify(mockReplicatedLog).snapshotCommit();
446 verify(mockDataPersistenceProvider).deleteMessages(50L);
448 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor =
449 ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
451 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
453 assertEquals(Long.MAX_VALUE, criteriaCaptor.getValue().maxSequenceNr());
454 assertEquals(1233L, criteriaCaptor.getValue().maxTimestamp());
456 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
460 public void testCommitBeforePersist() {
461 // when replicatedToAllIndex = -1
462 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
464 snapshotManager.commit(100L, 0);
466 verify(mockReplicatedLog, never()).snapshotCommit();
468 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
470 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
475 public void testCommitBeforeCapture() {
476 snapshotManager.commit(100L, 0);
478 verify(mockReplicatedLog, never()).snapshotCommit();
480 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
482 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
487 public void testCallingCommitMultipleTimesCausesNoHarm() {
488 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
490 // when replicatedToAllIndex = -1
491 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
493 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
495 snapshotManager.commit(100L, 0);
497 snapshotManager.commit(100L, 0);
499 verify(mockReplicatedLog, times(1)).snapshotCommit();
501 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
503 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
507 public void testRollback() {
508 // when replicatedToAllIndex = -1
509 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
511 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
513 snapshotManager.rollback();
515 verify(mockReplicatedLog).snapshotRollback();
517 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
522 public void testRollbackBeforePersist() {
523 // when replicatedToAllIndex = -1
524 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
526 snapshotManager.rollback();
528 verify(mockReplicatedLog, never()).snapshotRollback();
532 public void testRollbackBeforeCapture() {
533 snapshotManager.rollback();
535 verify(mockReplicatedLog, never()).snapshotRollback();
539 public void testCallingRollbackMultipleTimesCausesNoHarm() {
540 // when replicatedToAllIndex = -1
541 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
543 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
545 snapshotManager.rollback();
547 snapshotManager.rollback();
549 verify(mockReplicatedLog, times(1)).snapshotRollback();
553 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
554 doReturn(20L).when(mockRaftActorContext).getLastApplied();
556 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
557 doReturn(true).when(mockReplicatedLog).isPresent(10);
558 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
559 doReturn(5L).when(replicatedLogEntry).getTerm();
561 long retIndex = snapshotManager.trimLog(10);
562 assertEquals("return index", 10L, retIndex);
564 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
565 verify(mockReplicatedLog).snapshotCommit(false);
567 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
571 public void testTrimLogWhenLastAppliedNotSet() {
572 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
574 long retIndex = snapshotManager.trimLog(10);
575 assertEquals("return index", -1L, retIndex);
577 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
578 verify(mockReplicatedLog, never()).snapshotCommit(false);
580 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
584 public void testTrimLogWhenLastAppliedZero() {
585 doReturn(0L).when(mockRaftActorContext).getLastApplied();
587 long retIndex = snapshotManager.trimLog(10);
588 assertEquals("return index", -1L, retIndex);
590 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
591 verify(mockReplicatedLog, never()).snapshotCommit(false);
593 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
597 public void testTrimLogWhenTrimIndexNotPresent() {
598 doReturn(20L).when(mockRaftActorContext).getLastApplied();
600 doReturn(false).when(mockReplicatedLog).isPresent(10);
602 long retIndex = snapshotManager.trimLog(10);
603 assertEquals("return index", -1L, retIndex);
605 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
606 verify(mockReplicatedLog, never()).snapshotCommit(false);
608 // Trim index is greater than replicatedToAllIndex so should update it.
609 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
613 public void testTrimLogAfterCapture() {
614 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
615 new MockRaftActorContext.MockPayload()), 9);
619 assertEquals(true, snapshotManager.isCapturing());
621 snapshotManager.trimLog(10);
623 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
624 verify(mockReplicatedLog, never()).snapshotCommit(false);
628 public void testTrimLogAfterCaptureToInstall() {
629 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
630 new MockRaftActorContext.MockPayload()), 9);
634 assertEquals(true, snapshotManager.isCapturing());
636 snapshotManager.trimLog(10);
638 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
639 verify(mockReplicatedLog, never()).snapshotCommit();
643 public void testLastAppliedTermInformationReader() {
645 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
647 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
648 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
650 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
651 new MockRaftActorContext.MockPayload());
653 // No followers and valid lastLogEntry
654 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
656 assertEquals("getTerm", 6L, reader.getTerm());
657 assertEquals("getIndex", 9L, reader.getIndex());
659 // No followers and null lastLogEntry
660 reader.init(mockReplicatedLog, 1L, null, false);
662 assertEquals("getTerm", -1L, reader.getTerm());
663 assertEquals("getIndex", -1L, reader.getIndex());
665 // Followers and valid originalIndex entry
666 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
667 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
668 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
670 assertEquals("getTerm", 5L, reader.getTerm());
671 assertEquals("getIndex", 8L, reader.getIndex());
673 // Followers and null originalIndex entry and valid snapshot index
674 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
676 assertEquals("getTerm", 4L, reader.getTerm());
677 assertEquals("getIndex", 7L, reader.getIndex());
679 // Followers and null originalIndex entry and invalid snapshot index
680 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
681 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
683 assertEquals("getTerm", -1L, reader.getTerm());
684 assertEquals("getIndex", -1L, reader.getIndex());