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.ArgumentMatchers.argThat;
12 import static org.mockito.ArgumentMatchers.same;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.reset;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.verifyNoMoreInteractions;
19 import akka.japi.Procedure;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import java.util.Collections;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.mockito.ArgumentCaptor;
25 import org.mockito.ArgumentMatcher;
26 import org.mockito.Mock;
27 import org.mockito.MockitoAnnotations;
28 import org.mockito.internal.matchers.Same;
29 import org.opendaylight.controller.cluster.DataPersistenceProvider;
30 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
31 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
32 import org.opendaylight.controller.cluster.raft.persisted.DeleteEntries;
33 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * Unit tests for ReplicatedLogImpl.
40 * @author Thomas Pantelis
42 public class ReplicatedLogImplTest {
43 private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
46 private DataPersistenceProvider mockPersistence;
49 private RaftActorBehavior mockBehavior;
51 private RaftActorContext context;
52 private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
56 MockitoAnnotations.initMocks(this);
58 context = new RaftActorContextImpl(null, null, "test",
59 new ElectionTermImpl(mockPersistence, "test", LOG), -1, -1, Collections.<String,String>emptyMap(),
60 configParams, mockPersistence, applyState -> { }, LOG, MoreExecutors.directExecutor());
63 private void verifyPersist(Object message) throws Exception {
64 verifyPersist(message, new Same(message), true);
67 @SuppressWarnings({ "unchecked", "rawtypes" })
68 private void verifyPersist(Object message, ArgumentMatcher<?> matcher, boolean async) throws Exception {
69 ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
71 verify(mockPersistence).persistAsync(argThat(matcher), procedure.capture());
73 verify(mockPersistence).persist(argThat(matcher), procedure.capture());
76 procedure.getValue().apply(message);
79 @SuppressWarnings("unchecked")
81 public void testAppendAndPersistExpectingNoCapture() throws Exception {
82 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
84 ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
86 log.appendAndPersist(logEntry1, null, true);
88 verifyPersist(logEntry1);
90 assertEquals("size", 1, log.size());
92 reset(mockPersistence);
94 ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
95 Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
96 log.appendAndPersist(logEntry2, mockCallback, true);
98 verifyPersist(logEntry2);
100 verify(mockCallback).apply(same(logEntry2));
102 assertEquals("size", 2, log.size());
105 @SuppressWarnings("unchecked")
107 public void testAppendAndPersisWithDuplicateEntry() throws Exception {
108 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
110 Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
111 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
113 log.appendAndPersist(logEntry, mockCallback, true);
115 verifyPersist(logEntry);
117 assertEquals("size", 1, log.size());
119 reset(mockPersistence, mockCallback);
121 log.appendAndPersist(logEntry, mockCallback, true);
123 verifyNoMoreInteractions(mockPersistence, mockCallback);
125 assertEquals("size", 1, log.size());
129 public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
130 configParams.setSnapshotBatchCount(2);
132 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
134 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
136 final ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
137 final ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3"));
139 log.appendAndPersist(logEntry1, null, true);
140 verifyPersist(logEntry1);
142 reset(mockPersistence);
144 log.appendAndPersist(logEntry2, null, true);
145 verifyPersist(logEntry2);
148 assertEquals("size", 2, log.size());
152 public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
153 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
155 context.setTotalMemoryRetriever(() -> 100);
157 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
160 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
162 log.appendAndPersist(logEntry, null, true);
163 verifyPersist(logEntry);
165 reset(mockPersistence);
167 logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
169 log.appendAndPersist(logEntry, null, true);
170 verifyPersist(logEntry);
172 assertEquals("size", 2, log.size());
176 public void testRemoveFromAndPersist() throws Exception {
178 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
180 log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
181 log.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("1")));
182 log.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("2")));
184 log.removeFromAndPersist(1);
186 DeleteEntries deleteEntries = new DeleteEntries(1);
187 verifyPersist(deleteEntries, match(deleteEntries), false);
189 assertEquals("size", 1, log.size());
191 reset(mockPersistence);
193 log.removeFromAndPersist(1);
195 verifyNoMoreInteractions(mockPersistence);
198 public ArgumentMatcher<DeleteEntries> match(final DeleteEntries actual) {
199 return other -> actual.getFromIndex() == other.getFromIndex();