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 java.util.function.Consumer;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.mockito.ArgumentCaptor;
26 import org.mockito.ArgumentMatcher;
27 import org.mockito.Mock;
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.emptyMap(),
61 configParams, mockPersistence, applyState -> { }, LOG, MoreExecutors.directExecutor());
64 private void verifyPersist(final Object message) throws Exception {
65 verifyPersist(message, new Same(message), true);
68 @SuppressWarnings({ "unchecked", "rawtypes" })
69 private void verifyPersist(final Object message, final ArgumentMatcher<?> matcher, final boolean async)
71 ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
73 verify(mockPersistence).persistAsync(argThat(matcher), procedure.capture());
75 verify(mockPersistence).persist(argThat(matcher), procedure.capture());
78 procedure.getValue().apply(message);
81 @SuppressWarnings("unchecked")
83 public void testAppendAndPersistExpectingNoCapture() throws Exception {
84 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
86 ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
88 log.appendAndPersist(logEntry1, null, true);
90 verifyPersist(logEntry1);
92 assertEquals("size", 1, log.size());
94 reset(mockPersistence);
96 ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
97 Consumer<ReplicatedLogEntry> mockCallback = mock(Consumer.class);
98 log.appendAndPersist(logEntry2, mockCallback, true);
100 verifyPersist(logEntry2);
102 verify(mockCallback).accept(same(logEntry2));
104 assertEquals("size", 2, log.size());
107 @SuppressWarnings("unchecked")
109 public void testAppendAndPersisWithDuplicateEntry() throws Exception {
110 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
112 Consumer<ReplicatedLogEntry> mockCallback = mock(Consumer.class);
113 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
115 log.appendAndPersist(logEntry, mockCallback, true);
117 verifyPersist(logEntry);
119 assertEquals("size", 1, log.size());
121 reset(mockPersistence, mockCallback);
123 log.appendAndPersist(logEntry, mockCallback, true);
125 verifyNoMoreInteractions(mockPersistence, mockCallback);
127 assertEquals("size", 1, log.size());
131 public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
132 configParams.setSnapshotBatchCount(2);
134 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
136 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
138 final ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
139 final ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3"));
141 log.appendAndPersist(logEntry1, null, true);
142 verifyPersist(logEntry1);
144 reset(mockPersistence);
146 log.appendAndPersist(logEntry2, null, true);
147 verifyPersist(logEntry2);
150 assertEquals("size", 2, log.size());
154 public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
155 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
157 context.setTotalMemoryRetriever(() -> 100);
159 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
162 ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
164 log.appendAndPersist(logEntry, null, true);
165 verifyPersist(logEntry);
167 reset(mockPersistence);
169 logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
171 log.appendAndPersist(logEntry, null, true);
172 verifyPersist(logEntry);
174 assertEquals("size", 2, log.size());
178 public void testRemoveFromAndPersist() throws Exception {
180 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
182 log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
183 log.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("1")));
184 log.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("2")));
186 log.removeFromAndPersist(1);
188 DeleteEntries deleteEntries = new DeleteEntries(1);
189 verifyPersist(deleteEntries, match(deleteEntries), false);
191 assertEquals("size", 1, log.size());
193 reset(mockPersistence);
195 log.removeFromAndPersist(1);
197 verifyNoMoreInteractions(mockPersistence);
201 public void testCommitFakeSnapshot() {
202 ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
204 log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
205 final int dataSizeAfterFirstPayload = log.dataSize();
207 log.snapshotPreCommit(0,1);
208 log.snapshotCommit(false);
210 assertEquals(0, log.size());
211 assertEquals(dataSizeAfterFirstPayload, log.dataSize());
214 private static ArgumentMatcher<DeleteEntries> match(final DeleteEntries actual) {
215 return other -> actual.getFromIndex() == other.getFromIndex();