53110b3583a4f7353e3d17b1ec7ac91bf8ec7891
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / MockRaftActor.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.controller.cluster.raft;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.mockito.Mockito.mock;
13 import akka.actor.ActorRef;
14 import akka.actor.Props;
15 import akka.japi.Creator;
16 import com.google.common.base.Optional;
17 import com.google.common.util.concurrent.Uninterruptibles;
18 import java.io.ByteArrayInputStream;
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.concurrent.CountDownLatch;
25 import java.util.concurrent.TimeUnit;
26 import javax.annotation.Nonnull;
27 import org.opendaylight.controller.cluster.DataPersistenceProvider;
28 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
29
30 public class MockRaftActor extends RaftActor implements RaftActorRecoveryCohort, RaftActorSnapshotCohort {
31
32     final RaftActor actorDelegate;
33     final RaftActorRecoveryCohort recoveryCohortDelegate;
34     final RaftActorSnapshotCohort snapshotCohortDelegate;
35     private final CountDownLatch recoveryComplete = new CountDownLatch(1);
36     private final List<Object> state;
37     private ActorRef roleChangeNotifier;
38     private final CountDownLatch initializeBehaviorComplete = new CountDownLatch(1);
39     private RaftActorRecoverySupport raftActorRecoverySupport;
40     private RaftActorSnapshotMessageSupport snapshotMessageSupport;
41
42     public static final class MockRaftActorCreator implements Creator<MockRaftActor> {
43         private static final long serialVersionUID = 1L;
44         private final Map<String, String> peerAddresses;
45         private final String id;
46         private final Optional<ConfigParams> config;
47         private final DataPersistenceProvider dataPersistenceProvider;
48         private final ActorRef roleChangeNotifier;
49         private RaftActorSnapshotMessageSupport snapshotMessageSupport;
50
51         private MockRaftActorCreator(Map<String, String> peerAddresses, String id,
52             Optional<ConfigParams> config, DataPersistenceProvider dataPersistenceProvider,
53             ActorRef roleChangeNotifier) {
54             this.peerAddresses = peerAddresses;
55             this.id = id;
56             this.config = config;
57             this.dataPersistenceProvider = dataPersistenceProvider;
58             this.roleChangeNotifier = roleChangeNotifier;
59         }
60
61         @Override
62         public MockRaftActor create() throws Exception {
63             MockRaftActor mockRaftActor = new MockRaftActor(id, peerAddresses, config,
64                 dataPersistenceProvider);
65             mockRaftActor.roleChangeNotifier = this.roleChangeNotifier;
66             mockRaftActor.snapshotMessageSupport = snapshotMessageSupport;
67             return mockRaftActor;
68         }
69     }
70
71     public MockRaftActor(String id, Map<String, String> peerAddresses, Optional<ConfigParams> config,
72                          DataPersistenceProvider dataPersistenceProvider) {
73         super(id, peerAddresses, config);
74         state = new ArrayList<>();
75         this.actorDelegate = mock(RaftActor.class);
76         this.recoveryCohortDelegate = mock(RaftActorRecoveryCohort.class);
77         this.snapshotCohortDelegate = mock(RaftActorSnapshotCohort.class);
78         if(dataPersistenceProvider == null){
79             setPersistence(true);
80         } else {
81             setPersistence(dataPersistenceProvider);
82         }
83     }
84
85     public void setRaftActorRecoverySupport(RaftActorRecoverySupport support) {
86         raftActorRecoverySupport = support;
87     }
88
89     @Override
90     public RaftActorRecoverySupport newRaftActorRecoverySupport() {
91         return raftActorRecoverySupport != null ? raftActorRecoverySupport : super.newRaftActorRecoverySupport();
92     }
93
94     @Override
95     protected RaftActorSnapshotMessageSupport newRaftActorSnapshotMessageSupport() {
96         return snapshotMessageSupport != null ? snapshotMessageSupport : super.newRaftActorSnapshotMessageSupport();
97     }
98
99     public void waitForRecoveryComplete() {
100         try {
101             assertEquals("Recovery complete", true, recoveryComplete.await(5,  TimeUnit.SECONDS));
102         } catch (InterruptedException e) {
103             e.printStackTrace();
104         }
105     }
106
107     public void waitForInitializeBehaviorComplete() {
108         try {
109             assertEquals("Behavior initialized", true, initializeBehaviorComplete.await(5,  TimeUnit.SECONDS));
110         } catch (InterruptedException e) {
111             e.printStackTrace();
112         }
113     }
114
115
116     public void waitUntilLeader(){
117         for(int i = 0;i < 10; i++){
118             if(isLeader()){
119                 break;
120             }
121             Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
122         }
123     }
124
125     public List<Object> getState() {
126         return state;
127     }
128
129     public static Props props(final String id, final Map<String, String> peerAddresses,
130             Optional<ConfigParams> config){
131         return Props.create(new MockRaftActorCreator(peerAddresses, id, config, null, null));
132     }
133
134     public static Props props(final String id, final Map<String, String> peerAddresses,
135             Optional<ConfigParams> config, RaftActorSnapshotMessageSupport snapshotMessageSupport){
136         MockRaftActorCreator creator = new MockRaftActorCreator(peerAddresses, id, config, null, null);
137         creator.snapshotMessageSupport = snapshotMessageSupport;
138         return Props.create(creator);
139     }
140
141     public static Props props(final String id, final Map<String, String> peerAddresses,
142                               Optional<ConfigParams> config, DataPersistenceProvider dataPersistenceProvider){
143         return Props.create(new MockRaftActorCreator(peerAddresses, id, config, dataPersistenceProvider, null));
144     }
145
146     public static Props props(final String id, final Map<String, String> peerAddresses,
147         Optional<ConfigParams> config, ActorRef roleChangeNotifier){
148         return Props.create(new MockRaftActorCreator(peerAddresses, id, config, null, roleChangeNotifier));
149     }
150
151     public static Props props(final String id, final Map<String, String> peerAddresses,
152                               Optional<ConfigParams> config, ActorRef roleChangeNotifier,
153                               DataPersistenceProvider dataPersistenceProvider){
154         return Props.create(new MockRaftActorCreator(peerAddresses, id, config, dataPersistenceProvider, roleChangeNotifier));
155     }
156
157
158     @Override protected void applyState(ActorRef clientActor, String identifier, Object data) {
159         actorDelegate.applyState(clientActor, identifier, data);
160         LOG.info("{}: applyState called", persistenceId());
161     }
162
163     @Override
164     @Nonnull
165     protected RaftActorRecoveryCohort getRaftActorRecoveryCohort() {
166         return this;
167     }
168
169     @Override
170     protected RaftActorSnapshotCohort getRaftActorSnapshotCohort() {
171         return this;
172     }
173
174     @Override
175     public void startLogRecoveryBatch(int maxBatchSize) {
176     }
177
178     @Override
179     public void appendRecoveredLogEntry(Payload data) {
180         state.add(data);
181     }
182
183     @Override
184     public void applyCurrentLogRecoveryBatch() {
185     }
186
187     @Override
188     protected void onRecoveryComplete() {
189         actorDelegate.onRecoveryComplete();
190         recoveryComplete.countDown();
191     }
192
193     @Override
194     protected void initializeBehavior() {
195         super.initializeBehavior();
196         initializeBehaviorComplete.countDown();
197     }
198
199     @Override
200     public void applyRecoverySnapshot(byte[] bytes) {
201         recoveryCohortDelegate.applyRecoverySnapshot(bytes);
202         try {
203             Object data = toObject(bytes);
204             if (data instanceof List) {
205                 state.addAll((List<?>) data);
206             }
207         } catch (Exception e) {
208             e.printStackTrace();
209         }
210     }
211
212     @Override
213     public void createSnapshot(ActorRef actorRef) {
214         LOG.info("{}: createSnapshot called", persistenceId());
215         snapshotCohortDelegate.createSnapshot(actorRef);
216     }
217
218     @Override
219     public void applySnapshot(byte [] snapshot) {
220         LOG.info("{}: applySnapshot called", persistenceId());
221         snapshotCohortDelegate.applySnapshot(snapshot);
222     }
223
224     @Override
225     protected void onStateChanged() {
226         actorDelegate.onStateChanged();
227     }
228
229     @Override
230     protected Optional<ActorRef> getRoleChangeNotifier() {
231         return Optional.fromNullable(roleChangeNotifier);
232     }
233
234     @Override public String persistenceId() {
235         return this.getId();
236     }
237
238     private Object toObject(byte[] bs) throws ClassNotFoundException, IOException {
239         Object obj = null;
240         ByteArrayInputStream bis = null;
241         ObjectInputStream ois = null;
242         try {
243             bis = new ByteArrayInputStream(bs);
244             ois = new ObjectInputStream(bis);
245             obj = ois.readObject();
246         } finally {
247             if (bis != null) {
248                 bis.close();
249             }
250             if (ois != null) {
251                 ois.close();
252             }
253         }
254         return obj;
255     }
256
257     public ReplicatedLog getReplicatedLog(){
258         return this.getRaftActorContext().getReplicatedLog();
259     }
260 }