2 * Copyright (c) 2015 Brocade Communications 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.assertEquals;
11 import static org.mockito.Matchers.anyInt;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.verifyNoMoreInteractions;
15 import akka.persistence.RecoveryCompleted;
16 import akka.persistence.SnapshotMetadata;
17 import akka.persistence.SnapshotOffer;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.mockito.InOrder;
23 import org.mockito.Mock;
24 import org.mockito.Mockito;
25 import org.mockito.MockitoAnnotations;
26 import org.opendaylight.controller.cluster.DataPersistenceProvider;
27 import org.opendaylight.controller.cluster.raft.RaftActor.UpdateElectionTerm;
28 import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries;
29 import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries;
30 import org.opendaylight.controller.cluster.raft.base.messages.DeleteEntries;
31 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * Unit tests for RaftActorRecoverySupport.
38 * @author Thomas Pantelis
40 public class RaftActorRecoverySupportTest {
42 private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
45 private DataPersistenceProvider mockPersistence;
48 private RaftActorBehavior mockBehavior;
51 private RaftActorRecoveryCohort mockCohort;
53 private RaftActorRecoverySupport support;
55 private RaftActorContext context;
56 private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
60 MockitoAnnotations.initMocks(this);
62 context = new RaftActorContextImpl(null, null, "test", new ElectionTermImpl(mockPersistence, "test", LOG),
63 -1, -1, Collections.<String,String>emptyMap(), configParams, mockPersistence, LOG);
65 support = new RaftActorRecoverySupport(mockPersistence, context , mockBehavior, mockCohort);
67 doReturn(true).when(mockPersistence).isRecoveryApplicable();
69 context.setReplicatedLog(ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior));
72 private void sendMessageToSupport(Object message) {
73 sendMessageToSupport(message, false);
76 private void sendMessageToSupport(Object message, boolean expComplete) {
77 boolean complete = support.handleRecoveryMessage(message);
78 assertEquals("complete", expComplete, complete);
82 public void testOnReplicatedLogEntry() {
83 MockRaftActorContext.MockReplicatedLogEntry logEntry = new MockRaftActorContext.MockReplicatedLogEntry(1,
84 1, new MockRaftActorContext.MockPayload("1", 5));
86 sendMessageToSupport(logEntry);
88 assertEquals("Journal log size", 1, context.getReplicatedLog().size());
89 assertEquals("Journal data size", 5, context.getReplicatedLog().dataSize());
90 assertEquals("Last index", 1, context.getReplicatedLog().lastIndex());
91 assertEquals("Last applied", -1, context.getLastApplied());
92 assertEquals("Commit index", -1, context.getCommitIndex());
93 assertEquals("Snapshot term", -1, context.getReplicatedLog().getSnapshotTerm());
94 assertEquals("Snapshot index", -1, context.getReplicatedLog().getSnapshotIndex());
98 public void testOnApplyJournalEntries() {
99 configParams.setJournalRecoveryLogBatchSize(5);
101 ReplicatedLog replicatedLog = context.getReplicatedLog();
102 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
103 0, new MockRaftActorContext.MockPayload("0")));
104 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
105 1, new MockRaftActorContext.MockPayload("1")));
106 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
107 2, new MockRaftActorContext.MockPayload("2")));
108 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
109 3, new MockRaftActorContext.MockPayload("3")));
110 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
111 4, new MockRaftActorContext.MockPayload("4")));
112 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
113 5, new MockRaftActorContext.MockPayload("5")));
115 sendMessageToSupport(new ApplyJournalEntries(2));
117 assertEquals("Last applied", 2, context.getLastApplied());
118 assertEquals("Commit index", 2, context.getCommitIndex());
120 sendMessageToSupport(new ApplyJournalEntries(4));
122 assertEquals("Last applied", 4, context.getLastApplied());
123 assertEquals("Last applied", 4, context.getLastApplied());
125 sendMessageToSupport(new ApplyJournalEntries(5));
127 assertEquals("Last index", 5, context.getReplicatedLog().lastIndex());
128 assertEquals("Last applied", 5, context.getLastApplied());
129 assertEquals("Commit index", 5, context.getCommitIndex());
130 assertEquals("Snapshot term", -1, context.getReplicatedLog().getSnapshotTerm());
131 assertEquals("Snapshot index", -1, context.getReplicatedLog().getSnapshotIndex());
133 InOrder inOrder = Mockito.inOrder(mockCohort);
134 inOrder.verify(mockCohort).startLogRecoveryBatch(5);
136 for(int i = 0; i < replicatedLog.size() - 1; i++) {
137 inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData());
140 inOrder.verify(mockCohort).applyCurrentLogRecoveryBatch();
141 inOrder.verify(mockCohort).startLogRecoveryBatch(5);
142 inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(replicatedLog.size() - 1).getData());
144 inOrder.verifyNoMoreInteractions();
148 public void testOnApplyLogEntries() {
149 ReplicatedLog replicatedLog = context.getReplicatedLog();
150 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
151 0, new MockRaftActorContext.MockPayload("0")));
153 sendMessageToSupport(new ApplyLogEntries(0));
155 assertEquals("Last applied", 0, context.getLastApplied());
156 assertEquals("Commit index", 0, context.getCommitIndex());
160 public void testOnSnapshotOffer() {
162 ReplicatedLog replicatedLog = context.getReplicatedLog();
163 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
164 1, new MockRaftActorContext.MockPayload("1")));
165 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
166 2, new MockRaftActorContext.MockPayload("2")));
167 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
168 3, new MockRaftActorContext.MockPayload("3")));
170 byte[] snapshotBytes = {1,2,3,4,5};
172 ReplicatedLogEntry unAppliedEntry1 = new MockRaftActorContext.MockReplicatedLogEntry(1,
173 4, new MockRaftActorContext.MockPayload("4", 4));
175 ReplicatedLogEntry unAppliedEntry2 = new MockRaftActorContext.MockReplicatedLogEntry(1,
176 5, new MockRaftActorContext.MockPayload("5", 5));
178 int lastAppliedDuringSnapshotCapture = 3;
179 int lastIndexDuringSnapshotCapture = 5;
181 Snapshot snapshot = Snapshot.create(snapshotBytes, Arrays.asList(unAppliedEntry1, unAppliedEntry2),
182 lastIndexDuringSnapshotCapture, 1, lastAppliedDuringSnapshotCapture, 1);
184 SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345);
185 SnapshotOffer snapshotOffer = new SnapshotOffer(metadata , snapshot);
187 sendMessageToSupport(snapshotOffer);
189 assertEquals("Journal log size", 2, context.getReplicatedLog().size());
190 assertEquals("Journal data size", 9, context.getReplicatedLog().dataSize());
191 assertEquals("Last index", lastIndexDuringSnapshotCapture, context.getReplicatedLog().lastIndex());
192 assertEquals("Last applied", lastAppliedDuringSnapshotCapture, context.getLastApplied());
193 assertEquals("Commit index", lastAppliedDuringSnapshotCapture, context.getCommitIndex());
194 assertEquals("Snapshot term", 1, context.getReplicatedLog().getSnapshotTerm());
195 assertEquals("Snapshot index", lastAppliedDuringSnapshotCapture, context.getReplicatedLog().getSnapshotIndex());
197 verify(mockCohort).applyRecoverySnapshot(snapshotBytes);
201 public void testOnRecoveryCompletedWithRemainingBatch() {
202 ReplicatedLog replicatedLog = context.getReplicatedLog();
203 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
204 0, new MockRaftActorContext.MockPayload("0")));
205 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
206 1, new MockRaftActorContext.MockPayload("1")));
208 sendMessageToSupport(new ApplyJournalEntries(1));
210 sendMessageToSupport(RecoveryCompleted.getInstance(), true);
212 assertEquals("Last applied", 1, context.getLastApplied());
213 assertEquals("Commit index", 1, context.getCommitIndex());
215 InOrder inOrder = Mockito.inOrder(mockCohort);
216 inOrder.verify(mockCohort).startLogRecoveryBatch(anyInt());
218 for(int i = 0; i < replicatedLog.size(); i++) {
219 inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData());
222 inOrder.verify(mockCohort).applyCurrentLogRecoveryBatch();
224 inOrder.verifyNoMoreInteractions();
228 public void testOnRecoveryCompletedWithNoRemainingBatch() {
229 sendMessageToSupport(RecoveryCompleted.getInstance(), true);
231 verifyNoMoreInteractions(mockCohort);
235 public void testOnDeprecatedDeleteEntries() {
236 ReplicatedLog replicatedLog = context.getReplicatedLog();
237 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
238 0, new MockRaftActorContext.MockPayload("0")));
239 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
240 1, new MockRaftActorContext.MockPayload("1")));
241 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
242 2, new MockRaftActorContext.MockPayload("2")));
244 sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(1));
246 assertEquals("Journal log size", 1, context.getReplicatedLog().size());
247 assertEquals("Last index", 0, context.getReplicatedLog().lastIndex());
251 public void testOnDeleteEntries() {
252 ReplicatedLog replicatedLog = context.getReplicatedLog();
253 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
254 0, new MockRaftActorContext.MockPayload("0")));
255 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
256 1, new MockRaftActorContext.MockPayload("1")));
257 replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
258 2, new MockRaftActorContext.MockPayload("2")));
260 sendMessageToSupport(new DeleteEntries(1));
262 assertEquals("Journal log size", 1, context.getReplicatedLog().size());
263 assertEquals("Last index", 0, context.getReplicatedLog().lastIndex());
267 public void testUpdateElectionTerm() {
269 sendMessageToSupport(new UpdateElectionTerm(5, "member2"));
271 assertEquals("Current term", 5, context.getTermInformation().getCurrentTerm());
272 assertEquals("Voted For", "member2", context.getTermInformation().getVotedFor());
276 public void testRecoveryWithPersistenceDisabled() {
277 doReturn(false).when(mockPersistence).isRecoveryApplicable();
279 Snapshot snapshot = Snapshot.create(new byte[]{1}, Collections.<ReplicatedLogEntry>emptyList(), 3, 1, 3, 1);
280 SnapshotOffer snapshotOffer = new SnapshotOffer(new SnapshotMetadata("test", 6, 12345), snapshot);
282 sendMessageToSupport(snapshotOffer);
284 sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1,
285 4, new MockRaftActorContext.MockPayload("4")));
286 sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1,
287 5, new MockRaftActorContext.MockPayload("5")));
289 sendMessageToSupport(new ApplyJournalEntries(4));
291 sendMessageToSupport(new DeleteEntries(5));
293 sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(5));
295 assertEquals("Journal log size", 0, context.getReplicatedLog().size());
296 assertEquals("Last index", -1, context.getReplicatedLog().lastIndex());
297 assertEquals("Last applied", -1, context.getLastApplied());
298 assertEquals("Commit index", -1, context.getCommitIndex());
299 assertEquals("Snapshot term", -1, context.getReplicatedLog().getSnapshotTerm());
300 assertEquals("Snapshot index", -1, context.getReplicatedLog().getSnapshotIndex());
302 sendMessageToSupport(new UpdateElectionTerm(5, "member2"));
304 assertEquals("Current term", 0, context.getTermInformation().getCurrentTerm());
305 assertEquals("Voted For", null, context.getTermInformation().getVotedFor());
307 sendMessageToSupport(RecoveryCompleted.getInstance(), true);
309 verifyNoMoreInteractions(mockCohort);