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.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 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 TestActorRef<MessageCollectorActor> actorRef;
83 MockitoAnnotations.initMocks(this);
85 doReturn(false).when(mockRaftActorContext).hasFollowers();
86 doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
87 doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
88 doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
89 doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
90 doReturn("123").when(mockRaftActorContext).getId();
91 doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
92 doReturn(mockRaftActorBehavior).when(mockRaftActorContext).getCurrentBehavior();
93 doReturn("123").when(mockRaftActorBehavior).getLeaderId();
95 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
96 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
97 doReturn("member5").when(mockElectionTerm).getVotedFor();
99 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
100 factory = new TestActorFactory(getSystem());
102 actorRef = factory.createTestActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
103 doReturn(actorRef).when(mockRaftActorContext).getActor();
105 snapshotManager.setCreateSnapshotConsumer(mockProcedure);
109 public void tearDown() {
114 public void testConstruction() {
115 assertEquals(false, snapshotManager.isCapturing());
118 @SuppressWarnings({ "unchecked", "rawtypes" })
120 public void testCaptureToInstall() throws Exception {
122 // Force capturing toInstall = true
123 snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(0, 1,
124 new MockRaftActorContext.MockPayload()), 0, "follower-1");
126 assertEquals(true, snapshotManager.isCapturing());
128 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
129 verify(mockProcedure).accept(outputStream.capture());
130 assertEquals("isPresent", true, outputStream.getValue().isPresent());
132 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
134 // LastIndex and LastTerm are picked up from the lastLogEntry
135 assertEquals(0L, captureSnapshot.getLastIndex());
136 assertEquals(1L, captureSnapshot.getLastTerm());
138 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
139 assertEquals(0L, captureSnapshot.getLastAppliedIndex());
140 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
143 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
144 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
145 actorRef.underlyingActor().clear();
148 @SuppressWarnings({ "rawtypes", "unchecked" })
150 public void testCapture() throws Exception {
151 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
152 new MockRaftActorContext.MockPayload()), 9);
156 assertEquals(true, snapshotManager.isCapturing());
158 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
159 verify(mockProcedure).accept(outputStream.capture());
160 assertEquals("isPresent", false, outputStream.getValue().isPresent());
162 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
164 // LastIndex and LastTerm are picked up from the lastLogEntry
165 assertEquals(9L, captureSnapshot.getLastIndex());
166 assertEquals(1L, captureSnapshot.getLastTerm());
168 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
169 assertEquals(9L, captureSnapshot.getLastAppliedIndex());
170 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
173 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
174 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
176 actorRef.underlyingActor().clear();
180 @SuppressWarnings({ "unchecked", "rawtypes" })
182 public void testCaptureWithNullLastLogEntry() throws Exception {
183 boolean capture = snapshotManager.capture(null, 1);
187 assertEquals(true, 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(-1L, captureSnapshot.getLastIndex());
197 assertEquals(-1L, captureSnapshot.getLastTerm());
199 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
200 assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
201 assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
204 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
205 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
206 actorRef.underlyingActor().clear();
211 public void testCaptureWithCreateProcedureError() throws Exception {
212 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(anyObject());
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(anyObject());
224 @SuppressWarnings("unchecked")
226 public void testIllegalCapture() throws Exception {
227 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
228 new MockRaftActorContext.MockPayload()), 9);
232 verify(mockProcedure).accept(anyObject());
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(anyObject());
246 public void testPersistWhenReplicatedToAllIndexMinusOne() throws Exception {
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() throws Exception {
287 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
288 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
289 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
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(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
344 doReturn(6L).when(replicatedLogEntry).getTerm();
345 doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
347 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6,
348 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
350 snapshotManager.persist(ByteState.empty(), Optional.empty(), 2000000L);
352 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
354 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
356 verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
359 @SuppressWarnings({ "rawtypes", "unchecked" })
361 public void testPersistSendInstallSnapshot() throws Exception {
362 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
363 doNothing().when(mockProcedure).accept(anyObject());
365 // when replicatedToAllIndex = -1
366 boolean capture = snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(9, 6,
367 new MockRaftActorContext.MockPayload()), -1, "follower-1");
371 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
373 ArgumentCaptor<Optional> installSnapshotStreamCapture = ArgumentCaptor.forClass(Optional.class);
374 verify(mockProcedure).accept(installSnapshotStreamCapture.capture());
376 Optional<OutputStream> installSnapshotStream = installSnapshotStreamCapture.getValue();
377 assertEquals("isPresent", true, installSnapshotStream.isPresent());
379 installSnapshotStream.get().write(snapshotState.getBytes());
381 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
383 assertEquals(true, snapshotManager.isCapturing());
385 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
387 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
389 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
390 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
392 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
394 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
396 assertEquals("state", snapshotState, sendInstallSnapshot.getSnapshot().getState());
397 assertArrayEquals("state", snapshotState.getBytes(), sendInstallSnapshot.getSnapshotBytes().read());
401 public void testCallingPersistWithoutCaptureWillDoNothing() {
402 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
404 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
406 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
408 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
412 public void testCallingPersistTwiceWillDoNoHarm() {
413 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
415 // when replicatedToAllIndex = -1
416 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
418 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
420 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
422 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
424 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
428 public void testCommit() {
429 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
431 // when replicatedToAllIndex = -1
432 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
434 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
436 assertEquals(true, snapshotManager.isCapturing());
438 snapshotManager.commit(100L, 1234L);
440 assertEquals(false, snapshotManager.isCapturing());
442 verify(mockReplicatedLog).snapshotCommit();
444 verify(mockDataPersistenceProvider).deleteMessages(50L);
446 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor =
447 ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
449 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
451 assertEquals(100L, criteriaCaptor.getValue().maxSequenceNr());
452 assertEquals(1233L, criteriaCaptor.getValue().maxTimestamp());
454 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
458 public void testCommitBeforePersist() {
459 // when replicatedToAllIndex = -1
460 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
462 snapshotManager.commit(100L, 0);
464 verify(mockReplicatedLog, never()).snapshotCommit();
466 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
468 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
473 public void testCommitBeforeCapture() {
474 snapshotManager.commit(100L, 0);
476 verify(mockReplicatedLog, never()).snapshotCommit();
478 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
480 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
485 public void testCallingCommitMultipleTimesCausesNoHarm() {
486 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
488 // when replicatedToAllIndex = -1
489 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
491 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
493 snapshotManager.commit(100L, 0);
495 snapshotManager.commit(100L, 0);
497 verify(mockReplicatedLog, times(1)).snapshotCommit();
499 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
501 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
505 public void testRollback() {
506 // when replicatedToAllIndex = -1
507 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
509 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
511 snapshotManager.rollback();
513 verify(mockReplicatedLog).snapshotRollback();
515 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
520 public void testRollbackBeforePersist() {
521 // when replicatedToAllIndex = -1
522 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
524 snapshotManager.rollback();
526 verify(mockReplicatedLog, never()).snapshotRollback();
530 public void testRollbackBeforeCapture() {
531 snapshotManager.rollback();
533 verify(mockReplicatedLog, never()).snapshotRollback();
537 public void testCallingRollbackMultipleTimesCausesNoHarm() {
538 // when replicatedToAllIndex = -1
539 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
541 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
543 snapshotManager.rollback();
545 snapshotManager.rollback();
547 verify(mockReplicatedLog, times(1)).snapshotRollback();
551 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
552 doReturn(20L).when(mockRaftActorContext).getLastApplied();
554 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
555 doReturn(true).when(mockReplicatedLog).isPresent(10);
556 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
557 doReturn(5L).when(replicatedLogEntry).getTerm();
559 long retIndex = snapshotManager.trimLog(10);
560 assertEquals("return index", 10L, retIndex);
562 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
563 verify(mockReplicatedLog).snapshotCommit();
565 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
569 public void testTrimLogWhenLastAppliedNotSet() {
570 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
572 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
573 doReturn(true).when(mockReplicatedLog).isPresent(10);
574 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
575 doReturn(5L).when(replicatedLogEntry).getTerm();
577 long retIndex = snapshotManager.trimLog(10);
578 assertEquals("return index", -1L, retIndex);
580 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
581 verify(mockReplicatedLog, never()).snapshotCommit();
583 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
587 public void testTrimLogWhenLastAppliedZero() {
588 doReturn(0L).when(mockRaftActorContext).getLastApplied();
590 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
591 doReturn(true).when(mockReplicatedLog).isPresent(10);
592 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
593 doReturn(5L).when(replicatedLogEntry).getTerm();
595 long retIndex = snapshotManager.trimLog(10);
596 assertEquals("return index", -1L, retIndex);
598 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
599 verify(mockReplicatedLog, never()).snapshotCommit();
601 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
605 public void testTrimLogWhenTrimIndexNotPresent() {
606 doReturn(20L).when(mockRaftActorContext).getLastApplied();
608 doReturn(false).when(mockReplicatedLog).isPresent(10);
610 long retIndex = snapshotManager.trimLog(10);
611 assertEquals("return index", -1L, retIndex);
613 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
614 verify(mockReplicatedLog, never()).snapshotCommit();
616 // Trim index is greater than replicatedToAllIndex so should update it.
617 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
621 public void testTrimLogAfterCapture() {
622 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
623 new MockRaftActorContext.MockPayload()), 9);
627 assertEquals(true, snapshotManager.isCapturing());
629 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
630 doReturn(20L).when(mockRaftActorContext).getLastApplied();
631 doReturn(true).when(mockReplicatedLog).isPresent(10);
632 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
633 doReturn(5L).when(replicatedLogEntry).getTerm();
635 snapshotManager.trimLog(10);
637 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
638 verify(mockReplicatedLog, never()).snapshotCommit();
643 public void testTrimLogAfterCaptureToInstall() {
644 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
645 new MockRaftActorContext.MockPayload()), 9);
649 assertEquals(true, snapshotManager.isCapturing());
651 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
652 doReturn(20L).when(mockRaftActorContext).getLastApplied();
653 doReturn(true).when(mockReplicatedLog).isPresent(10);
654 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
655 doReturn(5L).when(replicatedLogEntry).getTerm();
657 snapshotManager.trimLog(10);
659 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
660 verify(mockReplicatedLog, never()).snapshotCommit();
665 public void testLastAppliedTermInformationReader() {
667 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
669 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
670 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
672 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
673 new MockRaftActorContext.MockPayload());
675 // No followers and valid lastLogEntry
676 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
678 assertEquals("getTerm", 6L, reader.getTerm());
679 assertEquals("getIndex", 9L, reader.getIndex());
681 // No followers and null lastLogEntry
682 reader.init(mockReplicatedLog, 1L, null, false);
684 assertEquals("getTerm", -1L, reader.getTerm());
685 assertEquals("getIndex", -1L, reader.getIndex());
687 // Followers and valid originalIndex entry
688 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
689 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
690 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
692 assertEquals("getTerm", 5L, reader.getTerm());
693 assertEquals("getIndex", 8L, reader.getIndex());
695 // Followers and null originalIndex entry and valid snapshot index
696 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
698 assertEquals("getTerm", 4L, reader.getTerm());
699 assertEquals("getIndex", 7L, reader.getIndex());
701 // Followers and null originalIndex entry and invalid snapshot index
702 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
703 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
705 assertEquals("getTerm", -1L, reader.getTerm());
706 assertEquals("getIndex", -1L, reader.getIndex());