Do not break actor containment
[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.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;
18
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;
36
37 /**
38  * Unit tests for ReplicatedLogImpl.
39  *
40  * @author Thomas Pantelis
41  */
42 public class ReplicatedLogImplTest {
43     private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
44
45     @Mock
46     private DataPersistenceProvider mockPersistence;
47
48     @Mock
49     private RaftActorBehavior mockBehavior;
50
51     private RaftActorContext context;
52     private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
53
54     @Before
55     public void setup() {
56         MockitoAnnotations.initMocks(this);
57
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());
61     }
62
63     private void verifyPersist(Object message) throws Exception {
64         verifyPersist(message, new Same(message), true);
65     }
66
67     @SuppressWarnings({ "unchecked", "rawtypes" })
68     private void verifyPersist(Object message, ArgumentMatcher<?> matcher, boolean async) throws Exception {
69         ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
70         if (async) {
71             verify(mockPersistence).persistAsync(argThat(matcher), procedure.capture());
72         } else {
73             verify(mockPersistence).persist(argThat(matcher), procedure.capture());
74         }
75
76         procedure.getValue().apply(message);
77     }
78
79     @SuppressWarnings("unchecked")
80     @Test
81     public void testAppendAndPersistExpectingNoCapture() throws Exception {
82         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
83
84         ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
85
86         log.appendAndPersist(logEntry1, null, true);
87
88         verifyPersist(logEntry1);
89
90         assertEquals("size", 1, log.size());
91
92         reset(mockPersistence);
93
94         ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
95         Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
96         log.appendAndPersist(logEntry2, mockCallback, true);
97
98         verifyPersist(logEntry2);
99
100         verify(mockCallback).apply(same(logEntry2));
101
102         assertEquals("size", 2, log.size());
103     }
104
105     @SuppressWarnings("unchecked")
106     @Test
107     public void testAppendAndPersisWithDuplicateEntry() throws Exception {
108         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
109
110         Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
111         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
112
113         log.appendAndPersist(logEntry, mockCallback, true);
114
115         verifyPersist(logEntry);
116
117         assertEquals("size", 1, log.size());
118
119         reset(mockPersistence, mockCallback);
120
121         log.appendAndPersist(logEntry, mockCallback, true);
122
123         verifyNoMoreInteractions(mockPersistence, mockCallback);
124
125         assertEquals("size", 1, log.size());
126     }
127
128     @Test
129     public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
130         configParams.setSnapshotBatchCount(2);
131
132         doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
133
134         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
135
136         final ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
137         final ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3"));
138
139         log.appendAndPersist(logEntry1, null, true);
140         verifyPersist(logEntry1);
141
142         reset(mockPersistence);
143
144         log.appendAndPersist(logEntry2, null, true);
145         verifyPersist(logEntry2);
146
147
148         assertEquals("size", 2, log.size());
149     }
150
151     @Test
152     public void testAppendAndPersistExpectingCaptureDueToDataSize() throws Exception {
153         doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
154
155         context.setTotalMemoryRetriever(() -> 100);
156
157         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
158
159         int dataSize = 600;
160         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
161
162         log.appendAndPersist(logEntry, null, true);
163         verifyPersist(logEntry);
164
165         reset(mockPersistence);
166
167         logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
168
169         log.appendAndPersist(logEntry, null, true);
170         verifyPersist(logEntry);
171
172         assertEquals("size", 2, log.size());
173     }
174
175     @Test
176     public void testRemoveFromAndPersist() throws Exception {
177
178         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
179
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")));
183
184         log.removeFromAndPersist(1);
185
186         DeleteEntries deleteEntries = new DeleteEntries(1);
187         verifyPersist(deleteEntries, match(deleteEntries), false);
188
189         assertEquals("size", 1, log.size());
190
191         reset(mockPersistence);
192
193         log.removeFromAndPersist(1);
194
195         verifyNoMoreInteractions(mockPersistence);
196     }
197
198     public ArgumentMatcher<DeleteEntries> match(final DeleteEntries actual) {
199         return other -> actual.getFromIndex() == other.getFromIndex();
200     }
201 }