e19b5216103757bafada5d9659c913c9de79c3e5
[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
247         public void appendAndPersist(
248             ReplicatedLogEntry replicatedLogEntry) {
249             append(replicatedLogEntry);
250         }
251
252         @Override
253         public int dataSize() {
254             return -1;
255         }
256
257         @Override
258         public void captureSnapshotIfReady(ReplicatedLogEntry replicatedLogEntry) {
259         }
260
261         @Override public void removeFromAndPersist(long index) {
262             removeFrom(index);
263         }
264
265         @Override
266         public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry, Procedure<ReplicatedLogEntry> callback) {
267             append(replicatedLogEntry);
268
269             if(callback != null) {
270                 try {
271                     callback.apply(replicatedLogEntry);
272                 } catch (Exception e) {
273                     e.printStackTrace();
274                 }
275             }
276         }
277     }
278
279     public static class MockPayload extends Payload implements Serializable {
280         private static final long serialVersionUID = 3121380393130864247L;
281         private String value = "";
282         private int size;
283
284         public MockPayload() {
285         }
286
287         public MockPayload(String s) {
288             this.value = s;
289             size = value.length();
290         }
291
292         public MockPayload(String s, int size) {
293             this(s);
294             this.size = size;
295         }
296
297         @Override public Map<GeneratedMessage.GeneratedExtension<?, ?>, String> encode() {
298             Map<GeneratedMessage.GeneratedExtension<?, ?>, String> map = new HashMap<>();
299             map.put(MockPayloadMessages.value, value);
300             return map;
301         }
302
303         @Override public Payload decode(
304             AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payloadProtoBuff) {
305             String value = payloadProtoBuff.getExtension(MockPayloadMessages.value);
306             this.value = value;
307             return this;
308         }
309
310         @Override
311         public int size() {
312             return size;
313         }
314
315         @Override public String getClientPayloadClassName() {
316             return MockPayload.class.getName();
317         }
318
319         @Override
320         public String toString() {
321             return value;
322         }
323
324         @Override
325         public int hashCode() {
326             final int prime = 31;
327             int result = 1;
328             result = prime * result + ((value == null) ? 0 : value.hashCode());
329             return result;
330         }
331
332         @Override
333         public boolean equals(Object obj) {
334             if (this == obj) {
335                 return true;
336             }
337             if (obj == null) {
338                 return false;
339             }
340             if (getClass() != obj.getClass()) {
341                 return false;
342             }
343             MockPayload other = (MockPayload) obj;
344             if (value == null) {
345                 if (other.value != null) {
346                     return false;
347                 }
348             } else if (!value.equals(other.value)) {
349                 return false;
350             }
351             return true;
352         }
353     }
354
355     public static class MockReplicatedLogEntry implements ReplicatedLogEntry, Serializable {
356         private static final long serialVersionUID = 1L;
357
358         private final long term;
359         private final long index;
360         private final Payload data;
361
362         public MockReplicatedLogEntry(long term, long index, Payload data){
363
364             this.term = term;
365             this.index = index;
366             this.data = data;
367         }
368
369         @Override public Payload getData() {
370             return data;
371         }
372
373         @Override public long getTerm() {
374             return term;
375         }
376
377         @Override public long getIndex() {
378             return index;
379         }
380
381         @Override
382         public int size() {
383             return getData().size();
384         }
385
386         @Override
387         public int hashCode() {
388             final int prime = 31;
389             int result = 1;
390             result = prime * result + ((data == null) ? 0 : data.hashCode());
391             result = prime * result + (int) (index ^ (index >>> 32));
392             result = prime * result + (int) (term ^ (term >>> 32));
393             return result;
394         }
395
396         @Override
397         public boolean equals(Object obj) {
398             if (this == obj) {
399                 return true;
400             }
401             if (obj == null) {
402                 return false;
403             }
404             if (getClass() != obj.getClass()) {
405                 return false;
406             }
407             MockReplicatedLogEntry other = (MockReplicatedLogEntry) obj;
408             if (data == null) {
409                 if (other.data != null) {
410                     return false;
411                 }
412             } else if (!data.equals(other.data)) {
413                 return false;
414             }
415             if (index != other.index) {
416                 return false;
417             }
418             if (term != other.term) {
419                 return false;
420             }
421             return true;
422         }
423
424         @Override
425         public String toString() {
426             StringBuilder builder = new StringBuilder();
427             builder.append("MockReplicatedLogEntry [term=").append(term).append(", index=").append(index)
428                     .append(", data=").append(data).append("]");
429             return builder.toString();
430         }
431     }
432
433     public static class MockReplicatedLogBuilder {
434         private final ReplicatedLog mockLog = new SimpleReplicatedLog();
435
436         public  MockReplicatedLogBuilder createEntries(int start, int end, int term) {
437             for (int i=start; i<end; i++) {
438                 this.mockLog.append(new ReplicatedLogImplEntry(i, term, new MockRaftActorContext.MockPayload("foo" + i)));
439             }
440             return this;
441         }
442
443         public  MockReplicatedLogBuilder addEntry(int index, int term, MockPayload payload) {
444             this.mockLog.append(new ReplicatedLogImplEntry(index, term, payload));
445             return this;
446         }
447
448         public ReplicatedLog build() {
449             return this.mockLog;
450         }
451     }
452 }