2 * Copyright (c) 2015 Brocade Communications 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.mockito.Matchers.same;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.reset;
14 import static org.mockito.Mockito.verify;
15 import static org.mockito.Mockito.verifyNoMoreInteractions;
17 import akka.japi.Procedure;
18 import java.util.Collections;
19 import org.hamcrest.BaseMatcher;
20 import org.hamcrest.Description;
21 import org.hamcrest.Matcher;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.mockito.ArgumentCaptor;
25 import org.mockito.Matchers;
26 import org.mockito.Mock;
27 import org.mockito.Mockito;
28 import org.mockito.MockitoAnnotations;
29 import org.mockito.internal.matchers.Same;
30 import org.opendaylight.controller.cluster.DataPersistenceProvider;
31 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
32 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
33 import org.opendaylight.controller.cluster.raft.persisted.DeleteEntries;
34 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Unit tests for ReplicatedLogImpl.
41 * @author Thomas Pantelis
43 public class ReplicatedLogImplTest {
44 private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
47 private DataPersistenceProvider mockPersistence;
50 private RaftActorBehavior mockBehavior;
52 private RaftActorContext context;
53 private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
57 MockitoAnnotations.initMocks(this);
59 context = new RaftActorContextImpl(null, null, "test",
60 new ElectionTermImpl(mockPersistence, "test", LOG), -1, -1, Collections.<String,String>emptyMap(),
61 configParams, mockPersistence, applyState -> { }, LOG);
64 private void verifyPersist(Object message) throws Exception {
65 verifyPersist(message, new Same(message), true);
68 @SuppressWarnings({ "unchecked", "rawtypes" })
69 private void verifyPersist(Object message, Matcher<?> matcher, boolean async) throws Exception {
70 ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
72 verify(mockPersistence).persistAsync(Matchers.argThat(matcher), procedure.capture());
74 verify(mockPersistence).persist(Matchers.argThat(matcher), procedure.capture());
77 procedure.getValue().apply(message);
80 @SuppressWarnings("unchecked")
82 public void testAppendAndPersistExpectingNoCapture() throws Exception {
83 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
85 ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
87 log.appendAndPersist(logEntry1, null, true);
89 verifyPersist(logEntry1);
91 assertEquals("size", 1, log.size());
93 reset(mockPersistence);
95 ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
96 Procedure<ReplicatedLogEntry> mockCallback = Mockito.mock(Procedure.class);
97 log.appendAndPersist(logEntry2, mockCallback, true);
99 verifyPersist(logEntry2);
101 verify(mockCallback).apply(same(logEntry2));
103 assertEquals("size", 2, log.size());
106 @SuppressWarnings("unchecked")
108 public void testAppendAndPersisWithDuplicateEntry() throws Exception {
109 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
111 Procedure<ReplicatedLogEntry> mockCallback = Mockito.mock(Procedure.class);
112 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
114 log.appendAndPersist(logEntry, mockCallback, true);
116 verifyPersist(logEntry);
118 assertEquals("size", 1, log.size());
120 reset(mockPersistence, mockCallback);
122 log.appendAndPersist(logEntry, mockCallback, true);
124 verifyNoMoreInteractions(mockPersistence, mockCallback);
126 assertEquals("size", 1, log.size());
130 public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
131 configParams.setSnapshotBatchCount(2);
133 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
135 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
137 final ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
138 final ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3"));
140 log.appendAndPersist(logEntry1, null, true);
141 verifyPersist(logEntry1);
143 reset(mockPersistence);
145 log.appendAndPersist(logEntry2, null, true);
146 verifyPersist(logEntry2);
149 assertEquals("size", 2, log.size());
153 public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
154 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
156 context.setTotalMemoryRetriever(() -> 100);
158 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
161 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
163 log.appendAndPersist(logEntry, null, true);
164 verifyPersist(logEntry);
166 reset(mockPersistence);
168 logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
170 log.appendAndPersist(logEntry, null, true);
171 verifyPersist(logEntry);
173 assertEquals("size", 2, log.size());
177 public void testRemoveFromAndPersist() throws Exception {
179 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
181 log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
182 log.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("1")));
183 log.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("2")));
185 log.removeFromAndPersist(1);
187 DeleteEntries deleteEntries = new DeleteEntries(1);
188 verifyPersist(deleteEntries, match(deleteEntries), false);
190 assertEquals("size", 1, log.size());
192 reset(mockPersistence);
194 log.removeFromAndPersist(1);
196 verifyNoMoreInteractions(mockPersistence);
199 public Matcher<DeleteEntries> match(final DeleteEntries actual) {
200 return new BaseMatcher<DeleteEntries>() {
202 public boolean matches(Object obj) {
203 DeleteEntries other = (DeleteEntries) obj;
204 return actual.getFromIndex() == other.getFromIndex();
208 public void describeTo(Description description) {
209 description.appendText("DeleteEntries: fromIndex: " + actual.getFromIndex());