blob: 0b7040119ab75b53ad500b31cae5483f780aebcc [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.mastership.impl;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070017
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070018/**
19 * Test of the Hazelcast-based distributed MastershipStore implementation.
20 */
21public class DistributedMastershipStoreTest {
Thomas Vachuskaba082b82015-05-20 13:47:38 -070022/*
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070023 private static final DeviceId DID1 = DeviceId.deviceId("of:01");
24 private static final DeviceId DID2 = DeviceId.deviceId("of:02");
25 private static final DeviceId DID3 = DeviceId.deviceId("of:03");
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070026
Pavlin Radoslavov444b5192014-10-28 10:45:19 -070027 private static final IpAddress IP = IpAddress.valueOf("127.0.0.1");
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070028
29 private static final NodeId N1 = new NodeId("node1");
30 private static final NodeId N2 = new NodeId("node2");
31
32 private static final ControllerNode CN1 = new DefaultControllerNode(N1, IP);
33 private static final ControllerNode CN2 = new DefaultControllerNode(N2, IP);
34
35 private DistributedMastershipStore dms;
36 private TestDistributedMastershipStore testStore;
Ayaka Koshibe4c891272014-10-08 17:14:16 -070037 private KryoSerializer serializationMgr;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070038 private StoreManager storeMgr;
39
40 @BeforeClass
41 public static void setUpBeforeClass() throws Exception {
42 }
43
44 @AfterClass
45 public static void tearDownAfterClass() throws Exception {
46 }
47
48 @Before
49 public void setUp() throws Exception {
50 // TODO should find a way to clean Hazelcast instance without shutdown.
Yuta HIGUCHI151cad82015-02-04 23:26:50 -080051 TestStoreManager testStoreMgr = new TestStoreManager();
52 testStoreMgr.setHazelcastInstance(testStoreMgr.initSingleInstance());
53 storeMgr = testStoreMgr;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070054 storeMgr.activate();
55
Ayaka Koshibe4c891272014-10-08 17:14:16 -070056 serializationMgr = new KryoSerializer();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070057
58 dms = new TestDistributedMastershipStore(storeMgr, serializationMgr);
59 dms.clusterService = new TestClusterService();
60 dms.activate();
61
62 testStore = (TestDistributedMastershipStore) dms;
63 }
64
65 @After
66 public void tearDown() throws Exception {
67 dms.deactivate();
68
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070069 storeMgr.deactivate();
70 }
71
72 @Test
Ray Milkey0811bdd2015-03-11 10:21:55 -070073 @Ignore("Disabled this test due to intermittent failures seen on Jenkins runs")
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070074 public void getRole() {
75 assertEquals("wrong role:", NONE, dms.getRole(N1, DID1));
Ayaka Koshibec4047702014-10-07 14:43:52 -070076 testStore.put(DID1, N1, true, false, true);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070077 assertEquals("wrong role:", MASTER, dms.getRole(N1, DID1));
Ayaka Koshibea7384a82014-10-22 18:59:06 -070078 testStore.put(DID1, N2, false, true, false);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070079 assertEquals("wrong role:", STANDBY, dms.getRole(N2, DID1));
80 }
81
82 @Test
83 public void getMaster() {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070084 assertTrue("wrong store state:", dms.roleMap.isEmpty());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070085
86 testStore.put(DID1, N1, true, false, false);
Brian O'Connor17367492015-03-03 17:11:54 -080087 TestTools.assertAfter(100, () -> //wait for up to 100ms
88 assertEquals("wrong master:", N1, dms.getMaster(DID1)));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070089 assertNull("wrong master:", dms.getMaster(DID2));
90 }
91
92 @Test
93 public void getDevices() {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -070094 assertTrue("wrong store state:", dms.roleMap.isEmpty());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070095
96 testStore.put(DID1, N1, true, false, false);
97 testStore.put(DID2, N1, true, false, false);
98 testStore.put(DID3, N2, true, false, false);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -070099 assertEquals("wrong devices",
100 Sets.newHashSet(DID1, DID2), dms.getDevices(N1));
101 }
102
103 @Test
104 public void requestRoleAndTerm() {
105 //CN1 is "local"
106 testStore.setCurrent(CN1);
107
108 //if already MASTER, nothing should happen
Yuta HIGUCHIb5b71b32014-10-30 02:41:25 -0700109 testStore.put(DID2, N1, true, false, true);
Madan Jampanide003d92015-05-11 17:14:20 -0700110 assertEquals("wrong role for MASTER:", MASTER, Futures.getUnchecked(dms.requestRole(DID2)));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700111
112 //populate maps with DID1, N1 thru NONE case
Madan Jampanide003d92015-05-11 17:14:20 -0700113 assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1)));
Ayaka Koshibec4047702014-10-07 14:43:52 -0700114 assertTrue("wrong state for store:", !dms.terms.isEmpty());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700115 assertEquals("wrong term",
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700116 MastershipTerm.of(N1, 1), dms.getTermFor(DID1));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700117
118 //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY
119 testStore.setCurrent(CN2);
Madan Jampanide003d92015-05-11 17:14:20 -0700120 assertEquals("wrong role for STANDBY:", STANDBY, Futures.getUnchecked(dms.requestRole(DID2)));
Ayaka Koshibec4047702014-10-07 14:43:52 -0700121 assertEquals("wrong number of entries:", 2, dms.terms.size());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700122
123 //change term and requestRole() again; should persist
124 testStore.increment(DID2);
Madan Jampanide003d92015-05-11 17:14:20 -0700125 assertEquals("wrong role for STANDBY:", STANDBY, Futures.getUnchecked(dms.requestRole(DID2)));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700126 assertEquals("wrong term", MastershipTerm.of(N1, 1), dms.getTermFor(DID2));
127 }
128
129 @Test
130 public void setMaster() {
131 //populate maps with DID1, N1 as MASTER thru NONE case
132 testStore.setCurrent(CN1);
Madan Jampanide003d92015-05-11 17:14:20 -0700133 assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1)));
Madan Jampanif7536ab2015-05-07 23:23:23 -0700134 assertNull("wrong event:", Futures.getUnchecked(dms.setMaster(N1, DID1)));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700135
136 //switch over to N2
Madan Jampanif7536ab2015-05-07 23:23:23 -0700137 assertEquals("wrong event:", Type.MASTER_CHANGED, Futures.getUnchecked(dms.setMaster(N2, DID1)).type());
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700138 System.out.println(dms.getTermFor(DID1).master() + ":" + dms.getTermFor(DID1).termNumber());
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700139 assertEquals("wrong term", MastershipTerm.of(N2, 2), dms.getTermFor(DID1));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700140
141 //orphan switch - should be rare case
Madan Jampanif7536ab2015-05-07 23:23:23 -0700142 assertEquals("wrong event:", Type.MASTER_CHANGED, Futures.getUnchecked(dms.setMaster(N2, DID2)).type());
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700143 assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700144 //disconnect and reconnect - sign of failing re-election or single-instance channel
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700145 dms.roleMap.clear();
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700146 dms.setMaster(N2, DID2);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700147 assertEquals("wrong term", MastershipTerm.of(N2, 2), dms.getTermFor(DID2));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700148 }
149
150 @Test
Ayaka Koshibec4047702014-10-07 14:43:52 -0700151 public void relinquishRole() {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700152 //populate maps with DID1, N1 as MASTER thru NONE case
153 testStore.setCurrent(CN1);
Madan Jampanide003d92015-05-11 17:14:20 -0700154 assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1)));
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700155 //no backup, no new MASTER/event
Madan Jampanif7536ab2015-05-07 23:23:23 -0700156 assertNull("wrong event:", Futures.getUnchecked(dms.relinquishRole(N1, DID1)));
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700157
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700158 dms.requestRole(DID1);
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700159
160 //add backup CN2, get it elected MASTER by relinquishing
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700161 testStore.setCurrent(CN2);
Madan Jampanide003d92015-05-11 17:14:20 -0700162 assertEquals("wrong role for NONE:", STANDBY, Futures.getUnchecked(dms.requestRole(DID1)));
Madan Jampanif7536ab2015-05-07 23:23:23 -0700163 assertEquals("wrong event:", Type.MASTER_CHANGED, Futures.getUnchecked(dms.relinquishRole(N1, DID1)).type());
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700164 assertEquals("wrong master", N2, dms.getMaster(DID1));
165
Ayaka Koshibec4047702014-10-07 14:43:52 -0700166 //all nodes "give up" on device, which goes back to NONE.
Madan Jampanif7536ab2015-05-07 23:23:23 -0700167 assertNull("wrong event:", Futures.getUnchecked(dms.relinquishRole(N2, DID1)));
Ayaka Koshibec4047702014-10-07 14:43:52 -0700168 assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1));
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700169
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700170 assertEquals("wrong number of retired nodes", 2,
171 dms.roleMap.get(DID1).nodesOfRole(NONE).size());
Ayaka Koshibec4047702014-10-07 14:43:52 -0700172
173 //bring nodes back
Madan Jampanide003d92015-05-11 17:14:20 -0700174 assertEquals("wrong role for NONE:", MASTER, Futures.getUnchecked(dms.requestRole(DID1)));
Ayaka Koshibec4047702014-10-07 14:43:52 -0700175 testStore.setCurrent(CN1);
Madan Jampanide003d92015-05-11 17:14:20 -0700176 assertEquals("wrong role for NONE:", STANDBY, Futures.getUnchecked(dms.requestRole(DID1)));
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700177 assertEquals("wrong number of backup nodes", 1,
178 dms.roleMap.get(DID1).nodesOfRole(STANDBY).size());
Ayaka Koshibec4047702014-10-07 14:43:52 -0700179
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700180 //If STANDBY, should drop to NONE
Madan Jampanif7536ab2015-05-07 23:23:23 -0700181 assertEquals("wrong event:", Type.BACKUPS_CHANGED, Futures.getUnchecked(dms.relinquishRole(N1, DID1)).type());
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700182 assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1));
183
Ayaka Koshibec4047702014-10-07 14:43:52 -0700184 //NONE - nothing happens
Madan Jampanif7536ab2015-05-07 23:23:23 -0700185 assertEquals("wrong event:", Type.BACKUPS_CHANGED, Futures.getUnchecked(dms.relinquishRole(N1, DID2)).type());
Ayaka Koshibec4047702014-10-07 14:43:52 -0700186 assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID2));
Ayaka Koshibe25fd23a2014-10-03 15:50:43 -0700187
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700188 }
189
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700190 @Ignore("Ignore until Delegate spec. is clear.")
191 @Test
192 public void testEvents() throws InterruptedException {
193 //shamelessly copy other distributed store tests
194 final CountDownLatch addLatch = new CountDownLatch(1);
195
196 MastershipStoreDelegate checkAdd = new MastershipStoreDelegate() {
197 @Override
198 public void notify(MastershipEvent event) {
199 assertEquals("wrong event:", Type.MASTER_CHANGED, event.type());
200 assertEquals("wrong subject", DID1, event.subject());
Ayaka Koshibea7384a82014-10-22 18:59:06 -0700201 assertEquals("wrong subject", N1, event.roleInfo().master());
Ayaka Koshibe5c0f2372014-10-02 17:59:04 -0700202 addLatch.countDown();
203 }
204 };
205
206 dms.setDelegate(checkAdd);
207 dms.setMaster(N1, DID1);
208 //this will fail until we do something about single-instance-ness
209 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
210 }
211
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700212 private class TestDistributedMastershipStore extends
213 DistributedMastershipStore {
214 public TestDistributedMastershipStore(StoreService storeService,
Ayaka Koshibe4c891272014-10-08 17:14:16 -0700215 KryoSerializer kryoSerialization) {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700216 this.storeService = storeService;
Ayaka Koshibe4c891272014-10-08 17:14:16 -0700217 this.serializer = kryoSerialization;
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700218 }
219
220 //helper to populate master/backup structures
221 public void put(DeviceId dev, NodeId node,
Ayaka Koshibec4047702014-10-07 14:43:52 -0700222 boolean master, boolean backup, boolean term) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700223 RoleValue rv = dms.roleMap.get(dev);
224 if (rv == null) {
225 rv = new RoleValue();
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700226 }
Ayaka Koshibec4047702014-10-07 14:43:52 -0700227
228 if (master) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700229 rv.add(MASTER, node);
230 rv.reassign(node, STANDBY, NONE);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700231 }
232 if (backup) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700233 rv.add(STANDBY, node);
234 rv.remove(MASTER, node);
235 rv.remove(NONE, node);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700236 }
237 if (term) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700238 dms.terms.put(dev, 0);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700239 }
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700240 dms.roleMap.put(dev, rv);
Ayaka Koshibec4047702014-10-07 14:43:52 -0700241 }
242
Ayaka Koshibe4c891272014-10-08 17:14:16 -0700243 //a dumb utility function.
Ayaka Koshibec4047702014-10-07 14:43:52 -0700244 public void dump() {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700245 for (Map.Entry<DeviceId, RoleValue> el : dms.roleMap.entrySet()) {
246 System.out.println("DID: " + el.getKey());
247 for (MastershipRole role : MastershipRole.values()) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700248 System.out.println("\t" + role.toString() + ":");
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700249 for (NodeId n : el.getValue().nodesOfRole(role)) {
Ayaka Koshibee8e45352014-10-16 00:37:19 -0700250 System.out.println("\t\t" + n);
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700251 }
252 }
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700253 }
254 }
255
256 //increment term for a device
257 public void increment(DeviceId dev) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700258 Integer t = dms.terms.get(dev);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700259 if (t != null) {
Ayaka Koshibef9b02fc2014-10-15 17:07:05 -0700260 dms.terms.put(dev, ++t);
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700261 }
262 }
263
264 //sets the "local" node
265 public void setCurrent(ControllerNode node) {
266 ((TestClusterService) clusterService).current = node;
267 }
268 }
269
Ray Milkeycc53abd2015-02-19 12:31:33 -0800270 private class TestClusterService extends ClusterServiceAdapter {
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700271
272 protected ControllerNode current;
273
274 @Override
275 public ControllerNode getLocalNode() {
276 return current;
277 }
278
279 @Override
280 public Set<ControllerNode> getNodes() {
281 return Sets.newHashSet(CN1, CN2);
282 }
283
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700284 }
Thomas Vachuskaba082b82015-05-20 13:47:38 -0700285*/
Ayaka Koshibe8583ff32014-10-02 16:25:30 -0700286}