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 java.util.HashMap;
15 import java.util.List;
17 import org.junit.After;
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 tearDown() {
44 replicatedLogImpl.journal.clear();
45 replicatedLogImpl.setSnapshotIndex(-1);
46 replicatedLogImpl.setSnapshotTerm(-1);
47 replicatedLogImpl = null;
51 public void testIndexOperations() {
53 // check if the values returned are correct, with snapshotIndex = -1
54 assertEquals("B", replicatedLogImpl.get(1).getData().toString());
55 assertEquals("D", replicatedLogImpl.last().getData().toString());
56 assertEquals(3, replicatedLogImpl.lastIndex());
57 assertEquals(2, replicatedLogImpl.lastTerm());
58 assertEquals(2, replicatedLogImpl.getFrom(2).size());
59 assertEquals(4, replicatedLogImpl.size());
60 assertTrue(replicatedLogImpl.isPresent(2));
61 assertFalse(replicatedLogImpl.isPresent(4));
62 assertFalse(replicatedLogImpl.isInSnapshot(2));
64 // now create a snapshot of 3 entries, with 1 unapplied entry left in the log
65 // It removes the entries which have made it to snapshot
66 // and updates the snapshot index and term
67 Map<Long, String> state = takeSnapshot(3);
69 // check the values after the snapshot.
70 // each index value passed in the test is the logical index (log entry index)
71 // which gets mapped to the list's physical index
72 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
73 assertEquals("D", replicatedLogImpl.last().getData().toString());
74 assertNull(replicatedLogImpl.get(1));
75 assertEquals(3, replicatedLogImpl.lastIndex());
76 assertEquals(2, replicatedLogImpl.lastTerm());
77 assertEquals(0, replicatedLogImpl.getFrom(2).size());
78 assertEquals(1, replicatedLogImpl.size());
79 assertFalse(replicatedLogImpl.isPresent(2));
80 assertTrue(replicatedLogImpl.isPresent(3));
81 assertFalse(replicatedLogImpl.isPresent(4));
82 assertTrue(replicatedLogImpl.isInSnapshot(2));
84 // append few more entries
85 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
86 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
87 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
88 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
90 // check their values as well
91 assertEquals(5, replicatedLogImpl.size());
92 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
93 assertEquals("E", replicatedLogImpl.get(4).getData().toString());
94 assertEquals("H", replicatedLogImpl.last().getData().toString());
95 assertEquals(3, replicatedLogImpl.lastTerm());
96 assertEquals(7, replicatedLogImpl.lastIndex());
97 assertTrue(replicatedLogImpl.isPresent(7));
98 assertFalse(replicatedLogImpl.isInSnapshot(7));
99 assertEquals(1, replicatedLogImpl.getFrom(7).size());
100 assertEquals(2, replicatedLogImpl.getFrom(6).size());
102 // take a second snapshot with 5 entries with 0 unapplied entries left in the log
103 state = takeSnapshot(5);
105 assertEquals(0, replicatedLogImpl.size());
106 assertNull(replicatedLogImpl.last());
107 assertNull(replicatedLogImpl.get(7));
108 assertNull(replicatedLogImpl.get(1));
109 assertFalse(replicatedLogImpl.isPresent(7));
110 assertTrue(replicatedLogImpl.isInSnapshot(7));
111 assertEquals(0, replicatedLogImpl.getFrom(7).size());
112 assertEquals(0, replicatedLogImpl.getFrom(6).size());
117 public void testGetFromWithMax(){
118 List<ReplicatedLogEntry> from = replicatedLogImpl.getFrom(0, 1);
119 Assert.assertEquals(1, from.size());
120 Assert.assertEquals(1, from.get(0).getTerm());
122 from = replicatedLogImpl.getFrom(0, 20);
123 Assert.assertEquals(4, from.size());
124 Assert.assertEquals(2, from.get(3).getTerm());
126 from = replicatedLogImpl.getFrom(1, 2);
127 Assert.assertEquals(2, from.size());
128 Assert.assertEquals(1, from.get(1).getTerm());
133 public void testSnapshotPreCommit() {
135 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
136 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
137 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
138 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
140 //sending negative values should not cause any changes
141 replicatedLogImpl.snapshotPreCommit(-1, -1);
142 assertEquals(8, replicatedLogImpl.size());
143 assertEquals(-1, replicatedLogImpl.getSnapshotIndex());
145 replicatedLogImpl.snapshotPreCommit(4, 3);
146 assertEquals(3, replicatedLogImpl.size());
147 assertEquals(4, replicatedLogImpl.getSnapshotIndex());
149 replicatedLogImpl.snapshotPreCommit(6, 3);
150 assertEquals(1, replicatedLogImpl.size());
151 assertEquals(6, replicatedLogImpl.getSnapshotIndex());
153 replicatedLogImpl.snapshotPreCommit(7, 3);
154 assertEquals(0, replicatedLogImpl.size());
155 assertEquals(7, replicatedLogImpl.getSnapshotIndex());
157 //running it again on an empty list should not throw exception
158 replicatedLogImpl.snapshotPreCommit(7, 3);
159 assertEquals(0, replicatedLogImpl.size());
160 assertEquals(7, replicatedLogImpl.getSnapshotIndex());
165 public void testIsPresent() {
166 assertTrue(replicatedLogImpl.isPresent(0));
167 assertTrue(replicatedLogImpl.isPresent(1));
168 assertTrue(replicatedLogImpl.isPresent(2));
169 assertTrue(replicatedLogImpl.isPresent(3));
171 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("D")));
172 replicatedLogImpl.snapshotPreCommit(3, 2); //snapshot on 3
173 replicatedLogImpl.snapshotCommit();
175 assertFalse(replicatedLogImpl.isPresent(0));
176 assertFalse(replicatedLogImpl.isPresent(1));
177 assertFalse(replicatedLogImpl.isPresent(2));
178 assertFalse(replicatedLogImpl.isPresent(3));
179 assertTrue(replicatedLogImpl.isPresent(4));
181 replicatedLogImpl.snapshotPreCommit(4, 2); //snapshot on 4
182 replicatedLogImpl.snapshotCommit();
183 assertFalse(replicatedLogImpl.isPresent(4));
185 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("D")));
186 assertTrue(replicatedLogImpl.isPresent(5));
189 // create a snapshot for test
190 public Map<Long, String> takeSnapshot(final int numEntries) {
191 Map<Long, String> map = new HashMap<>(numEntries);
192 List<ReplicatedLogEntry> entries = replicatedLogImpl.getEntriesTill(numEntries);
193 for (ReplicatedLogEntry entry : entries) {
194 map.put(entry.getIndex(), entry.getData().toString());
197 int term = (int) replicatedLogImpl.lastTerm();
198 int lastIndex = (int) entries.get(entries.size() - 1).getIndex();
200 replicatedLogImpl.setSnapshotTerm(term);
201 replicatedLogImpl.setSnapshotIndex(lastIndex);
206 class MockAbstractReplicatedLogImpl extends AbstractReplicatedLogImpl {
208 public void appendAndPersist(final ReplicatedLogEntry replicatedLogEntry) {
212 public void removeFromAndPersist(final long index) {
216 public int dataSize() {
220 public List<ReplicatedLogEntry> getEntriesTill(final int index) {
221 return journal.subList(0, index);