blob: 81ddce02aa7bb8ffc09814792b4c3c82985139b1 [file] [log] [blame]
Ayaka Koshibe8583ff32014-10-02 16:25:30 -07001package org.onlab.onos.store.cluster.impl;
2
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertNull;
5import static org.junit.Assert.assertTrue;
6import static org.onlab.onos.net.MastershipRole.*;
7
8import java.util.Set;
9
10import org.junit.After;
11import org.junit.AfterClass;
12import org.junit.Before;
13import org.junit.BeforeClass;
14import org.junit.Test;
15import org.onlab.onos.cluster.ClusterEventListener;
16import org.onlab.onos.cluster.ClusterService;
17import org.onlab.onos.cluster.ControllerNode;
18import org.onlab.onos.cluster.ControllerNode.State;
19import org.onlab.onos.cluster.DefaultControllerNode;
20import org.onlab.onos.cluster.MastershipEvent.Type;
21import org.onlab.onos.cluster.MastershipTerm;
22import org.onlab.onos.cluster.NodeId;
23import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.store.common.StoreManager;
25import org.onlab.onos.store.common.StoreService;
26import org.onlab.onos.store.common.TestStoreManager;
27import org.onlab.onos.store.serializers.KryoSerializationManager;
28import org.onlab.onos.store.serializers.KryoSerializationService;
29import org.onlab.packet.IpPrefix;
30
31import com.google.common.collect.Sets;
32import com.hazelcast.config.Config;
33import com.hazelcast.core.Hazelcast;
34
35/**
36 * Test of the Hazelcast-based distributed MastershipStore implementation.
37 */
38public class DistributedMastershipStoreTest {
39
40 private static final DeviceId DID1 = DeviceId.deviceId("of:01");
41 private static final DeviceId DID2 = DeviceId.deviceId("of:02");
42 private static final DeviceId DID3 = DeviceId.deviceId("of:03");
43 private static final DeviceId DID4 = DeviceId.deviceId("of:04");
44
45 private static final IpPrefix IP = IpPrefix.valueOf("127.0.0.1");
46
47 private static final NodeId N1 = new NodeId("node1");
48 private static final NodeId N2 = new NodeId("node2");
49
50 private static final ControllerNode CN1 = new DefaultControllerNode(N1, IP);
51 private static final ControllerNode CN2 = new DefaultControllerNode(N2, IP);
52
53 private DistributedMastershipStore dms;
54 private TestDistributedMastershipStore testStore;
55 private KryoSerializationManager serializationMgr;
56 private StoreManager storeMgr;
57
58 @BeforeClass
59 public static void setUpBeforeClass() throws Exception {
60 }
61
62 @AfterClass
63 public static void tearDownAfterClass() throws Exception {
64 }
65
66 @Before
67 public void setUp() throws Exception {
68 // TODO should find a way to clean Hazelcast instance without shutdown.
69 Config config = TestStoreManager.getTestConfig();
70
71 storeMgr = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
72 storeMgr.activate();
73
74 serializationMgr = new KryoSerializationManager();
75 serializationMgr.activate();
76
77 dms = new TestDistributedMastershipStore(storeMgr, serializationMgr);
78 dms.clusterService = new TestClusterService();
79 dms.activate();
80
81 testStore = (TestDistributedMastershipStore) dms;
82 }
83
84 @After
85 public void tearDown() throws Exception {
86 dms.deactivate();
87
88 serializationMgr.deactivate();
89
90 storeMgr.deactivate();
91 }
92
93 @Test
94 public void getRole() {
95 assertEquals("wrong role:", NONE, dms.getRole(N1, DID1));
96 testStore.put(DID1, N1, true, true, true);
97 assertEquals("wrong role:", MASTER, dms.getRole(N1, DID1));
98 assertEquals("wrong role:", STANDBY, dms.getRole(N2, DID1));
99 }
100
101 @Test
102 public void getMaster() {
103 assertTrue("wrong store state:", dms.rawMasters.isEmpty());
104
105 testStore.put(DID1, N1, true, false, false);
106 assertEquals("wrong master:", N1, dms.getMaster(DID1));
107 assertNull("wrong master:", dms.getMaster(DID2));
108 }
109
110 @Test
111 public void getDevices() {
112 assertTrue("wrong store state:", dms.rawMasters.isEmpty());
113
114 testStore.put(DID1, N1, true, false, false);
115 testStore.put(DID2, N1, true, false, false);
116 testStore.put(DID3, N2, true, false, false);
117
118 assertEquals("wrong devices",
119 Sets.newHashSet(DID1, DID2), dms.getDevices(N1));
120 }
121
122 @Test
123 public void requestRoleAndTerm() {
124 //CN1 is "local"
125 testStore.setCurrent(CN1);
126
127 //if already MASTER, nothing should happen
128 testStore.put(DID2, N1, true, false, false);
129 assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2));
130 assertTrue("wrong state for store:",
131 dms.backups.isEmpty() & dms.rawTerms.isEmpty());
132
133 //populate maps with DID1, N1 thru NONE case
134 assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
135 assertTrue("wrong state for store:",
136 !dms.backups.isEmpty() & !dms.rawTerms.isEmpty());
137 assertEquals("wrong term",
138 MastershipTerm.of(N1, 0), dms.getTermFor(DID1));
139
140 //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY
141 testStore.setCurrent(CN2);
142 assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2));
143 assertEquals("wrong number of entries:", 2, dms.rawTerms.size());
144
145 //change term and requestRole() again; should persist
146 testStore.increment(DID2);
147 assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2));
148 assertEquals("wrong term", MastershipTerm.of(N1, 1), dms.getTermFor(DID2));
149 }
150
151 @Test
152 public void setMaster() {
153 //populate maps with DID1, N1 as MASTER thru NONE case
154 testStore.setCurrent(CN1);
155 assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
156 assertNull("wrong event:", dms.setMaster(N1, DID1));
157
158 //switch over to N2
159 assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID1).type());
160 assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID1));
161
162 //orphan switch - should be rare case
163 assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type());
164 assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2));
165 //disconnect and reconnect - sign of failing re-election or single-instance channel
166 testStore.reset(true, false, false);
167 dms.setMaster(N2, DID2);
168 assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
169 }
170
171 @Test
172 public void unsetMaster() {
173 //populate maps with DID1, N1 as MASTER thru NONE case
174 testStore.setCurrent(CN1);
175 assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
176 //no backup, no new MASTER/event
177 assertNull("wrong event:", dms.unsetMaster(N1, DID1));
178 //add backup CN2, get it elected MASTER
179 dms.requestRole(DID1);
180 testStore.setCurrent(CN2);
181 dms.requestRole(DID1);
182 assertEquals("wrong event:", Type.MASTER_CHANGED, dms.unsetMaster(N1, DID1).type());
183 assertEquals("wrong master", N2, dms.getMaster(DID1));
184
185 //STANDBY - nothing here, either
186 assertNull("wrong event:", dms.unsetMaster(N1, DID1));
187 assertEquals("wrong role for node:", STANDBY, dms.getRole(N1, DID1));
188
189 //NONE - nothing happens
190 assertNull("wrong event:", dms.unsetMaster(N1, DID2));
191 assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID2));
192 }
193
194 private class TestDistributedMastershipStore extends
195 DistributedMastershipStore {
196 public TestDistributedMastershipStore(StoreService storeService,
197 KryoSerializationService kryoSerializationService) {
198 this.storeService = storeService;
199 this.kryoSerializationService = kryoSerializationService;
200 }
201
202 //helper to populate master/backup structures
203 public void put(DeviceId dev, NodeId node,
204 boolean store, boolean backup, boolean term) {
205 if (store) {
206 dms.rawMasters.put(serialize(dev), serialize(node));
207 }
208 if (backup) {
209 dms.backups.put(serialize(node), (byte) 0);
210 }
211 if (term) {
212 dms.rawTerms.put(serialize(dev), 0);
213 }
214 }
215
216 //clears structures
217 public void reset(boolean store, boolean backup, boolean term) {
218 if (store) {
219 dms.rawMasters.clear();
220 }
221 if (backup) {
222 dms.backups.clear();
223 }
224 if (term) {
225 dms.rawTerms.clear();
226 }
227 }
228
229 //increment term for a device
230 public void increment(DeviceId dev) {
231 Integer t = dms.rawTerms.get(serialize(dev));
232 if (t != null) {
233 dms.rawTerms.put(serialize(dev), ++t);
234 }
235 }
236
237 //sets the "local" node
238 public void setCurrent(ControllerNode node) {
239 ((TestClusterService) clusterService).current = node;
240 }
241 }
242
243 private class TestClusterService implements ClusterService {
244
245 protected ControllerNode current;
246
247 @Override
248 public ControllerNode getLocalNode() {
249 return current;
250 }
251
252 @Override
253 public Set<ControllerNode> getNodes() {
254 return Sets.newHashSet(CN1, CN2);
255 }
256
257 @Override
258 public ControllerNode getNode(NodeId nodeId) {
259 return null;
260 }
261
262 @Override
263 public State getState(NodeId nodeId) {
264 return null;
265 }
266
267 @Override
268 public void addListener(ClusterEventListener listener) {
269 }
270
271 @Override
272 public void removeListener(ClusterEventListener listener) {
273 }
274
275 }
276}