Bug 3020: Add version to AppendEntries and AppendEntriesReply
[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.Preconditions;
17 import com.google.common.base.Supplier;
18 import com.google.protobuf.GeneratedMessage;
19 import java.io.Serializable;
20 import java.util.HashMap;
21 import java.util.Map;
22 import org.opendaylight.controller.cluster.DataPersistenceProvider;
23 import org.opendaylight.controller.cluster.NonPersistentDataProvider;
24 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
25 import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages;
26 import org.opendaylight.controller.protobuff.messages.cluster.raft.test.MockPayloadMessages;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class MockRaftActorContext implements RaftActorContext {
31
32     private String id;
33     private ActorSystem system;
34     private ActorRef actor;
35     private long index = 0;
36     private long lastApplied = 0;
37     private final ElectionTerm electionTerm;
38     private ReplicatedLog replicatedLog;
39     private Map<String, String> peerAddresses = new HashMap<>();
40     private ConfigParams configParams;
41     private boolean snapshotCaptureInitiated;
42     private SnapshotManager snapshotManager;
43     private DataPersistenceProvider persistenceProvider = new NonPersistentDataProvider();
44     private short payloadVersion;
45
46     public MockRaftActorContext(){
47         electionTerm = new ElectionTerm() {
48             private long currentTerm = 1;
49             private String votedFor = "";
50
51             @Override
52             public long getCurrentTerm() {
53                 return currentTerm;
54             }
55
56             @Override
57             public String getVotedFor() {
58                 return votedFor;
59             }
60
61             @Override
62             public void update(long currentTerm, String votedFor){
63                 this.currentTerm = currentTerm;
64                 this.votedFor = votedFor;
65
66                 // TODO : Write to some persistent state
67             }
68
69             @Override public void updateAndPersist(long currentTerm,
70                 String votedFor) {
71                 update(currentTerm, votedFor);
72             }
73         };
74
75         configParams = new DefaultConfigParamsImpl();
76     }
77
78     public MockRaftActorContext(String id, ActorSystem system, ActorRef actor){
79         this();
80         this.id = id;
81         this.system = system;
82         this.actor = actor;
83
84         initReplicatedLog();
85     }
86
87
88     public void initReplicatedLog(){
89         this.replicatedLog = new SimpleReplicatedLog();
90         long term = getTermInformation().getCurrentTerm();
91         this.replicatedLog.append(new MockReplicatedLogEntry(term, 0, new MockPayload("1")));
92         this.replicatedLog.append(new MockReplicatedLogEntry(term, 1, new MockPayload("2")));
93     }
94
95     @Override public ActorRef actorOf(Props props) {
96         return system.actorOf(props);
97     }
98
99     @Override public ActorSelection actorSelection(String path) {
100         return system.actorSelection(path);
101     }
102
103     @Override public String getId() {
104         return id;
105     }
106
107     @Override public ActorRef getActor() {
108         return actor;
109     }
110
111     @Override public ElectionTerm getTermInformation() {
112         return electionTerm;
113     }
114
115     public void setIndex(long index){
116         this.index = index;
117     }
118
119     @Override public long getCommitIndex() {
120         return index;
121     }
122
123     @Override public void setCommitIndex(long commitIndex) {
124         this.index = commitIndex;
125     }
126
127     @Override public void setLastApplied(long lastApplied){
128         this.lastApplied = lastApplied;
129     }
130
131     @Override public long getLastApplied() {
132         return lastApplied;
133     }
134
135     @Override
136     // FIXME : A lot of tests try to manipulate the replicated log by setting it using this method
137     // This is OK to do if the underlyingActor is not RafActor or a derived class. If not then you should not
138     // used this way to manipulate the log because the RaftActor actually has a field replicatedLog
139     // which it creates internally and sets on the RaftActorContext
140     // The only right way to manipulate the replicated log therefore is to get it from either the RaftActor
141     // or the RaftActorContext and modify the entries in there instead of trying to replace it by using this setter
142     // Simple assertion that will fail if you do so
143     // ReplicatedLog log = new ReplicatedLogImpl();
144     // raftActor.underlyingActor().getRaftActorContext().setReplicatedLog(log);
145     // assertEquals(log, raftActor.underlyingActor().getReplicatedLog())
146     public void setReplicatedLog(ReplicatedLog replicatedLog) {
147         this.replicatedLog = replicatedLog;
148     }
149
150     @Override public ReplicatedLog getReplicatedLog() {
151         return replicatedLog;
152     }
153
154     @Override public ActorSystem getActorSystem() {
155         return this.system;
156     }
157
158     @Override public Logger getLogger() {
159         return LoggerFactory.getLogger(getClass());
160     }
161
162     @Override public Map<String, String> getPeerAddresses() {
163         return peerAddresses;
164     }
165
166     @Override public String getPeerAddress(String peerId) {
167         return peerAddresses.get(peerId);
168     }
169
170     @Override public void addToPeers(String name, String address) {
171         peerAddresses.put(name, address);
172     }
173
174     @Override public void removePeer(String name) {
175         peerAddresses.remove(name);
176     }
177
178     @Override public ActorSelection getPeerActorSelection(String peerId) {
179         String peerAddress = getPeerAddress(peerId);
180         if(peerAddress != null){
181             return actorSelection(peerAddress);
182         }
183         return null;
184     }
185
186     @Override public void setPeerAddress(String peerId, String peerAddress) {
187         Preconditions.checkState(peerAddresses.containsKey(peerId));
188         peerAddresses.put(peerId, peerAddress);
189     }
190
191     public void setPeerAddresses(Map<String, String> peerAddresses) {
192         this.peerAddresses = peerAddresses;
193     }
194
195     @Override
196     public ConfigParams getConfigParams() {
197         return configParams;
198     }
199
200     @Override
201     public SnapshotManager getSnapshotManager() {
202         if(this.snapshotManager == null){
203             this.snapshotManager = new SnapshotManager(this, getLogger());
204             this.snapshotManager.setCreateSnapshotCallable(NoopProcedure.<Void>instance());
205         }
206         return this.snapshotManager;
207     }
208
209     public void setConfigParams(ConfigParams configParams) {
210         this.configParams = configParams;
211     }
212
213     @Override
214     public long getTotalMemory() {
215         return Runtime.getRuntime().totalMemory();
216     }
217
218     @Override
219     public void setTotalMemoryRetriever(Supplier<Long> retriever) {
220     }
221
222     @Override
223     public boolean hasFollowers() {
224         return getPeerAddresses().keySet().size() > 0;
225     }
226
227     @Override
228     public DataPersistenceProvider getPersistenceProvider() {
229         return persistenceProvider;
230     }
231
232     public void setPersistenceProvider(DataPersistenceProvider persistenceProvider) {
233         this.persistenceProvider = persistenceProvider;
234     }
235
236     @Override
237     public short getPayloadVersion() {
238         return payloadVersion;
239     }
240
241     public void setPayloadVersion(short payloadVersion) {
242         this.payloadVersion = payloadVersion;
243     }
244
245     public static class SimpleReplicatedLog extends AbstractReplicatedLogImpl {
246         @Override public void appendAndPersist(
247             ReplicatedLogEntry replicatedLogEntry) {
248             append(replicatedLogEntry);
249         }
250
251         @Override
252         public int dataSize() {
253             return -1;
254         }
255
256         @Override public void removeFromAndPersist(long index) {
257             removeFrom(index);
258         }
259
260         @Override
261         public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry, Procedure<ReplicatedLogEntry> callback) {
262             append(replicatedLogEntry);
263
264             if(callback != null) {
265                 try {
266                     callback.apply(replicatedLogEntry);
267                 } catch (Exception e) {
268                     e.printStackTrace();
269                 }
270             }
271         }
272     }
273
274     public static class MockPayload extends Payload implements Serializable {
275         private static final long serialVersionUID = 3121380393130864247L;
276         private String value = "";
277         private int size;
278
279         public MockPayload() {
280         }
281
282         public MockPayload(String s) {
283             this.value = s;
284             size = value.length();
285         }
286
287         public MockPayload(String s, int size) {
288             this(s);
289             this.size = size;
290         }
291
292         @Override public Map<GeneratedMessage.GeneratedExtension<?, ?>, String> encode() {
293             Map<GeneratedMessage.GeneratedExtension<?, ?>, String> map = new HashMap<>();
294             map.put(MockPayloadMessages.value, value);
295             return map;
296         }
297
298         @Override public Payload decode(
299             AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payloadProtoBuff) {
300             String value = payloadProtoBuff.getExtension(MockPayloadMessages.value);
301             this.value = value;
302             return this;
303         }
304
305         @Override
306         public int size() {
307             return size;
308         }
309
310         @Override public String getClientPayloadClassName() {
311             return MockPayload.class.getName();
312         }
313
314         @Override
315         public String toString() {
316             return value;
317         }
318
319         @Override
320         public int hashCode() {
321             final int prime = 31;
322             int result = 1;
323             result = prime * result + ((value == null) ? 0 : value.hashCode());
324             return result;
325         }
326
327         @Override
328         public boolean equals(Object obj) {
329             if (this == obj) {
330                 return true;
331             }
332             if (obj == null) {
333                 return false;
334             }
335             if (getClass() != obj.getClass()) {
336                 return false;
337             }
338             MockPayload other = (MockPayload) obj;
339             if (value == null) {
340                 if (other.value != null) {
341                     return false;
342                 }
343             } else if (!value.equals(other.value)) {
344                 return false;
345             }
346             return true;
347         }
348     }
349
350     public static class MockReplicatedLogEntry implements ReplicatedLogEntry, Serializable {
351         private static final long serialVersionUID = 1L;
352
353         private final long term;
354         private final long index;
355         private final Payload data;
356
357         public MockReplicatedLogEntry(long term, long index, Payload data){
358
359             this.term = term;
360             this.index = index;
361             this.data = data;
362         }
363
364         @Override public Payload getData() {
365             return data;
366         }
367
368         @Override public long getTerm() {
369             return term;
370         }
371
372         @Override public long getIndex() {
373             return index;
374         }
375
376         @Override
377         public int size() {
378             return getData().size();
379         }
380
381         @Override
382         public int hashCode() {
383             final int prime = 31;
384             int result = 1;
385             result = prime * result + ((data == null) ? 0 : data.hashCode());
386             result = prime * result + (int) (index ^ (index >>> 32));
387             result = prime * result + (int) (term ^ (term >>> 32));
388             return result;
389         }
390
391         @Override
392         public boolean equals(Object obj) {
393             if (this == obj) {
394                 return true;
395             }
396             if (obj == null) {
397                 return false;
398             }
399             if (getClass() != obj.getClass()) {
400                 return false;
401             }
402             MockReplicatedLogEntry other = (MockReplicatedLogEntry) obj;
403             if (data == null) {
404                 if (other.data != null) {
405                     return false;
406                 }
407             } else if (!data.equals(other.data)) {
408                 return false;
409             }
410             if (index != other.index) {
411                 return false;
412             }
413             if (term != other.term) {
414                 return false;
415             }
416             return true;
417         }
418
419         @Override
420         public String toString() {
421             StringBuilder builder = new StringBuilder();
422             builder.append("MockReplicatedLogEntry [term=").append(term).append(", index=").append(index)
423                     .append(", data=").append(data).append("]");
424             return builder.toString();
425         }
426     }
427
428     public static class MockReplicatedLogBuilder {
429         private final ReplicatedLog mockLog = new SimpleReplicatedLog();
430
431         public  MockReplicatedLogBuilder createEntries(int start, int end, int term) {
432             for (int i=start; i<end; i++) {
433                 this.mockLog.append(new ReplicatedLogImplEntry(i, term, new MockRaftActorContext.MockPayload("foo" + i)));
434             }
435             return this;
436         }
437
438         public  MockReplicatedLogBuilder addEntry(int index, int term, MockPayload payload) {
439             this.mockLog.append(new ReplicatedLogImplEntry(index, term, payload));
440             return this;
441         }
442
443         public ReplicatedLog build() {
444             return this.mockLog;
445         }
446     }
447 }