Merge "Bug 2820 - problem to add second TLV with type 127."
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / AbstractReplicatedLogImplTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.controller.cluster.raft;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import akka.japi.Procedure;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import org.junit.Assert;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
23 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
24
25 /**
26 *
27 */
28 public class AbstractReplicatedLogImplTest {
29
30     private MockAbstractReplicatedLogImpl replicatedLogImpl;
31
32     @Before
33     public void setUp() {
34         replicatedLogImpl = new MockAbstractReplicatedLogImpl();
35         // create a set of initial entries in the in-memory log
36         replicatedLogImpl.append(new MockReplicatedLogEntry(1, 0, new MockPayload("A")));
37         replicatedLogImpl.append(new MockReplicatedLogEntry(1, 1, new MockPayload("B")));
38         replicatedLogImpl.append(new MockReplicatedLogEntry(1, 2, new MockPayload("C")));
39         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 3, new MockPayload("D")));
40
41     }
42
43     @Test
44     public void testEmptyLog() {
45         replicatedLogImpl = new MockAbstractReplicatedLogImpl();
46
47         assertEquals("size", 0, replicatedLogImpl.size());
48         assertEquals("dataSize", 0, replicatedLogImpl.dataSize());
49         assertEquals("getSnapshotIndex", -1, replicatedLogImpl.getSnapshotIndex());
50         assertEquals("getSnapshotTerm", -1, replicatedLogImpl.getSnapshotTerm());
51         assertEquals("lastIndex", -1, replicatedLogImpl.lastIndex());
52         assertEquals("lastTerm", -1, replicatedLogImpl.lastTerm());
53         assertEquals("isPresent", false, replicatedLogImpl.isPresent(0));
54         assertEquals("isInSnapshot", false, replicatedLogImpl.isInSnapshot(0));
55         Assert.assertNull("get(0)", replicatedLogImpl.get(0));
56         Assert.assertNull("last", replicatedLogImpl.last());
57
58         List<ReplicatedLogEntry> list = replicatedLogImpl.getFrom(0, 1);
59         assertEquals("getFrom size", 0, list.size());
60
61         assertEquals("removeFrom", -1, replicatedLogImpl.removeFrom(1));
62
63         replicatedLogImpl.setSnapshotIndex(2);
64         replicatedLogImpl.setSnapshotTerm(1);
65
66         assertEquals("getSnapshotIndex", 2, replicatedLogImpl.getSnapshotIndex());
67         assertEquals("getSnapshotTerm", 1, replicatedLogImpl.getSnapshotTerm());
68         assertEquals("lastIndex", 2, replicatedLogImpl.lastIndex());
69         assertEquals("lastTerm", 1, replicatedLogImpl.lastTerm());
70     }
71
72     @Test
73     public void testIndexOperations() {
74
75         // check if the values returned are correct, with snapshotIndex = -1
76         assertEquals("B", replicatedLogImpl.get(1).getData().toString());
77         assertEquals("D", replicatedLogImpl.last().getData().toString());
78         assertEquals(3, replicatedLogImpl.lastIndex());
79         assertEquals(2, replicatedLogImpl.lastTerm());
80         assertEquals(2, replicatedLogImpl.getFrom(2).size());
81         assertEquals(4, replicatedLogImpl.size());
82         assertTrue(replicatedLogImpl.isPresent(2));
83         assertFalse(replicatedLogImpl.isPresent(4));
84         assertFalse(replicatedLogImpl.isInSnapshot(2));
85
86         // now create a snapshot of 3 entries, with 1 unapplied entry left in the log
87         // It removes the entries which have made it to snapshot
88         // and updates the snapshot index and term
89         takeSnapshot(3);
90
91         // check the values after the snapshot.
92         // each index value passed in the test is the logical index (log entry index)
93         // which gets mapped to the list's physical index
94         assertEquals("D", replicatedLogImpl.get(3).getData().toString());
95         assertEquals("D", replicatedLogImpl.last().getData().toString());
96         assertNull(replicatedLogImpl.get(1));
97         assertEquals(3, replicatedLogImpl.lastIndex());
98         assertEquals(2, replicatedLogImpl.lastTerm());
99         assertEquals(0, replicatedLogImpl.getFrom(2).size());
100         assertEquals(1, replicatedLogImpl.size());
101         assertFalse(replicatedLogImpl.isPresent(2));
102         assertTrue(replicatedLogImpl.isPresent(3));
103         assertFalse(replicatedLogImpl.isPresent(4));
104         assertTrue(replicatedLogImpl.isInSnapshot(2));
105
106         // append few more entries
107         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
108         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
109         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
110         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
111
112         // check their values as well
113         assertEquals(5, replicatedLogImpl.size());
114         assertEquals("D", replicatedLogImpl.get(3).getData().toString());
115         assertEquals("E", replicatedLogImpl.get(4).getData().toString());
116         assertEquals("H", replicatedLogImpl.last().getData().toString());
117         assertEquals(3, replicatedLogImpl.lastTerm());
118         assertEquals(7, replicatedLogImpl.lastIndex());
119         assertTrue(replicatedLogImpl.isPresent(7));
120         assertFalse(replicatedLogImpl.isInSnapshot(7));
121         assertEquals(1, replicatedLogImpl.getFrom(7).size());
122         assertEquals(2, replicatedLogImpl.getFrom(6).size());
123
124         // take a second snapshot with 5 entries with 0 unapplied entries left in the log
125         takeSnapshot(5);
126
127         assertEquals(0, replicatedLogImpl.size());
128         assertNull(replicatedLogImpl.last());
129         assertNull(replicatedLogImpl.get(7));
130         assertNull(replicatedLogImpl.get(1));
131         assertFalse(replicatedLogImpl.isPresent(7));
132         assertTrue(replicatedLogImpl.isInSnapshot(7));
133         assertEquals(0, replicatedLogImpl.getFrom(7).size());
134         assertEquals(0, replicatedLogImpl.getFrom(6).size());
135
136     }
137
138     @Test
139     public void testGetFromWithMax(){
140         List<ReplicatedLogEntry> from = replicatedLogImpl.getFrom(0, 1);
141         Assert.assertEquals(1, from.size());
142         Assert.assertEquals(1, from.get(0).getTerm());
143
144         from = replicatedLogImpl.getFrom(0, 20);
145         Assert.assertEquals(4, from.size());
146         Assert.assertEquals(2, from.get(3).getTerm());
147
148         from = replicatedLogImpl.getFrom(1, 2);
149         Assert.assertEquals(2, from.size());
150         Assert.assertEquals(1, from.get(1).getTerm());
151
152     }
153
154     @Test
155     public void testSnapshotPreCommit() {
156         //add 4 more entries
157         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
158         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
159         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
160         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
161
162         //sending negative values should not cause any changes
163         replicatedLogImpl.snapshotPreCommit(-1, -1);
164         assertEquals(8, replicatedLogImpl.size());
165         assertEquals(-1, replicatedLogImpl.getSnapshotIndex());
166         assertEquals(-1, replicatedLogImpl.getSnapshotTerm());
167
168         replicatedLogImpl.snapshotPreCommit(4, 2);
169         assertEquals(3, replicatedLogImpl.size());
170         assertEquals(4, replicatedLogImpl.getSnapshotIndex());
171         assertEquals(2, replicatedLogImpl.getSnapshotTerm());
172
173         replicatedLogImpl.snapshotPreCommit(6, 3);
174         assertEquals(1, replicatedLogImpl.size());
175         assertEquals(6, replicatedLogImpl.getSnapshotIndex());
176         assertEquals(3, replicatedLogImpl.getSnapshotTerm());
177
178         replicatedLogImpl.snapshotPreCommit(7, 3);
179         assertEquals(0, replicatedLogImpl.size());
180         assertEquals(7, replicatedLogImpl.getSnapshotIndex());
181         assertEquals(3, replicatedLogImpl.getSnapshotTerm());
182
183         //running it again on an empty list should not throw exception
184         replicatedLogImpl.snapshotPreCommit(7, 3);
185         assertEquals(0, replicatedLogImpl.size());
186         assertEquals(7, replicatedLogImpl.getSnapshotIndex());
187         assertEquals(3, replicatedLogImpl.getSnapshotTerm());
188     }
189
190     @Test
191     public void testSnapshotCommit() {
192
193         replicatedLogImpl.snapshotPreCommit(1, 1);
194
195         replicatedLogImpl.snapshotCommit();
196
197         assertEquals("size", 2, replicatedLogImpl.size());
198         assertEquals("dataSize", 2, replicatedLogImpl.dataSize());
199         assertEquals("getSnapshotIndex", 1, replicatedLogImpl.getSnapshotIndex());
200         assertEquals("getSnapshotTerm", 1, replicatedLogImpl.getSnapshotTerm());
201         assertEquals("lastIndex", 3, replicatedLogImpl.lastIndex());
202         assertEquals("lastTerm", 2, replicatedLogImpl.lastTerm());
203
204         Assert.assertNull("get(0)", replicatedLogImpl.get(0));
205         Assert.assertNull("get(1)", replicatedLogImpl.get(1));
206         Assert.assertNotNull("get(2)", replicatedLogImpl.get(2));
207         Assert.assertNotNull("get(3)", replicatedLogImpl.get(3));
208     }
209
210     @Test
211     public void testSnapshotRollback() {
212
213         replicatedLogImpl.snapshotPreCommit(1, 1);
214
215         assertEquals("size", 2, replicatedLogImpl.size());
216         assertEquals("getSnapshotIndex", 1, replicatedLogImpl.getSnapshotIndex());
217         assertEquals("getSnapshotTerm", 1, replicatedLogImpl.getSnapshotTerm());
218
219         replicatedLogImpl.snapshotRollback();
220
221         assertEquals("size", 4, replicatedLogImpl.size());
222         assertEquals("dataSize", 4, replicatedLogImpl.dataSize());
223         assertEquals("getSnapshotIndex", -1, replicatedLogImpl.getSnapshotIndex());
224         assertEquals("getSnapshotTerm", -1, replicatedLogImpl.getSnapshotTerm());
225         Assert.assertNotNull("get(0)", replicatedLogImpl.get(0));
226         Assert.assertNotNull("get(3)", replicatedLogImpl.get(3));
227     }
228
229     @Test
230     public void testIsPresent() {
231         assertTrue(replicatedLogImpl.isPresent(0));
232         assertTrue(replicatedLogImpl.isPresent(1));
233         assertTrue(replicatedLogImpl.isPresent(2));
234         assertTrue(replicatedLogImpl.isPresent(3));
235
236         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("D")));
237         replicatedLogImpl.snapshotPreCommit(3, 2); //snapshot on 3
238         replicatedLogImpl.snapshotCommit();
239
240         assertFalse(replicatedLogImpl.isPresent(0));
241         assertFalse(replicatedLogImpl.isPresent(1));
242         assertFalse(replicatedLogImpl.isPresent(2));
243         assertFalse(replicatedLogImpl.isPresent(3));
244         assertTrue(replicatedLogImpl.isPresent(4));
245
246         replicatedLogImpl.snapshotPreCommit(4, 2); //snapshot on 4
247         replicatedLogImpl.snapshotCommit();
248         assertFalse(replicatedLogImpl.isPresent(4));
249
250         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("D")));
251         assertTrue(replicatedLogImpl.isPresent(5));
252     }
253
254     @Test
255     public void testRemoveFrom() {
256
257         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E", 2)));
258         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F", 3)));
259
260         assertEquals("dataSize", 9, replicatedLogImpl.dataSize());
261
262         long adjusted = replicatedLogImpl.removeFrom(4);
263         assertEquals("removeFrom - adjusted", 4, adjusted);
264         assertEquals("size", 4, replicatedLogImpl.size());
265         assertEquals("dataSize", 4, replicatedLogImpl.dataSize());
266
267         takeSnapshot(1);
268
269         adjusted = replicatedLogImpl.removeFrom(2);
270         assertEquals("removeFrom - adjusted", 1, adjusted);
271         assertEquals("size", 1, replicatedLogImpl.size());
272         assertEquals("dataSize", 1, replicatedLogImpl.dataSize());
273
274         assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(0));
275         assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(100));
276     }
277
278     // create a snapshot for test
279     public Map<Long, String> takeSnapshot(final int numEntries) {
280         Map<Long, String> map = new HashMap<>(numEntries);
281
282         long lastIndex = 0;
283         long lastTerm = 0;
284         for(int i = 0; i < numEntries; i++) {
285             ReplicatedLogEntry entry = replicatedLogImpl.getAtPhysicalIndex(i);
286             map.put(entry.getIndex(), entry.getData().toString());
287             lastIndex = entry.getIndex();
288             lastTerm = entry.getTerm();
289         }
290
291         replicatedLogImpl.snapshotPreCommit(lastIndex, lastTerm);
292         replicatedLogImpl.snapshotCommit();
293
294         return map;
295
296     }
297     class MockAbstractReplicatedLogImpl extends AbstractReplicatedLogImpl {
298         @Override
299         public void appendAndPersist(final ReplicatedLogEntry replicatedLogEntry) {
300         }
301
302         @Override
303         public void removeFromAndPersist(final long index) {
304         }
305
306         @Override
307         public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry, Procedure<ReplicatedLogEntry> callback) {
308         }
309     }
310 }