blob: 10e9b390382043cebf464e0bcb90dbbfe1ef1d7b [file] [log] [blame]
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -07001package org.onlab.onos.net.device.impl;
2
tom0872a172014-09-23 11:24:26 -07003import com.google.common.collect.Iterables;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07004import com.google.common.collect.Sets;
tom0872a172014-09-23 11:24:26 -07005import com.hazelcast.config.Config;
6import com.hazelcast.core.Hazelcast;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -07007
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -07008import org.junit.After;
9import org.junit.Before;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070010import org.junit.Test;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070011import org.onlab.onos.cluster.DefaultControllerNode;
tomb41d1ac2014-09-24 01:51:24 -070012import org.onlab.onos.cluster.MastershipServiceAdapter;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070013import org.onlab.onos.cluster.NodeId;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070014import org.onlab.onos.event.Event;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070015import org.onlab.onos.event.EventDeliveryService;
tom0872a172014-09-23 11:24:26 -070016import org.onlab.onos.event.impl.TestEventDispatcher;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070017import org.onlab.onos.net.Device;
18import org.onlab.onos.net.DeviceId;
19import org.onlab.onos.net.MastershipRole;
20import org.onlab.onos.net.Port;
21import org.onlab.onos.net.PortNumber;
22import org.onlab.onos.net.device.DefaultDeviceDescription;
23import org.onlab.onos.net.device.DefaultPortDescription;
24import org.onlab.onos.net.device.DeviceAdminService;
25import org.onlab.onos.net.device.DeviceDescription;
26import org.onlab.onos.net.device.DeviceEvent;
27import org.onlab.onos.net.device.DeviceListener;
28import org.onlab.onos.net.device.DeviceProvider;
29import org.onlab.onos.net.device.DeviceProviderRegistry;
30import org.onlab.onos.net.device.DeviceProviderService;
31import org.onlab.onos.net.device.DeviceService;
32import org.onlab.onos.net.device.PortDescription;
33import org.onlab.onos.net.provider.AbstractProvider;
34import org.onlab.onos.net.provider.ProviderId;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070035import org.onlab.onos.store.common.StoreManager;
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -070036import org.onlab.onos.store.common.StoreService;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070037import org.onlab.onos.store.common.TestStoreManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070038import org.onlab.onos.store.device.impl.DistributedDeviceStore;
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -070039import org.onlab.onos.store.serializers.KryoSerializationManager;
40import org.onlab.onos.store.serializers.KryoSerializationService;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070041import org.onlab.packet.IpPrefix;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070042
43import java.util.ArrayList;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070044import java.util.HashSet;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070045import java.util.Iterator;
46import java.util.List;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070047import java.util.Map.Entry;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070048import java.util.Set;
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -070049import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070050import java.util.concurrent.ConcurrentHashMap;
51import java.util.concurrent.ConcurrentMap;
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -070052import java.util.concurrent.LinkedBlockingQueue;
53import java.util.concurrent.TimeUnit;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070054
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070055import static org.junit.Assert.*;
56import static org.onlab.onos.net.Device.Type.SWITCH;
57import static org.onlab.onos.net.DeviceId.deviceId;
58import static org.onlab.onos.net.device.DeviceEvent.Type.*;
59
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -070060// FIXME This test is slow starting up Hazelcast on each test cases.
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070061// FIXME DistributedDeviceStore should have it's own test cases.
tomb41d1ac2014-09-24 01:51:24 -070062
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070063/**
64 * Test codifying the device service & device provider service contracts.
65 */
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070066public class DistributedDeviceManagerTest {
67
68 private static final ProviderId PID = new ProviderId("of", "foo");
69 private static final DeviceId DID1 = deviceId("of:foo");
70 private static final DeviceId DID2 = deviceId("of:bar");
71 private static final String MFR = "whitebox";
72 private static final String HW = "1.1.x";
73 private static final String SW1 = "3.8.1";
74 private static final String SW2 = "3.9.5";
75 private static final String SN = "43311-12345";
76
77 private static final PortNumber P1 = PortNumber.portNumber(1);
78 private static final PortNumber P2 = PortNumber.portNumber(2);
79 private static final PortNumber P3 = PortNumber.portNumber(3);
80
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070081 private static final DefaultControllerNode SELF
82 = new DefaultControllerNode(new NodeId("foobar"),
83 IpPrefix.valueOf("127.0.0.1"));
84
85
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070086 private DeviceManager mgr;
87
tom0872a172014-09-23 11:24:26 -070088 protected StoreManager storeManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070089 protected DeviceService service;
90 protected DeviceAdminService admin;
91 protected DeviceProviderRegistry registry;
92 protected DeviceProviderService providerService;
93 protected TestProvider provider;
94 protected TestListener listener = new TestListener();
95 private DistributedDeviceStore dstore;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070096 private TestMastershipManager masterManager;
97 private EventDeliveryService eventService;
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -070098 private KryoSerializationManager serializationMgr;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070099
100 @Before
101 public void setUp() {
102 mgr = new DeviceManager();
103 service = mgr;
104 admin = mgr;
105 registry = mgr;
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -0700106 // TODO should find a way to clean Hazelcast instance without shutdown.
107 Config config = TestStoreManager.getTestConfig();
tom0872a172014-09-23 11:24:26 -0700108
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700109 masterManager = new TestMastershipManager();
110
tom0872a172014-09-23 11:24:26 -0700111 storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
112 storeManager.activate();
113
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -0700114 serializationMgr = new KryoSerializationManager();
115 serializationMgr.activate();
116
117 dstore = new TestDistributedDeviceStore(storeManager, serializationMgr);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700118 dstore.activate();
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700119
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700120 mgr.store = dstore;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700121 eventService = new TestEventDispatcher();
122 mgr.eventDispatcher = eventService;
123 mgr.mastershipService = masterManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700124 mgr.activate();
125
126 service.addListener(listener);
127
128 provider = new TestProvider();
129 providerService = registry.register(provider);
130 assertTrue("provider should be registered",
131 registry.getProviders().contains(provider.id()));
132 }
133
134 @After
135 public void tearDown() {
136 registry.unregister(provider);
137 assertFalse("provider should not be registered",
138 registry.getProviders().contains(provider.id()));
139 service.removeListener(listener);
140 mgr.deactivate();
141
142 dstore.deactivate();
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -0700143 serializationMgr.deactivate();
tom0872a172014-09-23 11:24:26 -0700144 storeManager.deactivate();
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700145 }
146
147 private void connectDevice(DeviceId deviceId, String swVersion) {
148 DeviceDescription description =
149 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
150 HW, swVersion, SN);
151 providerService.deviceConnected(deviceId, description);
152 assertNotNull("device should be found", service.getDevice(DID1));
153 }
154
155 @Test
156 public void deviceConnected() {
157 assertNull("device should not be found", service.getDevice(DID1));
158 connectDevice(DID1, SW1);
159 validateEvents(DEVICE_ADDED);
160
161 assertEquals("only one device expected", 1, Iterables.size(service.getDevices()));
162 Iterator<Device> it = service.getDevices().iterator();
163 assertNotNull("one device expected", it.next());
164 assertFalse("only one device expected", it.hasNext());
165
166 assertEquals("incorrect device count", 1, service.getDeviceCount());
167 assertTrue("device should be available", service.isAvailable(DID1));
168 }
169
170 @Test
171 public void deviceDisconnected() {
172 connectDevice(DID1, SW1);
173 connectDevice(DID2, SW1);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700174 validateEvents(DEVICE_ADDED, DEVICE_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700175 assertTrue("device should be available", service.isAvailable(DID1));
176
177 // Disconnect
178 providerService.deviceDisconnected(DID1);
179 assertNotNull("device should not be found", service.getDevice(DID1));
180 assertFalse("device should not be available", service.isAvailable(DID1));
181 validateEvents(DEVICE_AVAILABILITY_CHANGED);
182
183 // Reconnect
184 connectDevice(DID1, SW1);
185 validateEvents(DEVICE_AVAILABILITY_CHANGED);
186
187 assertEquals("incorrect device count", 2, service.getDeviceCount());
188 }
189
190 @Test
191 public void deviceUpdated() {
192 connectDevice(DID1, SW1);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700193 validateEvents(DEVICE_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700194
195 connectDevice(DID1, SW2);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700196 validateEvents(DEVICE_UPDATED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700197 }
198
199 @Test
200 public void getRole() {
201 connectDevice(DID1, SW1);
202 assertEquals("incorrect role", MastershipRole.MASTER, service.getRole(DID1));
203 }
204
205 @Test
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700206 public void updatePorts() {
207 connectDevice(DID1, SW1);
208 List<PortDescription> pds = new ArrayList<>();
209 pds.add(new DefaultPortDescription(P1, true));
210 pds.add(new DefaultPortDescription(P2, true));
211 pds.add(new DefaultPortDescription(P3, true));
212 providerService.updatePorts(DID1, pds);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700213 validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700214 pds.clear();
215
216 pds.add(new DefaultPortDescription(P1, false));
217 pds.add(new DefaultPortDescription(P3, true));
218 providerService.updatePorts(DID1, pds);
219 validateEvents(PORT_UPDATED, PORT_REMOVED);
220 }
221
222 @Test
223 public void updatePortStatus() {
224 connectDevice(DID1, SW1);
225 List<PortDescription> pds = new ArrayList<>();
226 pds.add(new DefaultPortDescription(P1, true));
227 pds.add(new DefaultPortDescription(P2, true));
228 providerService.updatePorts(DID1, pds);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700229 validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700230
231 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
232 validateEvents(PORT_UPDATED);
233 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
234 assertTrue("no events expected", listener.events.isEmpty());
235 }
236
237 @Test
238 public void getPorts() {
239 connectDevice(DID1, SW1);
240 List<PortDescription> pds = new ArrayList<>();
241 pds.add(new DefaultPortDescription(P1, true));
242 pds.add(new DefaultPortDescription(P2, true));
243 providerService.updatePorts(DID1, pds);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700244 validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700245 assertEquals("wrong port count", 2, service.getPorts(DID1).size());
246
247 Port port = service.getPort(DID1, P1);
248 assertEquals("incorrect port", P1, service.getPort(DID1, P1).number());
249 assertEquals("incorrect state", true, service.getPort(DID1, P1).isEnabled());
250 }
251
252 @Test
253 public void removeDevice() {
254 connectDevice(DID1, SW1);
255 connectDevice(DID2, SW2);
256 assertEquals("incorrect device count", 2, service.getDeviceCount());
257 admin.removeDevice(DID1);
Yuta HIGUCHIfec9e192014-09-28 14:58:02 -0700258 validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_REMOVED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700259 assertNull("device should not be found", service.getDevice(DID1));
260 assertNotNull("device should be found", service.getDevice(DID2));
261 assertEquals("incorrect device count", 1, service.getDeviceCount());
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700262 }
263
264 protected void validateEvents(Enum... types) {
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700265 for (Enum type : types) {
266 try {
267 Event event = listener.events.poll(1, TimeUnit.SECONDS);
268 assertNotNull("Timed out waiting for " + event, event);
269 assertEquals("incorrect event type", type, event.type());
270 } catch (InterruptedException e) {
271 fail("Unexpected interrupt");
272 }
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700273 }
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700274 assertTrue("Unexpected events left", listener.events.isEmpty());
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700275 listener.events.clear();
276 }
277
278
279 private class TestProvider extends AbstractProvider implements DeviceProvider {
280 private Device deviceReceived;
281 private MastershipRole roleReceived;
282
283 public TestProvider() {
284 super(PID);
285 }
286
287 @Override
288 public void triggerProbe(Device device) {
289 }
290
291 @Override
292 public void roleChanged(Device device, MastershipRole newRole) {
293 deviceReceived = device;
294 roleReceived = newRole;
295 }
296 }
297
298 private static class TestListener implements DeviceListener {
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700299 final BlockingQueue<DeviceEvent> events = new LinkedBlockingQueue<>();
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700300
301 @Override
302 public void event(DeviceEvent event) {
303 events.add(event);
304 }
305 }
306
tom85ff08b2014-09-22 17:14:18 -0700307 private class TestDistributedDeviceStore extends DistributedDeviceStore {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700308
Yuta HIGUCHIad4c2182014-09-29 11:16:23 -0700309 public TestDistributedDeviceStore(StoreService storeService,
310 KryoSerializationService kryoSerializationService) {
311 this.storeService = storeService;
312 this.kryoSerializationService = kryoSerializationService;
tom0872a172014-09-23 11:24:26 -0700313 }
314 }
315
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700316 private static class TestMastershipManager extends MastershipServiceAdapter {
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -0700317
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700318 private ConcurrentMap<DeviceId, NodeId> masters = new ConcurrentHashMap<>();
319
320 public TestMastershipManager() {
321 // SELF master of all initially
322 masters.put(DID1, SELF.id());
323 masters.put(DID1, SELF.id());
324 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700325 @Override
tomb41d1ac2014-09-24 01:51:24 -0700326 public MastershipRole getLocalRole(DeviceId deviceId) {
327 return MastershipRole.MASTER;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700328 }
329
330 @Override
331 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700332 HashSet<DeviceId> set = Sets.newHashSet();
333 for (Entry<DeviceId, NodeId> e : masters.entrySet()) {
334 if (e.getValue().equals(nodeId)) {
335 set.add(e.getKey());
336 }
337 }
338 return set;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700339 }
340
341 @Override
342 public MastershipRole requestRoleFor(DeviceId deviceId) {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700343 if (SELF.id().equals(masters.get(deviceId))) {
344 return MastershipRole.MASTER;
345 } else {
346 return MastershipRole.STANDBY;
347 }
348 }
349
350 @Override
351 public void relinquishMastership(DeviceId deviceId) {
352 masters.remove(deviceId, SELF.id());
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700353 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700354 }
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700355}