Migrate ReplicatedLogImplTest
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / ReplicatedLogImplTest.java
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.raft;
9
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.mock;
14 import static org.mockito.Mockito.reset;
15 import static org.mockito.Mockito.verify;
16 import static org.mockito.Mockito.verifyNoMoreInteractions;
17
18 import akka.japi.Procedure;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.util.Collections;
21 import java.util.function.Consumer;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.junit.runner.RunWith;
25 import org.mockito.ArgumentCaptor;
26 import org.mockito.ArgumentMatcher;
27 import org.mockito.Mock;
28 import org.mockito.internal.matchers.Same;
29 import org.mockito.junit.MockitoJUnitRunner;
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;
37
38 /**
39  * Unit tests for ReplicatedLogImpl.
40  *
41  * @author Thomas Pantelis
42  */
43 @RunWith(MockitoJUnitRunner.StrictStubs.class)
44 public class ReplicatedLogImplTest {
45     private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
46
47     @Mock
48     private DataPersistenceProvider mockPersistence;
49
50     @Mock
51     private RaftActorBehavior mockBehavior;
52
53     private RaftActorContext context;
54     private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
55
56     @Before
57     public void setup() {
58         context = new RaftActorContextImpl(null, null, "test",
59                 new ElectionTermImpl(mockPersistence, "test", LOG), -1, -1, Collections.emptyMap(),
60                 configParams, mockPersistence, applyState -> { }, LOG,  MoreExecutors.directExecutor());
61     }
62
63     private void verifyPersist(final Object message) throws Exception {
64         verifyPersist(message, new Same(message), true);
65     }
66
67     @SuppressWarnings({ "unchecked", "rawtypes" })
68     private void verifyPersist(final Object message, final ArgumentMatcher<?> matcher, final boolean async)
69             throws Exception {
70         ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
71         if (async) {
72             verify(mockPersistence).persistAsync(argThat(matcher), procedure.capture());
73         } else {
74             verify(mockPersistence).persist(argThat(matcher), procedure.capture());
75         }
76
77         procedure.getValue().apply(message);
78     }
79
80     @Test
81     @SuppressWarnings("unchecked")
82     public void testAppendAndPersistExpectingNoCapture() throws Exception {
83         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
84
85         ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
86
87         log.appendAndPersist(logEntry1, null, true);
88
89         verifyPersist(logEntry1);
90
91         assertEquals("size", 1, log.size());
92
93         reset(mockPersistence);
94
95         ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
96         Consumer<ReplicatedLogEntry> mockCallback = mock(Consumer.class);
97         log.appendAndPersist(logEntry2, mockCallback, true);
98
99         verifyPersist(logEntry2);
100
101         verify(mockCallback).accept(same(logEntry2));
102
103         assertEquals("size", 2, log.size());
104     }
105
106     @SuppressWarnings("unchecked")
107     @Test
108     public void testAppendAndPersisWithDuplicateEntry() throws Exception {
109         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
110
111         Consumer<ReplicatedLogEntry> mockCallback = mock(Consumer.class);
112         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
113
114         log.appendAndPersist(logEntry, mockCallback, true);
115
116         verifyPersist(logEntry);
117
118         assertEquals("size", 1, log.size());
119
120         reset(mockPersistence, mockCallback);
121
122         log.appendAndPersist(logEntry, mockCallback, true);
123
124         verifyNoMoreInteractions(mockPersistence, mockCallback);
125
126         assertEquals("size", 1, log.size());
127     }
128
129     @Test
130     public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
131         configParams.setSnapshotBatchCount(2);
132
133         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
134
135         final ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
136         final ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3"));
137
138         log.appendAndPersist(logEntry1, null, true);
139         verifyPersist(logEntry1);
140
141         reset(mockPersistence);
142
143         log.appendAndPersist(logEntry2, null, true);
144         verifyPersist(logEntry2);
145
146
147         assertEquals("size", 2, log.size());
148     }
149
150     @Test
151     public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
152         context.setTotalMemoryRetriever(() -> 100);
153
154         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
155
156         int dataSize = 600;
157         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
158
159         log.appendAndPersist(logEntry, null, true);
160         verifyPersist(logEntry);
161
162         reset(mockPersistence);
163
164         logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
165
166         log.appendAndPersist(logEntry, null, true);
167         verifyPersist(logEntry);
168
169         assertEquals("size", 2, log.size());
170     }
171
172     @Test
173     public void testRemoveFromAndPersist() throws Exception {
174
175         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
176
177         log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
178         log.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("1")));
179         log.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("2")));
180
181         log.removeFromAndPersist(1);
182
183         DeleteEntries deleteEntries = new DeleteEntries(1);
184         verifyPersist(deleteEntries, match(deleteEntries), false);
185
186         assertEquals("size", 1, log.size());
187
188         reset(mockPersistence);
189
190         log.removeFromAndPersist(1);
191
192         verifyNoMoreInteractions(mockPersistence);
193     }
194
195     @Test
196     public void testCommitFakeSnapshot() {
197         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
198
199         log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
200         final int dataSizeAfterFirstPayload = log.dataSize();
201
202         log.snapshotPreCommit(0,1);
203         log.snapshotCommit(false);
204
205         assertEquals(0, log.size());
206         assertEquals(dataSizeAfterFirstPayload, log.dataSize());
207     }
208
209     private static ArgumentMatcher<DeleteEntries> match(final DeleteEntries actual) {
210         return other -> actual.getFromIndex() == other.getFromIndex();
211     }
212 }