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.eq;
12 import static org.mockito.Matchers.same;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.reset;
15 import static org.mockito.Mockito.verify;
16 import static org.mockito.Mockito.verifyNoMoreInteractions;
17 import akka.japi.Procedure;
18 import com.google.common.base.Supplier;
19 import java.util.Collections;
20 import org.hamcrest.BaseMatcher;
21 import org.hamcrest.Description;
22 import org.hamcrest.Matcher;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.mockito.ArgumentCaptor;
26 import org.mockito.Matchers;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.mockito.MockitoAnnotations;
30 import org.mockito.internal.matchers.Same;
31 import org.opendaylight.controller.cluster.DataPersistenceProvider;
32 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
33 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
34 import org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries;
35 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * Unit tests for ReplicatedLogImpl.
42 * @author Thomas Pantelis
44 public class ReplicatedLogImplTest {
45 private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
48 private DataPersistenceProvider mockPersistence;
51 private RaftActorBehavior mockBehavior;
54 private SnapshotManager mockSnapshotManager;
56 private RaftActorContext context;
57 private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
61 MockitoAnnotations.initMocks(this);
63 context = new RaftActorContextImpl(null, null, "test",
64 new ElectionTermImpl(mockPersistence, "test", LOG),
65 -1, -1, Collections.<String,String>emptyMap(), configParams, LOG) {
67 public SnapshotManager getSnapshotManager() {
68 return mockSnapshotManager;
73 private void verifyPersist(Object message) throws Exception {
74 verifyPersist(message, new Same(message));
77 @SuppressWarnings({ "unchecked", "rawtypes" })
78 private void verifyPersist(Object message, Matcher<?> matcher) throws Exception {
79 ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
80 verify(mockPersistence).persist(Matchers.argThat(matcher), procedure.capture());
82 procedure.getValue().apply(message);
85 @SuppressWarnings("unchecked")
87 public void testAppendAndPersistExpectingNoCapture() throws Exception {
88 ReplicatedLog log = ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior);
90 MockReplicatedLogEntry logEntry = new MockReplicatedLogEntry(1, 1, new MockPayload("1"));
92 log.appendAndPersist(logEntry);
94 verifyPersist(logEntry);
96 assertEquals("size", 1, log.size());
98 reset(mockPersistence);
100 Procedure<ReplicatedLogEntry> mockCallback = Mockito.mock(Procedure.class);
101 log.appendAndPersist(logEntry, mockCallback);
103 verifyPersist(logEntry);
105 verify(mockCallback).apply(same(logEntry));
106 verifyNoMoreInteractions(mockSnapshotManager);
108 assertEquals("size", 2, log.size());
112 public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
113 configParams.setSnapshotBatchCount(2);
115 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
117 ReplicatedLog log = ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior);
119 MockReplicatedLogEntry logEntry1 = new MockReplicatedLogEntry(1, 2, new MockPayload("2"));
120 MockReplicatedLogEntry logEntry2 = new MockReplicatedLogEntry(1, 3, new MockPayload("3"));
122 log.appendAndPersist(logEntry1);
123 verifyPersist(logEntry1);
125 verifyNoMoreInteractions(mockSnapshotManager);
126 reset(mockPersistence);
128 log.appendAndPersist(logEntry2);
129 verifyPersist(logEntry2);
131 verify(mockSnapshotManager).capture(same(logEntry2), eq(1L));
133 assertEquals("size", 2, log.size());
137 public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
138 doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
140 context.setTotalMemoryRetriever(new Supplier<Long>() {
147 ReplicatedLog log = ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior);
150 MockReplicatedLogEntry logEntry = new MockReplicatedLogEntry(1, 2, new MockPayload("2", dataSize));
152 doReturn(true).when(mockSnapshotManager).capture(same(logEntry), eq(1L));
154 log.appendAndPersist(logEntry);
155 verifyPersist(logEntry);
157 verify(mockSnapshotManager).capture(same(logEntry), eq(1L));
159 reset(mockPersistence, mockSnapshotManager);
161 logEntry = new MockReplicatedLogEntry(1, 3, new MockPayload("3", 5));
163 log.appendAndPersist(logEntry);
164 verifyPersist(logEntry);
166 verifyNoMoreInteractions(mockSnapshotManager);
168 assertEquals("size", 2, log.size());
172 public void testRemoveFromAndPersist() throws Exception {
174 ReplicatedLog log = ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior);
176 log.append(new MockReplicatedLogEntry(1, 0, new MockPayload("0")));
177 log.append(new MockReplicatedLogEntry(1, 1, new MockPayload("1")));
178 log.append(new MockReplicatedLogEntry(1, 2, new MockPayload("2")));
180 log.removeFromAndPersist(1);
182 DeleteEntries deleteEntries = new DeleteEntries(1);
183 verifyPersist(deleteEntries, match(deleteEntries));
185 assertEquals("size", 1, log.size());
187 reset(mockPersistence);
189 log.removeFromAndPersist(1);
191 verifyNoMoreInteractions(mockPersistence);
194 public Matcher<DeleteEntries> match(final DeleteEntries actual){
195 return new BaseMatcher<DeleteEntries>() {
197 public boolean matches(Object o) {
198 DeleteEntries other = (DeleteEntries) o;
199 return actual.getFromIndex() == other.getFromIndex();
203 public void describeTo(Description description) {
204 description.appendText("DeleteEntries: fromIndex: " + actual.getFromIndex());