6ae5731800049ec42d252bc22a1a9ed74c47adb9
[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 java.util.Collections;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.mockito.ArgumentCaptor;
24 import org.mockito.ArgumentMatcher;
25 import org.mockito.Mock;
26 import org.mockito.MockitoAnnotations;
27 import org.mockito.internal.matchers.Same;
28 import org.opendaylight.controller.cluster.DataPersistenceProvider;
29 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
30 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
31 import org.opendaylight.controller.cluster.raft.persisted.DeleteEntries;
32 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * Unit tests for ReplicatedLogImpl.
38  *
39  * @author Thomas Pantelis
40  */
41 public class ReplicatedLogImplTest {
42     private static final Logger LOG = LoggerFactory.getLogger(RaftActorRecoverySupportTest.class);
43
44     @Mock
45     private DataPersistenceProvider mockPersistence;
46
47     @Mock
48     private RaftActorBehavior mockBehavior;
49
50     private RaftActorContext context;
51     private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
52
53     @Before
54     public void setup() {
55         MockitoAnnotations.initMocks(this);
56
57         context = new RaftActorContextImpl(null, null, "test",
58                 new ElectionTermImpl(mockPersistence, "test", LOG), -1, -1, Collections.<String,String>emptyMap(),
59                 configParams, mockPersistence, applyState -> { }, LOG);
60     }
61
62     private void verifyPersist(Object message) throws Exception {
63         verifyPersist(message, new Same(message), true);
64     }
65
66     @SuppressWarnings({ "unchecked", "rawtypes" })
67     private void verifyPersist(Object message, ArgumentMatcher<?> matcher, boolean async) throws Exception {
68         ArgumentCaptor<Procedure> procedure = ArgumentCaptor.forClass(Procedure.class);
69         if (async) {
70             verify(mockPersistence).persistAsync(argThat(matcher), procedure.capture());
71         } else {
72             verify(mockPersistence).persist(argThat(matcher), procedure.capture());
73         }
74
75         procedure.getValue().apply(message);
76     }
77
78     @SuppressWarnings("unchecked")
79     @Test
80     public void testAppendAndPersistExpectingNoCapture() throws Exception {
81         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
82
83         ReplicatedLogEntry logEntry1 = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
84
85         log.appendAndPersist(logEntry1, null, true);
86
87         verifyPersist(logEntry1);
88
89         assertEquals("size", 1, log.size());
90
91         reset(mockPersistence);
92
93         ReplicatedLogEntry logEntry2 = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2"));
94         Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
95         log.appendAndPersist(logEntry2, mockCallback, true);
96
97         verifyPersist(logEntry2);
98
99         verify(mockCallback).apply(same(logEntry2));
100
101         assertEquals("size", 2, log.size());
102     }
103
104     @SuppressWarnings("unchecked")
105     @Test
106     public void testAppendAndPersisWithDuplicateEntry() throws Exception {
107         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
108
109         Procedure<ReplicatedLogEntry> mockCallback = mock(Procedure.class);
110         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockPayload("1"));
111
112         log.appendAndPersist(logEntry, mockCallback, true);
113
114         verifyPersist(logEntry);
115
116         assertEquals("size", 1, log.size());
117
118         reset(mockPersistence, mockCallback);
119
120         log.appendAndPersist(logEntry, mockCallback, true);
121
122         verifyNoMoreInteractions(mockPersistence, mockCallback);
123
124         assertEquals("size", 1, log.size());
125     }
126
127     @Test
128     public void testAppendAndPersistExpectingCaptureDueToJournalCount() throws Exception {
129         configParams.setSnapshotBatchCount(2);
130
131         doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
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         doReturn(1L).when(mockBehavior).getReplicatedToAllIndex();
153
154         context.setTotalMemoryRetriever(() -> 100);
155
156         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
157
158         int dataSize = 600;
159         ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(2, 1, new MockPayload("2", dataSize));
160
161         log.appendAndPersist(logEntry, null, true);
162         verifyPersist(logEntry);
163
164         reset(mockPersistence);
165
166         logEntry = new SimpleReplicatedLogEntry(3, 1, new MockPayload("3", 5));
167
168         log.appendAndPersist(logEntry, null, true);
169         verifyPersist(logEntry);
170
171         assertEquals("size", 2, log.size());
172     }
173
174     @Test
175     public void testRemoveFromAndPersist() throws Exception {
176
177         ReplicatedLog log = ReplicatedLogImpl.newInstance(context);
178
179         log.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("0")));
180         log.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("1")));
181         log.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("2")));
182
183         log.removeFromAndPersist(1);
184
185         DeleteEntries deleteEntries = new DeleteEntries(1);
186         verifyPersist(deleteEntries, match(deleteEntries), false);
187
188         assertEquals("size", 1, log.size());
189
190         reset(mockPersistence);
191
192         log.removeFromAndPersist(1);
193
194         verifyNoMoreInteractions(mockPersistence);
195     }
196
197     public ArgumentMatcher<DeleteEntries> match(final DeleteEntries actual) {
198         return other -> actual.getFromIndex() == other.getFromIndex();
199     }
200 }