Merge "Address comment in gerrit 17266"
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / RaftActorRecoverySupportTest.java
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.raft;
9
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;
34
35 /**
36  * Unit tests for RaftActorRecoverySupport.
37  *
38  * @author Thomas Pantelis
39  */
40 public class RaftActorRecoverySupportTest {
41
42     private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
43
44     @Mock
45     private DataPersistenceProvider mockPersistence;
46
47     @Mock
48     private RaftActorBehavior mockBehavior;
49
50     @Mock
51     private RaftActorRecoveryCohort mockCohort;
52
53     private RaftActorRecoverySupport support;
54
55     private RaftActorContext context;
56     private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
57
58     @Before
59     public void setup() {
60         MockitoAnnotations.initMocks(this);
61
62         context = new RaftActorContextImpl(null, null, "test", new ElectionTermImpl(mockPersistence, "test", LOG),
63                 -1, -1, Collections.<String,String>emptyMap(), configParams, mockPersistence, LOG);
64
65         support = new RaftActorRecoverySupport(mockPersistence, context , mockBehavior, mockCohort);
66
67         doReturn(true).when(mockPersistence).isRecoveryApplicable();
68
69         context.setReplicatedLog(ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior));
70     }
71
72     private void sendMessageToSupport(Object message) {
73         sendMessageToSupport(message, false);
74     }
75
76     private void sendMessageToSupport(Object message, boolean expComplete) {
77         boolean complete = support.handleRecoveryMessage(message);
78         assertEquals("complete", expComplete, complete);
79     }
80
81     @Test
82     public void testOnReplicatedLogEntry() {
83         MockRaftActorContext.MockReplicatedLogEntry logEntry = new MockRaftActorContext.MockReplicatedLogEntry(1,
84                 1, new MockRaftActorContext.MockPayload("1", 5));
85
86         sendMessageToSupport(logEntry);
87
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());
95     }
96
97     @Test
98     public void testOnApplyJournalEntries() {
99         configParams.setJournalRecoveryLogBatchSize(5);
100
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")));
114
115         sendMessageToSupport(new ApplyJournalEntries(2));
116
117         assertEquals("Last applied", 2, context.getLastApplied());
118         assertEquals("Commit index", 2, context.getCommitIndex());
119
120         sendMessageToSupport(new ApplyJournalEntries(4));
121
122         assertEquals("Last applied", 4, context.getLastApplied());
123         assertEquals("Last applied", 4, context.getLastApplied());
124
125         sendMessageToSupport(new ApplyJournalEntries(5));
126
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());
132
133         InOrder inOrder = Mockito.inOrder(mockCohort);
134         inOrder.verify(mockCohort).startLogRecoveryBatch(5);
135
136         for(int i = 0; i < replicatedLog.size() - 1; i++) {
137             inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData());
138         }
139
140         inOrder.verify(mockCohort).applyCurrentLogRecoveryBatch();
141         inOrder.verify(mockCohort).startLogRecoveryBatch(5);
142         inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(replicatedLog.size() - 1).getData());
143
144         inOrder.verifyNoMoreInteractions();
145     }
146
147     @Test
148     public void testOnApplyLogEntries() {
149         ReplicatedLog replicatedLog = context.getReplicatedLog();
150         replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,
151                 0, new MockRaftActorContext.MockPayload("0")));
152
153         sendMessageToSupport(new ApplyLogEntries(0));
154
155         assertEquals("Last applied", 0, context.getLastApplied());
156         assertEquals("Commit index", 0, context.getCommitIndex());
157     }
158
159     @Test
160     public void testOnSnapshotOffer() {
161
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")));
169
170         byte[] snapshotBytes = {1,2,3,4,5};
171
172         ReplicatedLogEntry unAppliedEntry1 = new MockRaftActorContext.MockReplicatedLogEntry(1,
173                 4, new MockRaftActorContext.MockPayload("4", 4));
174
175         ReplicatedLogEntry unAppliedEntry2 = new MockRaftActorContext.MockReplicatedLogEntry(1,
176                 5, new MockRaftActorContext.MockPayload("5", 5));
177
178         int lastAppliedDuringSnapshotCapture = 3;
179         int lastIndexDuringSnapshotCapture = 5;
180
181         Snapshot snapshot = Snapshot.create(snapshotBytes, Arrays.asList(unAppliedEntry1, unAppliedEntry2),
182                 lastIndexDuringSnapshotCapture, 1, lastAppliedDuringSnapshotCapture, 1);
183
184         SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345);
185         SnapshotOffer snapshotOffer = new SnapshotOffer(metadata , snapshot);
186
187         sendMessageToSupport(snapshotOffer);
188
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());
196
197         verify(mockCohort).applyRecoverySnapshot(snapshotBytes);
198     }
199
200     @Test
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")));
207
208         sendMessageToSupport(new ApplyJournalEntries(1));
209
210         sendMessageToSupport(RecoveryCompleted.getInstance(), true);
211
212         assertEquals("Last applied", 1, context.getLastApplied());
213         assertEquals("Commit index", 1, context.getCommitIndex());
214
215         InOrder inOrder = Mockito.inOrder(mockCohort);
216         inOrder.verify(mockCohort).startLogRecoveryBatch(anyInt());
217
218         for(int i = 0; i < replicatedLog.size(); i++) {
219             inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData());
220         }
221
222         inOrder.verify(mockCohort).applyCurrentLogRecoveryBatch();
223
224         inOrder.verifyNoMoreInteractions();
225     }
226
227     @Test
228     public void testOnRecoveryCompletedWithNoRemainingBatch() {
229         sendMessageToSupport(RecoveryCompleted.getInstance(), true);
230
231         verifyNoMoreInteractions(mockCohort);
232     }
233
234     @Test
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")));
243
244         sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(1));
245
246         assertEquals("Journal log size", 1, context.getReplicatedLog().size());
247         assertEquals("Last index", 0, context.getReplicatedLog().lastIndex());
248     }
249
250     @Test
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")));
259
260         sendMessageToSupport(new DeleteEntries(1));
261
262         assertEquals("Journal log size", 1, context.getReplicatedLog().size());
263         assertEquals("Last index", 0, context.getReplicatedLog().lastIndex());
264     }
265
266     @Test
267     public void testUpdateElectionTerm() {
268
269         sendMessageToSupport(new UpdateElectionTerm(5, "member2"));
270
271         assertEquals("Current term", 5, context.getTermInformation().getCurrentTerm());
272         assertEquals("Voted For", "member2", context.getTermInformation().getVotedFor());
273     }
274
275     @Test
276     public void testRecoveryWithPersistenceDisabled() {
277         doReturn(false).when(mockPersistence).isRecoveryApplicable();
278
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);
281
282         sendMessageToSupport(snapshotOffer);
283
284         sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1,
285                 4, new MockRaftActorContext.MockPayload("4")));
286         sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1,
287                 5, new MockRaftActorContext.MockPayload("5")));
288
289         sendMessageToSupport(new ApplyJournalEntries(4));
290
291         sendMessageToSupport(new DeleteEntries(5));
292
293         sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(5));
294
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());
301
302         sendMessageToSupport(new UpdateElectionTerm(5, "member2"));
303
304         assertEquals("Current term", 0, context.getTermInformation().getCurrentTerm());
305         assertEquals("Voted For", null, context.getTermInformation().getVotedFor());
306
307         sendMessageToSupport(RecoveryCompleted.getInstance(), true);
308
309         verifyNoMoreInteractions(mockCohort);
310     }
311 }