2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.cluster.raft;
11 import static org.junit.Assert.assertArrayEquals;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertTrue;
15 import static org.mockito.Matchers.any;
16 import static org.mockito.Matchers.anyLong;
17 import static org.mockito.Matchers.anyObject;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.doThrow;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.reset;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
27 import akka.actor.ActorRef;
28 import akka.persistence.SnapshotSelectionCriteria;
29 import akka.testkit.TestActorRef;
30 import java.io.OutputStream;
31 import java.util.Arrays;
32 import java.util.Optional;
33 import java.util.function.Consumer;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.Mock;
39 import org.mockito.MockitoAnnotations;
40 import org.opendaylight.controller.cluster.DataPersistenceProvider;
41 import org.opendaylight.controller.cluster.io.FileBackedOutputStream;
42 import org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader;
43 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
44 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
45 import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete;
46 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
47 import org.opendaylight.controller.cluster.raft.persisted.ByteState;
48 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
49 import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
50 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
51 import org.slf4j.LoggerFactory;
53 public class SnapshotManagerTest extends AbstractActorTest {
56 private RaftActorContext mockRaftActorContext;
59 private ConfigParams mockConfigParams;
62 private ReplicatedLog mockReplicatedLog;
65 private DataPersistenceProvider mockDataPersistenceProvider;
68 private RaftActorBehavior mockRaftActorBehavior;
71 private Consumer<Optional<OutputStream>> mockProcedure;
74 private ElectionTerm mockElectionTerm;
76 private SnapshotManager snapshotManager;
78 private TestActorFactory factory;
80 private TestActorRef<MessageCollectorActor> actorRef;
84 MockitoAnnotations.initMocks(this);
86 doReturn(false).when(mockRaftActorContext).hasFollowers();
87 doReturn(mockConfigParams).when(mockRaftActorContext).getConfigParams();
88 doReturn(10L).when(mockConfigParams).getSnapshotBatchCount();
89 doReturn(70).when(mockConfigParams).getSnapshotDataThresholdPercentage();
90 doReturn(mockReplicatedLog).when(mockRaftActorContext).getReplicatedLog();
91 doReturn("123").when(mockRaftActorContext).getId();
92 doReturn(mockDataPersistenceProvider).when(mockRaftActorContext).getPersistenceProvider();
93 doReturn(mockRaftActorBehavior).when(mockRaftActorContext).getCurrentBehavior();
94 doReturn("123").when(mockRaftActorBehavior).getLeaderId();
96 doReturn(mockElectionTerm).when(mockRaftActorContext).getTermInformation();
97 doReturn(5L).when(mockElectionTerm).getCurrentTerm();
98 doReturn("member5").when(mockElectionTerm).getVotedFor();
100 doReturn(new FileBackedOutputStream(10000000, "target")).when(mockRaftActorContext).newFileBackedOutputStream();
102 snapshotManager = new SnapshotManager(mockRaftActorContext, LoggerFactory.getLogger(this.getClass()));
103 factory = new TestActorFactory(getSystem());
105 actorRef = factory.createTestActor(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() throws Exception {
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 actorRef.underlyingActor().clear();
151 @SuppressWarnings({ "rawtypes", "unchecked" })
153 public void testCapture() throws Exception {
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 actorRef.underlyingActor().clear();
183 @SuppressWarnings({ "unchecked", "rawtypes" })
185 public void testCaptureWithNullLastLogEntry() throws Exception {
186 boolean capture = snapshotManager.capture(null, 1);
190 assertEquals(true, snapshotManager.isCapturing());
192 ArgumentCaptor<Optional> outputStream = ArgumentCaptor.forClass(Optional.class);
193 verify(mockProcedure).accept(outputStream.capture());
194 assertEquals("isPresent", false, outputStream.getValue().isPresent());
196 CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
198 // LastIndex and LastTerm are picked up from the lastLogEntry
199 assertEquals(-1L, captureSnapshot.getLastIndex());
200 assertEquals(-1L, captureSnapshot.getLastTerm());
202 // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
203 assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
204 assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
207 assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
208 assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
209 actorRef.underlyingActor().clear();
214 public void testCaptureWithCreateProcedureError() throws Exception {
215 doThrow(new RuntimeException("mock")).when(mockProcedure).accept(anyObject());
217 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
218 new MockRaftActorContext.MockPayload()), 9);
220 assertFalse(capture);
222 assertEquals(false, snapshotManager.isCapturing());
224 verify(mockProcedure).accept(anyObject());
227 @SuppressWarnings("unchecked")
229 public void testIllegalCapture() throws Exception {
230 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
231 new MockRaftActorContext.MockPayload()), 9);
235 verify(mockProcedure).accept(anyObject());
237 reset(mockProcedure);
239 // This will not cause snapshot capture to start again
240 capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
241 new MockRaftActorContext.MockPayload()), 9);
243 assertFalse(capture);
245 verify(mockProcedure, never()).accept(anyObject());
249 public void testPersistWhenReplicatedToAllIndexMinusOne() throws Exception {
250 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
251 doReturn(1L).when(mockReplicatedLog).getSnapshotTerm();
253 doReturn(true).when(mockRaftActorContext).hasFollowers();
255 doReturn(8L).when(mockRaftActorContext).getLastApplied();
257 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 3L, new MockRaftActorContext.MockPayload());
259 ReplicatedLogEntry lastAppliedEntry = new SimpleReplicatedLogEntry(
260 8L, 2L, new MockRaftActorContext.MockPayload());
262 doReturn(lastAppliedEntry).when(mockReplicatedLog).get(8L);
263 doReturn(Arrays.asList(lastLogEntry)).when(mockReplicatedLog).getFrom(9L);
265 // when replicatedToAllIndex = -1
266 snapshotManager.capture(lastLogEntry, -1);
268 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
269 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
271 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
272 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
274 Snapshot snapshot = snapshotArgumentCaptor.getValue();
276 assertEquals("getLastTerm", 3L, snapshot.getLastTerm());
277 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
278 assertEquals("getLastAppliedTerm", 2L, snapshot.getLastAppliedTerm());
279 assertEquals("getLastAppliedIndex", 8L, snapshot.getLastAppliedIndex());
280 assertEquals("getState", snapshotState, snapshot.getState());
281 assertEquals("getUnAppliedEntries", Arrays.asList(lastLogEntry), snapshot.getUnAppliedEntries());
282 assertEquals("electionTerm", mockElectionTerm.getCurrentTerm(), snapshot.getElectionTerm());
283 assertEquals("electionVotedFor", mockElectionTerm.getVotedFor(), snapshot.getElectionVotedFor());
285 verify(mockReplicatedLog).snapshotPreCommit(7L, 1L);
289 public void testPersistWhenReplicatedToAllIndexNotMinus() throws Exception {
290 doReturn(45L).when(mockReplicatedLog).getSnapshotIndex();
291 doReturn(6L).when(mockReplicatedLog).getSnapshotTerm();
292 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
293 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(9);
294 doReturn(6L).when(replicatedLogEntry).getTerm();
295 doReturn(9L).when(replicatedLogEntry).getIndex();
297 // when replicatedToAllIndex != -1
298 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), 9);
300 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
301 snapshotManager.persist(snapshotState, Optional.empty(), Runtime.getRuntime().totalMemory());
303 ArgumentCaptor<Snapshot> snapshotArgumentCaptor = ArgumentCaptor.forClass(Snapshot.class);
304 verify(mockDataPersistenceProvider).saveSnapshot(snapshotArgumentCaptor.capture());
306 Snapshot snapshot = snapshotArgumentCaptor.getValue();
308 assertEquals("getLastTerm", 6L, snapshot.getLastTerm());
309 assertEquals("getLastIndex", 9L, snapshot.getLastIndex());
310 assertEquals("getLastAppliedTerm", 6L, snapshot.getLastAppliedTerm());
311 assertEquals("getLastAppliedIndex", 9L, snapshot.getLastAppliedIndex());
312 assertEquals("getState", snapshotState, snapshot.getState());
313 assertEquals("getUnAppliedEntries size", 0, snapshot.getUnAppliedEntries().size());
315 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
317 verify(mockRaftActorBehavior).setReplicatedToAllIndex(9);
321 public void testPersistWhenReplicatedLogDataSizeGreaterThanThreshold() {
322 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
324 // when replicatedToAllIndex = -1
325 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
327 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
329 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
331 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
333 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
337 public void testPersistWhenReplicatedLogSizeExceedsSnapshotBatchCount() {
338 doReturn(10L).when(mockReplicatedLog).size(); // matches snapshotBatchCount
339 doReturn(100).when(mockReplicatedLog).dataSize();
341 doReturn(5L).when(mockReplicatedLog).getSnapshotIndex();
342 doReturn(5L).when(mockReplicatedLog).getSnapshotTerm();
344 long replicatedToAllIndex = 1;
345 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
346 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(replicatedToAllIndex);
347 doReturn(6L).when(replicatedLogEntry).getTerm();
348 doReturn(replicatedToAllIndex).when(replicatedLogEntry).getIndex();
350 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6,
351 new MockRaftActorContext.MockPayload()), replicatedToAllIndex);
353 snapshotManager.persist(ByteState.empty(), Optional.empty(), 2000000L);
355 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
357 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
359 verify(mockRaftActorBehavior).setReplicatedToAllIndex(replicatedToAllIndex);
362 @SuppressWarnings({ "rawtypes", "unchecked" })
364 public void testPersistSendInstallSnapshot() throws Exception {
365 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
366 doNothing().when(mockProcedure).accept(anyObject());
368 // when replicatedToAllIndex = -1
369 boolean capture = snapshotManager.captureToInstall(new SimpleReplicatedLogEntry(9, 6,
370 new MockRaftActorContext.MockPayload()), -1, "follower-1");
374 ByteState snapshotState = ByteState.of(new byte[] {1,2,3,4,5,6,7,8,9,10});
376 ArgumentCaptor<Optional> installSnapshotStreamCapture = ArgumentCaptor.forClass(Optional.class);
377 verify(mockProcedure).accept(installSnapshotStreamCapture.capture());
379 Optional<OutputStream> installSnapshotStream = installSnapshotStreamCapture.getValue();
380 assertEquals("isPresent", true, installSnapshotStream.isPresent());
382 installSnapshotStream.get().write(snapshotState.getBytes());
384 snapshotManager.persist(snapshotState, installSnapshotStream, Runtime.getRuntime().totalMemory());
386 assertEquals(true, snapshotManager.isCapturing());
388 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
390 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
392 ArgumentCaptor<SendInstallSnapshot> sendInstallSnapshotArgumentCaptor
393 = ArgumentCaptor.forClass(SendInstallSnapshot.class);
395 verify(mockRaftActorBehavior).handleMessage(any(ActorRef.class), sendInstallSnapshotArgumentCaptor.capture());
397 SendInstallSnapshot sendInstallSnapshot = sendInstallSnapshotArgumentCaptor.getValue();
399 assertEquals("state", snapshotState, sendInstallSnapshot.getSnapshot().getState());
400 assertArrayEquals("state", snapshotState.getBytes(), sendInstallSnapshot.getSnapshotBytes().read());
404 public void testCallingPersistWithoutCaptureWillDoNothing() {
405 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
407 verify(mockDataPersistenceProvider, never()).saveSnapshot(any(Snapshot.class));
409 verify(mockReplicatedLog, never()).snapshotPreCommit(9L, 6L);
411 verify(mockRaftActorBehavior, never()).handleMessage(any(ActorRef.class), any(SendInstallSnapshot.class));
415 public void testCallingPersistTwiceWillDoNoHarm() {
416 doReturn(Integer.MAX_VALUE).when(mockReplicatedLog).dataSize();
418 // when replicatedToAllIndex = -1
419 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
421 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
423 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
425 verify(mockDataPersistenceProvider).saveSnapshot(any(Snapshot.class));
427 verify(mockReplicatedLog).snapshotPreCommit(9L, 6L);
431 public void testCommit() {
432 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
434 // when replicatedToAllIndex = -1
435 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
437 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
439 assertEquals(true, snapshotManager.isCapturing());
441 snapshotManager.commit(100L, 1234L);
443 assertEquals(false, snapshotManager.isCapturing());
445 verify(mockReplicatedLog).snapshotCommit();
447 verify(mockDataPersistenceProvider).deleteMessages(50L);
449 ArgumentCaptor<SnapshotSelectionCriteria> criteriaCaptor =
450 ArgumentCaptor.forClass(SnapshotSelectionCriteria.class);
452 verify(mockDataPersistenceProvider).deleteSnapshots(criteriaCaptor.capture());
454 assertEquals(100L, criteriaCaptor.getValue().maxSequenceNr());
455 assertEquals(1233L, criteriaCaptor.getValue().maxTimestamp());
457 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
461 public void testCommitBeforePersist() {
462 // when replicatedToAllIndex = -1
463 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
465 snapshotManager.commit(100L, 0);
467 verify(mockReplicatedLog, never()).snapshotCommit();
469 verify(mockDataPersistenceProvider, never()).deleteMessages(100L);
471 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
476 public void testCommitBeforeCapture() {
477 snapshotManager.commit(100L, 0);
479 verify(mockReplicatedLog, never()).snapshotCommit();
481 verify(mockDataPersistenceProvider, never()).deleteMessages(anyLong());
483 verify(mockDataPersistenceProvider, never()).deleteSnapshots(any(SnapshotSelectionCriteria.class));
488 public void testCallingCommitMultipleTimesCausesNoHarm() {
489 doReturn(50L).when(mockDataPersistenceProvider).getLastSequenceNumber();
491 // when replicatedToAllIndex = -1
492 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
494 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
496 snapshotManager.commit(100L, 0);
498 snapshotManager.commit(100L, 0);
500 verify(mockReplicatedLog, times(1)).snapshotCommit();
502 verify(mockDataPersistenceProvider, times(1)).deleteMessages(50L);
504 verify(mockDataPersistenceProvider, times(1)).deleteSnapshots(any(SnapshotSelectionCriteria.class));
508 public void testRollback() {
509 // when replicatedToAllIndex = -1
510 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
512 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
514 snapshotManager.rollback();
516 verify(mockReplicatedLog).snapshotRollback();
518 MessageCollectorActor.expectFirstMatching(actorRef, SnapshotComplete.class);
523 public void testRollbackBeforePersist() {
524 // when replicatedToAllIndex = -1
525 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
527 snapshotManager.rollback();
529 verify(mockReplicatedLog, never()).snapshotRollback();
533 public void testRollbackBeforeCapture() {
534 snapshotManager.rollback();
536 verify(mockReplicatedLog, never()).snapshotRollback();
540 public void testCallingRollbackMultipleTimesCausesNoHarm() {
541 // when replicatedToAllIndex = -1
542 snapshotManager.capture(new SimpleReplicatedLogEntry(9, 6, new MockRaftActorContext.MockPayload()), -1);
544 snapshotManager.persist(ByteState.empty(), Optional.empty(), Runtime.getRuntime().totalMemory());
546 snapshotManager.rollback();
548 snapshotManager.rollback();
550 verify(mockReplicatedLog, times(1)).snapshotRollback();
554 public void testTrimLogWhenTrimIndexLessThanLastApplied() {
555 doReturn(20L).when(mockRaftActorContext).getLastApplied();
557 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
558 doReturn(true).when(mockReplicatedLog).isPresent(10);
559 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
560 doReturn(5L).when(replicatedLogEntry).getTerm();
562 long retIndex = snapshotManager.trimLog(10);
563 assertEquals("return index", 10L, retIndex);
565 verify(mockReplicatedLog).snapshotPreCommit(10, 5);
566 verify(mockReplicatedLog).snapshotCommit();
568 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
572 public void testTrimLogWhenLastAppliedNotSet() {
573 doReturn(-1L).when(mockRaftActorContext).getLastApplied();
575 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
576 doReturn(true).when(mockReplicatedLog).isPresent(10);
577 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
578 doReturn(5L).when(replicatedLogEntry).getTerm();
580 long retIndex = snapshotManager.trimLog(10);
581 assertEquals("return index", -1L, retIndex);
583 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
584 verify(mockReplicatedLog, never()).snapshotCommit();
586 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
590 public void testTrimLogWhenLastAppliedZero() {
591 doReturn(0L).when(mockRaftActorContext).getLastApplied();
593 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
594 doReturn(true).when(mockReplicatedLog).isPresent(10);
595 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
596 doReturn(5L).when(replicatedLogEntry).getTerm();
598 long retIndex = snapshotManager.trimLog(10);
599 assertEquals("return index", -1L, retIndex);
601 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
602 verify(mockReplicatedLog, never()).snapshotCommit();
604 verify(mockRaftActorBehavior, never()).setReplicatedToAllIndex(anyLong());
608 public void testTrimLogWhenTrimIndexNotPresent() {
609 doReturn(20L).when(mockRaftActorContext).getLastApplied();
611 doReturn(false).when(mockReplicatedLog).isPresent(10);
613 long retIndex = snapshotManager.trimLog(10);
614 assertEquals("return index", -1L, retIndex);
616 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
617 verify(mockReplicatedLog, never()).snapshotCommit();
619 // Trim index is greater than replicatedToAllIndex so should update it.
620 verify(mockRaftActorBehavior).setReplicatedToAllIndex(10L);
624 public void testTrimLogAfterCapture() {
625 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
626 new MockRaftActorContext.MockPayload()), 9);
630 assertEquals(true, snapshotManager.isCapturing());
632 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
633 doReturn(20L).when(mockRaftActorContext).getLastApplied();
634 doReturn(true).when(mockReplicatedLog).isPresent(10);
635 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
636 doReturn(5L).when(replicatedLogEntry).getTerm();
638 snapshotManager.trimLog(10);
640 verify(mockReplicatedLog, never()).snapshotPreCommit(anyLong(), anyLong());
641 verify(mockReplicatedLog, never()).snapshotCommit();
646 public void testTrimLogAfterCaptureToInstall() {
647 boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1,
648 new MockRaftActorContext.MockPayload()), 9);
652 assertEquals(true, snapshotManager.isCapturing());
654 ReplicatedLogEntry replicatedLogEntry = mock(ReplicatedLogEntry.class);
655 doReturn(20L).when(mockRaftActorContext).getLastApplied();
656 doReturn(true).when(mockReplicatedLog).isPresent(10);
657 doReturn(replicatedLogEntry).when(mockReplicatedLog).get(10);
658 doReturn(5L).when(replicatedLogEntry).getTerm();
660 snapshotManager.trimLog(10);
662 verify(mockReplicatedLog, never()).snapshotPreCommit(10, 5);
663 verify(mockReplicatedLog, never()).snapshotCommit();
668 public void testLastAppliedTermInformationReader() {
670 LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
672 doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
673 doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
675 ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L,
676 new MockRaftActorContext.MockPayload());
678 // No followers and valid lastLogEntry
679 reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
681 assertEquals("getTerm", 6L, reader.getTerm());
682 assertEquals("getIndex", 9L, reader.getIndex());
684 // No followers and null lastLogEntry
685 reader.init(mockReplicatedLog, 1L, null, false);
687 assertEquals("getTerm", -1L, reader.getTerm());
688 assertEquals("getIndex", -1L, reader.getIndex());
690 // Followers and valid originalIndex entry
691 doReturn(new SimpleReplicatedLogEntry(8L, 5L,
692 new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
693 reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
695 assertEquals("getTerm", 5L, reader.getTerm());
696 assertEquals("getIndex", 8L, reader.getIndex());
698 // Followers and null originalIndex entry and valid snapshot index
699 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
701 assertEquals("getTerm", 4L, reader.getTerm());
702 assertEquals("getIndex", 7L, reader.getIndex());
704 // Followers and null originalIndex entry and invalid snapshot index
705 doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
706 reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
708 assertEquals("getTerm", -1L, reader.getTerm());
709 assertEquals("getIndex", -1L, reader.getIndex());