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 java.io.OutputStream;
30 import java.util.Arrays;
31 import java.util.Optional;
32 import java.util.function.Consumer;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.mockito.ArgumentCaptor;
37 import org.mockito.Mock;
38 import org.mockito.MockitoAnnotations;
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 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 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 doReturn(new FileBackedOutputStreamFactory(10000000, "target"))
100 .when(mockRaftActorContext).getFileBackedOutputStreamFactory();
102 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
103 factory = new TestActorFactory(getSystem());
105 actorRef = factory.createActor(MessageCollectorActor.props(), factory.generateActorId("test-"));
106 doReturn(actorRef).when(mockRaftActorContext).getActor();
108 snapshotManager.setCreateSnapshotConsumer(mockProcedure);
112 public void tearDown() {
117 public void testConstruction() {
118 assertEquals(false, snapshotManager.isCapturing());
121 @SuppressWarnings({ "unchecked", "rawtypes" })
123 public void testCaptureToInstall() {
125 // Force capturing toInstall = true
126 snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(0, 1,
127 new MockRaftActorContext.MockPayload()), 0, "follower-1");
129 assertEquals(true, snapshotManager.isCapturing());
131 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
132 verify(mockProcedure).accept(outputStream.capture());
133 assertEquals("isPresent", true, outputStream.getValue().isPresent());
135 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
137 // LastIndex and LastTerm are picked up from the lastLogEntry
138 assertEquals(0L, captureSnapshot.getLastIndex());
139 assertEquals(1L, captureSnapshot.getLastTerm());
141 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
142 assertEquals(0L, captureSnapshot.getLastAppliedIndex());
143 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
146 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
147 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
148 MessageCollectorActor.clearMessages(actorRef);
151 @SuppressWarnings({ "rawtypes", "unchecked" })
153 public void testCapture() {
154 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
155 new MockRaftActorContext.MockPayload()), 9);
159 assertEquals(true, snapshotManager.isCapturing());
161 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
162 verify(mockProcedure).accept(outputStream.capture());
163 assertEquals("isPresent", false, outputStream.getValue().isPresent());
165 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
167 // LastIndex and LastTerm are picked up from the lastLogEntry
168 assertEquals(9L, captureSnapshot.getLastIndex());
169 assertEquals(1L, captureSnapshot.getLastTerm());
171 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
172 assertEquals(9L, captureSnapshot.getLastAppliedIndex());
173 assertEquals(1L, captureSnapshot.getLastAppliedTerm());
176 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
177 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
179 MessageCollectorActor.clearMessages(actorRef);
182 @SuppressWarnings({ "unchecked", "rawtypes" })
184 public void testCaptureWithNullLastLogEntry() {
185 boolean capture = snapshotManager.capture(null, 1);
189 assertEquals(true, snapshotManager.isCapturing());
191 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
192 verify(mockProcedure).accept(outputStream.capture());
193 assertEquals("isPresent", false, outputStream.getValue().isPresent());
195 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
197 // LastIndex and LastTerm are picked up from the lastLogEntry
198 assertEquals(-1L, captureSnapshot.getLastIndex());
199 assertEquals(-1L, captureSnapshot.getLastTerm());
201 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
202 assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
203 assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
206 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
207 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
208 MessageCollectorActor.clearMessages(actorRef);
212 public void testCaptureWithCreateProcedureError() {
213 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(anyObject());
215 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
216 new MockRaftActorContext.MockPayload()), 9);
218 assertFalse(capture);
220 assertEquals(false, snapshotManager.isCapturing());
222 verify(mockProcedure).accept(anyObject());
225 @SuppressWarnings("unchecked")
227 public void testIllegalCapture() {
228 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
229 new MockRaftActorContext.MockPayload()), 9);
233 verify(mockProcedure).accept(anyObject());
235 reset(mockProcedure);
237 // This will not cause snapshot capture to start again
238 capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
239 new MockRaftActorContext.MockPayload()), 9);
241 assertFalse(capture);
243 verify(mockProcedure, never()).accept(anyObject());
247 public void testPersistWhenReplicatedToAllIndexMinusOne() {
248 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
249 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
251 doReturn(true).when(mockRaftActorContext).hasFollowers();
253 doReturn(8L).when(mockRaftActorContext).getLastApplied();
255 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 3L, new MockRaftActorContext.MockPayload());
257 ReplicatedLogEntry lastAppliedEntry = new SimpleReplicatedLogEntry(
258 8L, 2L, new MockRaftActorContext.MockPayload());
260 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
261 doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
263 // when replicatedToAllIndex = -1
264 snapshotManager.capture(lastLogEntry, -1);
266 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
267 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
269 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
270 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
272 Snapshot snapshot = snapshotArgumentCaptor.getValue();
274 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
275 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
276 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
277 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
278 assertEquals("getState", snapshotState, snapshot.getState());
279 assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
280 assertEquals("electionTerm", mockElectionTerm.getCurrentTerm(), snapshot.getElectionTerm());
281 assertEquals("electionVotedFor", mockElectionTerm.getVotedFor(), snapshot.getElectionVotedFor());
283 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
287 public void testPersistWhenReplicatedToAllIndexNotMinus() {
288 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
289 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
290 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
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(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(anyObject());
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.get().write(snapshotState.getBytes());
382 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
384 assertEquals(true, 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 assertEquals(true, snapshotManager.isCapturing());
439 snapshotManager.commit(100L, 1234L);
441 assertEquals(false, 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(100L, 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();
566 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
570 public void testTrimLogWhenLastAppliedNotSet() {
571 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
573 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
574 doReturn(true).when(mockReplicatedLog).isPresent(10);
575 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
576 doReturn(5L).when(replicatedLogEntry).getTerm();
578 long retIndex = snapshotManager.trimLog(10);
579 assertEquals("return index", -1L, retIndex);
581 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
582 verify(mockReplicatedLog, never()).snapshotCommit();
584 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
588 public void testTrimLogWhenLastAppliedZero() {
589 doReturn(0L).when(mockRaftActorContext).getLastApplied();
591 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
592 doReturn(true).when(mockReplicatedLog).isPresent(10);
593 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
594 doReturn(5L).when(replicatedLogEntry).getTerm();
596 long retIndex = snapshotManager.trimLog(10);
597 assertEquals("return index", -1L, retIndex);
599 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
600 verify(mockReplicatedLog, never()).snapshotCommit();
602 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
606 public void testTrimLogWhenTrimIndexNotPresent() {
607 doReturn(20L).when(mockRaftActorContext).getLastApplied();
609 doReturn(false).when(mockReplicatedLog).isPresent(10);
611 long retIndex = snapshotManager.trimLog(10);
612 assertEquals("return index", -1L, retIndex);
614 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
615 verify(mockReplicatedLog, never()).snapshotCommit();
617 // Trim index is greater than replicatedToAllIndex so should update it.
618 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
622 public void testTrimLogAfterCapture() {
623 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
624 new MockRaftActorContext.MockPayload()), 9);
628 assertEquals(true, snapshotManager.isCapturing());
630 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
631 doReturn(20L).when(mockRaftActorContext).getLastApplied();
632 doReturn(true).when(mockReplicatedLog).isPresent(10);
633 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
634 doReturn(5L).when(replicatedLogEntry).getTerm();
636 snapshotManager.trimLog(10);
638 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
639 verify(mockReplicatedLog, never()).snapshotCommit();
644 public void testTrimLogAfterCaptureToInstall() {
645 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
646 new MockRaftActorContext.MockPayload()), 9);
650 assertEquals(true, snapshotManager.isCapturing());
652 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
653 doReturn(20L).when(mockRaftActorContext).getLastApplied();
654 doReturn(true).when(mockReplicatedLog).isPresent(10);
655 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
656 doReturn(5L).when(replicatedLogEntry).getTerm();
658 snapshotManager.trimLog(10);
660 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
661 verify(mockReplicatedLog, never()).snapshotCommit();
666 public void testLastAppliedTermInformationReader() {
668 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
670 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
671 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
673 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
674 new MockRaftActorContext.MockPayload());
676 // No followers and valid lastLogEntry
677 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
679 assertEquals("getTerm", 6L, reader.getTerm());
680 assertEquals("getIndex", 9L, reader.getIndex());
682 // No followers and null lastLogEntry
683 reader.init(mockReplicatedLog, 1L, null, false);
685 assertEquals("getTerm", -1L, reader.getTerm());
686 assertEquals("getIndex", -1L, reader.getIndex());
688 // Followers and valid originalIndex entry
689 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
690 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
691 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
693 assertEquals("getTerm", 5L, reader.getTerm());
694 assertEquals("getIndex", 8L, reader.getIndex());
696 // Followers and null originalIndex entry and valid snapshot index
697 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
699 assertEquals("getTerm", 4L, reader.getTerm());
700 assertEquals("getIndex", 7L, reader.getIndex());
702 // Followers and null originalIndex entry and invalid snapshot index
703 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
704 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
706 assertEquals("getTerm", -1L, reader.getTerm());
707 assertEquals("getIndex", -1L, reader.getIndex());