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