2 * Copyright (c) 2014 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
8 package org.opendaylight.controller.cluster.raft;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import akka.japi.Procedure;
15 import java.util.HashMap;
16 import java.util.List;
18 import org.junit.Assert;
19 import org.junit.Before;
20 import org.junit.Test;
21 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
22 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
27 public class AbstractReplicatedLogImplTest {
29 private MockAbstractReplicatedLogImpl replicatedLogImpl;
33 replicatedLogImpl = new MockAbstractReplicatedLogImpl();
34 // create a set of initial entries in the in-memory log
35 replicatedLogImpl.append(new MockReplicatedLogEntry(1, 0, new MockPayload("A")));
36 replicatedLogImpl.append(new MockReplicatedLogEntry(1, 1, new MockPayload("B")));
37 replicatedLogImpl.append(new MockReplicatedLogEntry(1, 2, new MockPayload("C")));
38 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 3, new MockPayload("D")));
43 public void testIndexOperations() {
45 // check if the values returned are correct, with snapshotIndex = -1
46 assertEquals("B", replicatedLogImpl.get(1).getData().toString());
47 assertEquals("D", replicatedLogImpl.last().getData().toString());
48 assertEquals(3, replicatedLogImpl.lastIndex());
49 assertEquals(2, replicatedLogImpl.lastTerm());
50 assertEquals(2, replicatedLogImpl.getFrom(2).size());
51 assertEquals(4, replicatedLogImpl.size());
52 assertTrue(replicatedLogImpl.isPresent(2));
53 assertFalse(replicatedLogImpl.isPresent(4));
54 assertFalse(replicatedLogImpl.isInSnapshot(2));
56 // now create a snapshot of 3 entries, with 1 unapplied entry left in the log
57 // It removes the entries which have made it to snapshot
58 // and updates the snapshot index and term
61 // check the values after the snapshot.
62 // each index value passed in the test is the logical index (log entry index)
63 // which gets mapped to the list's physical index
64 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
65 assertEquals("D", replicatedLogImpl.last().getData().toString());
66 assertNull(replicatedLogImpl.get(1));
67 assertEquals(3, replicatedLogImpl.lastIndex());
68 assertEquals(2, replicatedLogImpl.lastTerm());
69 assertEquals(0, replicatedLogImpl.getFrom(2).size());
70 assertEquals(1, replicatedLogImpl.size());
71 assertFalse(replicatedLogImpl.isPresent(2));
72 assertTrue(replicatedLogImpl.isPresent(3));
73 assertFalse(replicatedLogImpl.isPresent(4));
74 assertTrue(replicatedLogImpl.isInSnapshot(2));
76 // append few more entries
77 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
78 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
79 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
80 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
82 // check their values as well
83 assertEquals(5, replicatedLogImpl.size());
84 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
85 assertEquals("E", replicatedLogImpl.get(4).getData().toString());
86 assertEquals("H", replicatedLogImpl.last().getData().toString());
87 assertEquals(3, replicatedLogImpl.lastTerm());
88 assertEquals(7, replicatedLogImpl.lastIndex());
89 assertTrue(replicatedLogImpl.isPresent(7));
90 assertFalse(replicatedLogImpl.isInSnapshot(7));
91 assertEquals(1, replicatedLogImpl.getFrom(7).size());
92 assertEquals(2, replicatedLogImpl.getFrom(6).size());
94 // take a second snapshot with 5 entries with 0 unapplied entries left in the log
97 assertEquals(0, replicatedLogImpl.size());
98 assertNull(replicatedLogImpl.last());
99 assertNull(replicatedLogImpl.get(7));
100 assertNull(replicatedLogImpl.get(1));
101 assertFalse(replicatedLogImpl.isPresent(7));
102 assertTrue(replicatedLogImpl.isInSnapshot(7));
103 assertEquals(0, replicatedLogImpl.getFrom(7).size());
104 assertEquals(0, replicatedLogImpl.getFrom(6).size());
109 public void testGetFromWithMax(){
110 List<ReplicatedLogEntry> from = replicatedLogImpl.getFrom(0, 1);
111 Assert.assertEquals(1, from.size());
112 Assert.assertEquals(1, from.get(0).getTerm());
114 from = replicatedLogImpl.getFrom(0, 20);
115 Assert.assertEquals(4, from.size());
116 Assert.assertEquals(2, from.get(3).getTerm());
118 from = replicatedLogImpl.getFrom(1, 2);
119 Assert.assertEquals(2, from.size());
120 Assert.assertEquals(1, from.get(1).getTerm());
125 public void testSnapshotPreCommit() {
127 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
128 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
129 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
130 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
132 //sending negative values should not cause any changes
133 replicatedLogImpl.snapshotPreCommit(-1, -1);
134 assertEquals(8, replicatedLogImpl.size());
135 assertEquals(-1, replicatedLogImpl.getSnapshotIndex());
137 replicatedLogImpl.snapshotPreCommit(4, 3);
138 assertEquals(3, replicatedLogImpl.size());
139 assertEquals(4, replicatedLogImpl.getSnapshotIndex());
141 replicatedLogImpl.snapshotPreCommit(6, 3);
142 assertEquals(1, replicatedLogImpl.size());
143 assertEquals(6, replicatedLogImpl.getSnapshotIndex());
145 replicatedLogImpl.snapshotPreCommit(7, 3);
146 assertEquals(0, replicatedLogImpl.size());
147 assertEquals(7, replicatedLogImpl.getSnapshotIndex());
149 //running it again on an empty list should not throw exception
150 replicatedLogImpl.snapshotPreCommit(7, 3);
151 assertEquals(0, replicatedLogImpl.size());
152 assertEquals(7, replicatedLogImpl.getSnapshotIndex());
157 public void testIsPresent() {
158 assertTrue(replicatedLogImpl.isPresent(0));
159 assertTrue(replicatedLogImpl.isPresent(1));
160 assertTrue(replicatedLogImpl.isPresent(2));
161 assertTrue(replicatedLogImpl.isPresent(3));
163 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("D")));
164 replicatedLogImpl.snapshotPreCommit(3, 2); //snapshot on 3
165 replicatedLogImpl.snapshotCommit();
167 assertFalse(replicatedLogImpl.isPresent(0));
168 assertFalse(replicatedLogImpl.isPresent(1));
169 assertFalse(replicatedLogImpl.isPresent(2));
170 assertFalse(replicatedLogImpl.isPresent(3));
171 assertTrue(replicatedLogImpl.isPresent(4));
173 replicatedLogImpl.snapshotPreCommit(4, 2); //snapshot on 4
174 replicatedLogImpl.snapshotCommit();
175 assertFalse(replicatedLogImpl.isPresent(4));
177 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("D")));
178 assertTrue(replicatedLogImpl.isPresent(5));
182 public void testRemoveFrom() {
184 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E", 2)));
185 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F", 3)));
187 assertEquals("dataSize", 9, replicatedLogImpl.dataSize());
189 long adjusted = replicatedLogImpl.removeFrom(4);
190 assertEquals("removeFrom - adjusted", 4, adjusted);
191 assertEquals("size", 4, replicatedLogImpl.size());
192 assertEquals("dataSize", 4, replicatedLogImpl.dataSize());
196 adjusted = replicatedLogImpl.removeFrom(2);
197 assertEquals("removeFrom - adjusted", 1, adjusted);
198 assertEquals("size", 1, replicatedLogImpl.size());
199 assertEquals("dataSize", 1, replicatedLogImpl.dataSize());
201 assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(0));
202 assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(100));
205 // create a snapshot for test
206 public Map<Long, String> takeSnapshot(final int numEntries) {
207 Map<Long, String> map = new HashMap<>(numEntries);
211 for(int i = 0; i < numEntries; i++) {
212 ReplicatedLogEntry entry = replicatedLogImpl.getAtPhysicalIndex(i);
213 map.put(entry.getIndex(), entry.getData().toString());
214 lastIndex = entry.getIndex();
215 lastTerm = entry.getTerm();
218 replicatedLogImpl.snapshotPreCommit(lastIndex, lastTerm);
219 replicatedLogImpl.snapshotCommit();
224 class MockAbstractReplicatedLogImpl extends AbstractReplicatedLogImpl {
226 public void appendAndPersist(final ReplicatedLogEntry replicatedLogEntry) {
230 public void removeFromAndPersist(final long index) {
234 public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry, Procedure<ReplicatedLogEntry> callback) {