Bug 7362: Notify applyState synchronously
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / MockRaftActorContext.java
1 /*
2  * Copyright (c) 2014 Cisco 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
9 package org.opendaylight.controller.cluster.raft;
10
11 import akka.actor.ActorRef;
12 import akka.actor.ActorSelection;
13 import akka.actor.ActorSystem;
14 import akka.actor.Props;
15 import akka.japi.Procedure;
16 import com.google.common.base.Throwables;
17 import java.io.Serializable;
18 import java.util.HashMap;
19 import java.util.Map;
20 import org.opendaylight.controller.cluster.NonPersistentDataProvider;
21 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
22 import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
23 import org.opendaylight.controller.cluster.raft.policy.RaftPolicy;
24 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 public class MockRaftActorContext extends RaftActorContextImpl {
29     private static final Logger LOG = LoggerFactory.getLogger(MockRaftActorContext.class);
30
31     private ActorSystem system;
32     private RaftPolicy raftPolicy;
33
34     private static ElectionTerm newElectionTerm() {
35         return new ElectionTerm() {
36             private long currentTerm = 1;
37             private String votedFor = "";
38
39             @Override
40             public long getCurrentTerm() {
41                 return currentTerm;
42             }
43
44             @Override
45             public String getVotedFor() {
46                 return votedFor;
47             }
48
49             @Override
50             public void update(long newTerm, String newVotedFor) {
51                 this.currentTerm = newTerm;
52                 this.votedFor = newVotedFor;
53
54                 // TODO : Write to some persistent state
55             }
56
57             @Override public void updateAndPersist(long newTerm, String newVotedFor) {
58                 update(newTerm, newVotedFor);
59             }
60         };
61     }
62
63     public MockRaftActorContext() {
64         super(null, null, "test", newElectionTerm(), -1, -1, new HashMap<>(),
65                 new DefaultConfigParamsImpl(), new NonPersistentDataProvider(), applyState -> { }, LOG);
66         setReplicatedLog(new MockReplicatedLogBuilder().build());
67     }
68
69     public MockRaftActorContext(String id, ActorSystem system, ActorRef actor) {
70         super(actor, null, id, newElectionTerm(), -1, -1, new HashMap<>(),
71             new DefaultConfigParamsImpl(), new NonPersistentDataProvider(),
72             applyState -> actor.tell(applyState, actor), LOG);
73
74         this.system = system;
75
76         initReplicatedLog();
77     }
78
79
80     public void initReplicatedLog() {
81         SimpleReplicatedLog replicatedLog = new SimpleReplicatedLog();
82         long term = getTermInformation().getCurrentTerm();
83         replicatedLog.append(new SimpleReplicatedLogEntry(0, term, new MockPayload("1")));
84         replicatedLog.append(new SimpleReplicatedLogEntry(1, term, new MockPayload("2")));
85         setReplicatedLog(replicatedLog);
86         setCommitIndex(replicatedLog.lastIndex());
87         setLastApplied(replicatedLog.lastIndex());
88     }
89
90     @Override public ActorRef actorOf(Props props) {
91         return system.actorOf(props);
92     }
93
94     @Override public ActorSelection actorSelection(String path) {
95         return system.actorSelection(path);
96     }
97
98     @Override public ActorSystem getActorSystem() {
99         return this.system;
100     }
101
102     @Override public ActorSelection getPeerActorSelection(String peerId) {
103         String peerAddress = getPeerAddress(peerId);
104         if (peerAddress != null) {
105             return actorSelection(peerAddress);
106         }
107         return null;
108     }
109
110     public void setPeerAddresses(Map<String, String> peerAddresses) {
111         for (String id: getPeerIds()) {
112             removePeer(id);
113         }
114
115         for (Map.Entry<String, String> e: peerAddresses.entrySet()) {
116             addToPeers(e.getKey(), e.getValue(), VotingState.VOTING);
117         }
118     }
119
120     @Override
121     public SnapshotManager getSnapshotManager() {
122         SnapshotManager snapshotManager = super.getSnapshotManager();
123         snapshotManager.setCreateSnapshotRunnable(() -> { });
124         return snapshotManager;
125     }
126
127     @Override
128     public RaftPolicy getRaftPolicy() {
129         return raftPolicy != null ? raftPolicy : super.getRaftPolicy();
130     }
131
132     public void setRaftPolicy(RaftPolicy raftPolicy) {
133         this.raftPolicy = raftPolicy;
134     }
135
136     public static class SimpleReplicatedLog extends AbstractReplicatedLogImpl {
137         @Override
138         public int dataSize() {
139             return -1;
140         }
141
142         @Override
143         public void captureSnapshotIfReady(ReplicatedLogEntry replicatedLogEntry) {
144         }
145
146         @Override
147         public boolean shouldCaptureSnapshot(long logIndex) {
148             return false;
149         }
150
151         @Override
152         public boolean removeFromAndPersist(long index) {
153             return removeFrom(index) >= 0;
154         }
155
156         @Override
157         @SuppressWarnings("checkstyle:IllegalCatch")
158         public boolean appendAndPersist(ReplicatedLogEntry replicatedLogEntry, Procedure<ReplicatedLogEntry> callback,
159                 boolean doAsync) {
160             append(replicatedLogEntry);
161
162             if (callback != null) {
163                 try {
164                     callback.apply(replicatedLogEntry);
165                 } catch (Exception e) {
166                     Throwables.propagate(e);
167                 }
168             }
169
170             return true;
171         }
172     }
173
174     public static class MockPayload extends Payload implements Serializable {
175         private static final long serialVersionUID = 3121380393130864247L;
176         private String value = "";
177         private int size;
178
179         public MockPayload() {
180         }
181
182         public MockPayload(String data) {
183             this.value = data;
184             size = value.length();
185         }
186
187         public MockPayload(String data, int size) {
188             this(data);
189             this.size = size;
190         }
191
192         @Override
193         public int size() {
194             return size;
195         }
196
197         @Override
198         public String toString() {
199             return value;
200         }
201
202         @Override
203         public int hashCode() {
204             final int prime = 31;
205             int result = 1;
206             result = prime * result + (value == null ? 0 : value.hashCode());
207             return result;
208         }
209
210         @Override
211         public boolean equals(Object obj) {
212             if (this == obj) {
213                 return true;
214             }
215             if (obj == null) {
216                 return false;
217             }
218             if (getClass() != obj.getClass()) {
219                 return false;
220             }
221             MockPayload other = (MockPayload) obj;
222             if (value == null) {
223                 if (other.value != null) {
224                     return false;
225                 }
226             } else if (!value.equals(other.value)) {
227                 return false;
228             }
229             return true;
230         }
231     }
232
233     public static class MockReplicatedLogBuilder {
234         private final ReplicatedLog mockLog = new SimpleReplicatedLog();
235
236         public  MockReplicatedLogBuilder createEntries(int start, int end, int term) {
237             for (int i = start; i < end; i++) {
238                 this.mockLog.append(new SimpleReplicatedLogEntry(i, term,
239                         new MockRaftActorContext.MockPayload(Integer.toString(i))));
240             }
241             return this;
242         }
243
244         public  MockReplicatedLogBuilder addEntry(int index, int term, MockPayload payload) {
245             this.mockLog.append(new SimpleReplicatedLogEntry(index, term, payload));
246             return this;
247         }
248
249         public ReplicatedLog build() {
250             return this.mockLog;
251         }
252     }
253
254     @Override
255     public void setCurrentBehavior(final RaftActorBehavior behavior) {
256         super.setCurrentBehavior(behavior);
257     }
258 }