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
8 package org.opendaylight.controller.cluster.raft;
10 import static org.junit.Assert.assertArrayEquals;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.ArgumentMatchers.anyLong;
16 import static org.mockito.Mockito.doNothing;
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;
25 import akka.actor.ActorRef;
26 import akka.persistence.SnapshotSelectionCriteria;
27 import java.io.OutputStream;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.function.Consumer;
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.mockito.ArgumentCaptor;
36 import org.mockito.Mock;
37 import org.mockito.junit.MockitoJUnitRunner;
38 import org.opendaylight.controller.cluster.DataPersistenceProvider;
39 import org.opendaylight.controller.cluster.io.FileBackedOutputStreamFactory;
40 import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
41 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
42 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
43 import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete;
44 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
45 import org.opendaylight.controller.cluster.raft.persisted.ByteState;
46 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
47 import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
48 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
49 import org.slf4j.LoggerFactory;
51 @RunWith(MockitoJUnitRunner.StrictStubs.class)
52 public class SnapshotManagerTest extends AbstractActorTest {
55 private RaftActorContext mockRaftActorContext;
58 private ConfigParams mockConfigParams;
61 private ReplicatedLog mockReplicatedLog;
64 private DataPersistenceProvider mockDataPersistenceProvider;
67 private RaftActorBehavior mockRaftActorBehavior;
70 private Consumer<Optional<OutputStream>> mockProcedure;
73 private ElectionTerm mockElectionTerm;
75 private SnapshotManager snapshotManager;
77 private TestActorFactory factory;
79 private ActorRef actorRef;
83 doReturn(false).when(mockRaftActorContext).hasFollowers();
84 doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
85 doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
86 doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
87 doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
88 doReturn("123").when(mockRaftActorContext).getId();
89 doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
90 doReturn(mockRaftActorBehavior).when(mockRaftActorContext).getCurrentBehavior();
91 doReturn("123").when(mockRaftActorBehavior).getLeaderId();
93 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
94 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
95 doReturn("member5").when(mockElectionTerm).getVotedFor();
97 doReturn(new FileBackedOutputStreamFactory(10000000, "target"))
98 .when(mockRaftActorContext).getFileBackedOutputStreamFactory();
100 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
101 factory = new TestActorFactory(getSystem());
103 actorRef = factory.createActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
104 doReturn(actorRef).when(mockRaftActorContext).getActor();
106 snapshotManager.setCreateSnapshotConsumer(mockProcedure);
110 public void tearDown() {
115 public void testConstruction() {
116 assertFalse(snapshotManager.isCapturing());
119 @SuppressWarnings({ "unchecked", "rawtypes" })
121 public void testCaptureToInstall() {
123 // Force capturing toInstall = true
124 snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(0, 1,
125 new MockRaftActorContext.MockPayload()), 0, "follower-1");
127 assertTrue(snapshotManager.isCapturing());
129 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
130 verify(mockProcedure).accept(outputStream.capture());
131 assertEquals("isPresent", true, outputStream.getValue().isPresent());
133 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
135 // LastIndex and LastTerm are picked up from the lastLogEntry
136 assertEquals(0L, captureSnapshot.getLastIndex());
137 assertEquals(1L, captureSnapshot.getLastTerm());
139 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
140 assertEquals(0L, captureSnapshot.getLastAppliedIndex());
141 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
144 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
145 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
146 MessageCollectorActor.clearMessages(actorRef);
149 @SuppressWarnings({ "rawtypes", "unchecked" })
151 public void testCapture() {
152 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
153 new MockRaftActorContext.MockPayload()), 9);
157 assertTrue(snapshotManager.isCapturing());
159 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
160 verify(mockProcedure).accept(outputStream.capture());
161 assertEquals("isPresent", false, outputStream.getValue().isPresent());
163 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
165 // LastIndex and LastTerm are picked up from the lastLogEntry
166 assertEquals(9L, captureSnapshot.getLastIndex());
167 assertEquals(1L, captureSnapshot.getLastTerm());
169 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
170 assertEquals(9L, captureSnapshot.getLastAppliedIndex());
171 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
174 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
175 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
177 MessageCollectorActor.clearMessages(actorRef);
180 @SuppressWarnings({ "unchecked", "rawtypes" })
182 public void testCaptureWithNullLastLogEntry() {
183 boolean capture = snapshotManager.capture(null, 1);
187 assertTrue(snapshotManager.isCapturing());
189 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
190 verify(mockProcedure).accept(outputStream.capture());
191 assertEquals("isPresent", false, outputStream.getValue().isPresent());
193 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
195 // LastIndex and LastTerm are picked up from the lastLogEntry
196 assertEquals(0, captureSnapshot.getLastIndex());
197 assertEquals(0, captureSnapshot.getLastTerm());
199 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
200 assertEquals(0, captureSnapshot.getLastAppliedIndex());
201 assertEquals(0, captureSnapshot.getLastAppliedTerm());
204 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
205 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
206 MessageCollectorActor.clearMessages(actorRef);
210 public void testCaptureWithCreateProcedureError() {
211 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(any());
213 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
214 new MockRaftActorContext.MockPayload()), 9);
216 assertFalse(capture);
218 assertFalse(snapshotManager.isCapturing());
220 verify(mockProcedure).accept(any());
223 @SuppressWarnings("unchecked")
225 public void testIllegalCapture() {
226 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
227 new MockRaftActorContext.MockPayload()), 9);
231 verify(mockProcedure).accept(any());
233 reset(mockProcedure);
235 // This will not cause snapshot capture to start again
236 capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
237 new MockRaftActorContext.MockPayload()), 9);
239 assertFalse(capture);
241 verify(mockProcedure, never()).accept(any());
245 public void testPersistWhenReplicatedToAllIndexMinusOne() {
246 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
247 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
249 doReturn(true).when(mockRaftActorContext).hasFollowers();
251 doReturn(8L).when(mockRaftActorContext).getLastApplied();
253 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 3L, new MockRaftActorContext.MockPayload());
255 ReplicatedLogEntry lastAppliedEntry = new SimpleReplicatedLogEntry(
256 8L, 2L, new MockRaftActorContext.MockPayload());
258 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
259 doReturn(List.of(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
261 // when replicatedToAllIndex = -1
262 snapshotManager.capture(lastLogEntry, -1);
264 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
265 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
267 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
268 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
270 Snapshot snapshot = snapshotArgumentCaptor.getValue();
272 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
273 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
274 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
275 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
276 assertEquals("getState", snapshotState, snapshot.getState());
277 assertEquals("getUnAppliedEntries", List.of(lastLogEntry), snapshot.getUnAppliedEntries());
278 assertEquals("electionTerm", mockElectionTerm.getCurrentTerm(), snapshot.getElectionTerm());
279 assertEquals("electionVotedFor", mockElectionTerm.getVotedFor(), snapshot.getElectionVotedFor());
281 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
285 public void testPersistWhenReplicatedToAllIndexNotMinus() {
286 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
287 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
288 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
289 doReturn(null).when(mockReplicatedLog).get(0);
290 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
291 doReturn(6L).when(replicatedLogEntry).getTerm();
292 doReturn(9L).when(replicatedLogEntry).getIndex();
294 // when replicatedToAllIndex != -1
295 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), 9);
297 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
298 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
300 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
301 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
303 Snapshot snapshot = snapshotArgumentCaptor.getValue();
305 assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
306 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
307 assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
308 assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
309 assertEquals("getState", snapshotState, snapshot.getState());
310 assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
312 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
314 verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
318 public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold() {
319 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
321 // when replicatedToAllIndex = -1
322 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
324 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
326 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
328 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
330 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
334 public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
335 doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
336 doReturn(100).when(mockReplicatedLog).dataSize();
338 doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
339 doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
341 long replicatedToAllIndex = 1;
342 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
343 doReturn(null).when(mockReplicatedLog).get(0);
344 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
345 doReturn(6L).when(replicatedLogEntry).getTerm();
346 doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
348 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6,
349 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
351 snapshotManager.persist(ByteState.empty(), Optional.empty(), 2000000L);
353 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
355 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
357 verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
360 @SuppressWarnings({ "rawtypes", "unchecked" })
362 public void testPersistSendInstallSnapshot() throws Exception {
363 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
364 doNothing().when(mockProcedure).accept(any());
366 // when replicatedToAllIndex = -1
367 boolean capture = snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(9, 6,
368 new MockRaftActorContext.MockPayload()), -1, "follower-1");
372 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
374 ArgumentCaptor<Optional> installSnapshotStreamCapture = ArgumentCaptor.forClass(Optional.class);
375 verify(mockProcedure).accept(installSnapshotStreamCapture.capture());
377 Optional<OutputStream> installSnapshotStream = installSnapshotStreamCapture.getValue();
378 assertEquals("isPresent", true, installSnapshotStream.isPresent());
380 installSnapshotStream.orElseThrow().write(snapshotState.getBytes());
382 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
384 assertTrue(snapshotManager.isCapturing());
386 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
388 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
390 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
391 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
393 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
395 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
397 assertEquals("state", snapshotState, sendInstallSnapshot.getSnapshot().getState());
398 assertArrayEquals("state", snapshotState.getBytes(), sendInstallSnapshot.getSnapshotBytes().read());
402 public void testCallingPersistWithoutCaptureWillDoNothing() {
403 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
405 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
407 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
409 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
413 public void testCallingPersistTwiceWillDoNoHarm() {
414 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
416 // when replicatedToAllIndex = -1
417 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
419 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
421 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
423 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
425 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
429 public void testCommit() {
430 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
432 // when replicatedToAllIndex = -1
433 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
435 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
437 assertTrue(snapshotManager.isCapturing());
439 snapshotManager.commit(100L, 1234L);
441 assertFalse(snapshotManager.isCapturing());
443 verify(mockReplicatedLog).snapshotCommit();
445 verify(mockDataPersistenceProvider).deleteMessages(50L);
447 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor =
448 ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
450 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
452 assertEquals(Long.MAX_VALUE, criteriaCaptor.getValue().maxSequenceNr());
453 assertEquals(1233L, criteriaCaptor.getValue().maxTimestamp());
455 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
459 public void testCommitBeforePersist() {
460 // when replicatedToAllIndex = -1
461 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
463 snapshotManager.commit(100L, 0);
465 verify(mockReplicatedLog, never()).snapshotCommit();
467 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
469 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
474 public void testCommitBeforeCapture() {
475 snapshotManager.commit(100L, 0);
477 verify(mockReplicatedLog, never()).snapshotCommit();
479 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
481 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
486 public void testCallingCommitMultipleTimesCausesNoHarm() {
487 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
489 // when replicatedToAllIndex = -1
490 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
492 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
494 snapshotManager.commit(100L, 0);
496 snapshotManager.commit(100L, 0);
498 verify(mockReplicatedLog, times(1)).snapshotCommit();
500 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
502 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
506 public void testRollback() {
507 // when replicatedToAllIndex = -1
508 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
510 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
512 snapshotManager.rollback();
514 verify(mockReplicatedLog).snapshotRollback();
516 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
521 public void testRollbackBeforePersist() {
522 // when replicatedToAllIndex = -1
523 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
525 snapshotManager.rollback();
527 verify(mockReplicatedLog, never()).snapshotRollback();
531 public void testRollbackBeforeCapture() {
532 snapshotManager.rollback();
534 verify(mockReplicatedLog, never()).snapshotRollback();
538 public void testCallingRollbackMultipleTimesCausesNoHarm() {
539 // when replicatedToAllIndex = -1
540 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
542 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
544 snapshotManager.rollback();
546 snapshotManager.rollback();
548 verify(mockReplicatedLog, times(1)).snapshotRollback();
552 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
553 doReturn(20L).when(mockRaftActorContext).getLastApplied();
555 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
556 doReturn(true).when(mockReplicatedLog).isPresent(10);
557 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
558 doReturn(5L).when(replicatedLogEntry).getTerm();
560 long retIndex = snapshotManager.trimLog(10);
561 assertEquals("return index", 10L, retIndex);
563 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
564 verify(mockReplicatedLog).snapshotCommit(false);
566 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
570 public void testTrimLogWhenLastAppliedNotSet() {
571 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
573 long retIndex = snapshotManager.trimLog(10);
574 assertEquals("return index", -1L, retIndex);
576 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
577 verify(mockReplicatedLog, never()).snapshotCommit(false);
579 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
583 public void testTrimLogWhenLastAppliedZero() {
584 doReturn(0L).when(mockRaftActorContext).getLastApplied();
586 long retIndex = snapshotManager.trimLog(10);
587 assertEquals("return index", -1L, retIndex);
589 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
590 verify(mockReplicatedLog, never()).snapshotCommit(false);
592 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
596 public void testTrimLogWhenTrimIndexNotPresent() {
597 doReturn(20L).when(mockRaftActorContext).getLastApplied();
599 doReturn(false).when(mockReplicatedLog).isPresent(10);
601 long retIndex = snapshotManager.trimLog(10);
602 assertEquals("return index", -1L, retIndex);
604 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
605 verify(mockReplicatedLog, never()).snapshotCommit(false);
607 // Trim index is greater than replicatedToAllIndex so should update it.
608 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
612 public void testTrimLogAfterCapture() {
613 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
614 new MockRaftActorContext.MockPayload()), 9);
618 assertTrue(snapshotManager.isCapturing());
620 snapshotManager.trimLog(10);
622 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
623 verify(mockReplicatedLog, never()).snapshotCommit(false);
627 public void testTrimLogAfterCaptureToInstall() {
628 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
629 new MockRaftActorContext.MockPayload()), 9);
633 assertTrue(snapshotManager.isCapturing());
635 snapshotManager.trimLog(10);
637 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
638 verify(mockReplicatedLog, never()).snapshotCommit();
642 public void testLastAppliedTermInformationReader() {
644 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
646 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
647 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
649 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
650 new MockRaftActorContext.MockPayload());
652 // No followers and valid lastLogEntry
653 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
655 assertEquals("getTerm", 6L, reader.getTerm());
656 assertEquals("getIndex", 9L, reader.getIndex());
658 // No followers and null lastLogEntry
659 reader.init(mockReplicatedLog, 1L, null, false);
661 assertEquals("getTerm", -1L, reader.getTerm());
662 assertEquals("getIndex", -1L, reader.getIndex());
664 // Followers and valid originalIndex entry
665 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
666 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
667 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
669 assertEquals("getTerm", 5L, reader.getTerm());
670 assertEquals("getIndex", 8L, reader.getIndex());
672 // Followers and null originalIndex entry and valid snapshot index
673 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
675 assertEquals("getTerm", 4L, reader.getTerm());
676 assertEquals("getIndex", 7L, reader.getIndex());
678 // Followers and null originalIndex entry and invalid snapshot index
679 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
680 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
682 assertEquals("getTerm", -1L, reader.getTerm());
683 assertEquals("getIndex", -1L, reader.getIndex());