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