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