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 junit.framework.Assert;
11 import org.junit.After;
12 import org.junit.Before;
13 import org.junit.Test;
15 import java.util.HashMap;
16 import java.util.List;
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
24 import static org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
28 public class AbstractReplicatedLogImplTest {
30 private MockAbstractReplicatedLogImpl replicatedLogImpl;
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")));
44 public void tearDown() {
45 replicatedLogImpl.journal.clear();
46 replicatedLogImpl.setSnapshotIndex(-1);
47 replicatedLogImpl.setSnapshotTerm(-1);
48 replicatedLogImpl = null;
52 public void testIndexOperations() {
54 // check if the values returned are correct, with snapshotIndex = -1
55 assertEquals("B", replicatedLogImpl.get(1).getData().toString());
56 assertEquals("D", replicatedLogImpl.last().getData().toString());
57 assertEquals(3, replicatedLogImpl.lastIndex());
58 assertEquals(2, replicatedLogImpl.lastTerm());
59 assertEquals(2, replicatedLogImpl.getFrom(2).size());
60 assertEquals(4, replicatedLogImpl.size());
61 assertTrue(replicatedLogImpl.isPresent(2));
62 assertFalse(replicatedLogImpl.isPresent(4));
63 assertFalse(replicatedLogImpl.isInSnapshot(2));
65 // now create a snapshot of 3 entries, with 1 unapplied entry left in the log
66 // It removes the entries which have made it to snapshot
67 // and updates the snapshot index and term
68 Map state = takeSnapshot(3);
70 // check the values after the snapshot.
71 // each index value passed in the test is the logical index (log entry index)
72 // which gets mapped to the list's physical index
73 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
74 assertEquals("D", replicatedLogImpl.last().getData().toString());
75 assertNull(replicatedLogImpl.get(1));
76 assertEquals(3, replicatedLogImpl.lastIndex());
77 assertEquals(2, replicatedLogImpl.lastTerm());
78 assertEquals(0, replicatedLogImpl.getFrom(2).size());
79 assertEquals(1, replicatedLogImpl.size());
80 assertFalse(replicatedLogImpl.isPresent(2));
81 assertTrue(replicatedLogImpl.isPresent(3));
82 assertFalse(replicatedLogImpl.isPresent(4));
83 assertTrue(replicatedLogImpl.isInSnapshot(2));
85 // append few more entries
86 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
87 replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
88 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
89 replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
91 // check their values as well
92 assertEquals(5, replicatedLogImpl.size());
93 assertEquals("D", replicatedLogImpl.get(3).getData().toString());
94 assertEquals("E", replicatedLogImpl.get(4).getData().toString());
95 assertEquals("H", replicatedLogImpl.last().getData().toString());
96 assertEquals(3, replicatedLogImpl.lastTerm());
97 assertEquals(7, replicatedLogImpl.lastIndex());
98 assertTrue(replicatedLogImpl.isPresent(7));
99 assertFalse(replicatedLogImpl.isInSnapshot(7));
100 assertEquals(1, replicatedLogImpl.getFrom(7).size());
101 assertEquals(2, replicatedLogImpl.getFrom(6).size());
103 // take a second snapshot with 5 entries with 0 unapplied entries left in the log
104 state = takeSnapshot(5);
106 assertEquals(0, replicatedLogImpl.size());
107 assertNull(replicatedLogImpl.last());
108 assertNull(replicatedLogImpl.get(7));
109 assertNull(replicatedLogImpl.get(1));
110 assertFalse(replicatedLogImpl.isPresent(7));
111 assertTrue(replicatedLogImpl.isInSnapshot(7));
112 assertEquals(0, replicatedLogImpl.getFrom(7).size());
113 assertEquals(0, replicatedLogImpl.getFrom(6).size());
118 public void testGetFromWithMax(){
119 List<ReplicatedLogEntry> from = replicatedLogImpl.getFrom(0, 1);
120 Assert.assertEquals(1, from.size());
121 Assert.assertEquals(1, from.get(0).getTerm());
123 from = replicatedLogImpl.getFrom(0, 20);
124 Assert.assertEquals(4, from.size());
125 Assert.assertEquals(2, from.get(3).getTerm());
127 from = replicatedLogImpl.getFrom(1, 2);
128 Assert.assertEquals(2, from.size());
129 Assert.assertEquals(1, from.get(1).getTerm());
133 // create a snapshot for test
134 public Map takeSnapshot(int numEntries) {
135 Map map = new HashMap(numEntries);
136 List<ReplicatedLogEntry> entries = replicatedLogImpl.getEntriesTill(numEntries);
137 for (ReplicatedLogEntry entry : entries) {
138 map.put(entry.getIndex(), entry.getData().toString());
141 int term = (int) replicatedLogImpl.lastTerm();
142 int lastIndex = (int) entries.get(entries.size() - 1).getIndex();
144 replicatedLogImpl.setSnapshotTerm(term);
145 replicatedLogImpl.setSnapshotIndex(lastIndex);
150 class MockAbstractReplicatedLogImpl extends AbstractReplicatedLogImpl {
152 public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry) {
156 public void removeFromAndPersist(long index) {
159 public void setSnapshotIndex(long snapshotIndex) {
160 this.snapshotIndex = snapshotIndex;
163 public void setSnapshotTerm(long snapshotTerm) {
164 this.snapshotTerm = snapshotTerm;
167 public List<ReplicatedLogEntry> getEntriesTill(int index) {
168 return journal.subList(0, index);