blob: 90cb49c00a14b81b639b6f01df5c96517566848d [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;
36import org.onlab.onos.store.common.TestStoreManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070037import org.onlab.onos.store.device.impl.DistributedDeviceStore;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070038import org.onlab.packet.IpPrefix;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070039
40import java.util.ArrayList;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070041import java.util.HashSet;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070042import java.util.Iterator;
43import java.util.List;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070044import java.util.Map.Entry;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070045import java.util.Set;
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -070046import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070047import java.util.concurrent.ConcurrentHashMap;
48import java.util.concurrent.ConcurrentMap;
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -070049import java.util.concurrent.LinkedBlockingQueue;
50import java.util.concurrent.TimeUnit;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070051
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070052import static org.junit.Assert.*;
53import static org.onlab.onos.net.Device.Type.SWITCH;
54import static org.onlab.onos.net.DeviceId.deviceId;
55import static org.onlab.onos.net.device.DeviceEvent.Type.*;
56
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -070057// FIXME This test is slow starting up Hazelcast on each test cases.
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070058// FIXME DistributedDeviceStore should have it's own test cases.
tomb41d1ac2014-09-24 01:51:24 -070059
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070060/**
61 * Test codifying the device service & device provider service contracts.
62 */
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070063public class DistributedDeviceManagerTest {
64
65 private static final ProviderId PID = new ProviderId("of", "foo");
66 private static final DeviceId DID1 = deviceId("of:foo");
67 private static final DeviceId DID2 = deviceId("of:bar");
68 private static final String MFR = "whitebox";
69 private static final String HW = "1.1.x";
70 private static final String SW1 = "3.8.1";
71 private static final String SW2 = "3.9.5";
72 private static final String SN = "43311-12345";
73
74 private static final PortNumber P1 = PortNumber.portNumber(1);
75 private static final PortNumber P2 = PortNumber.portNumber(2);
76 private static final PortNumber P3 = PortNumber.portNumber(3);
77
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070078 private static final DefaultControllerNode SELF
79 = new DefaultControllerNode(new NodeId("foobar"),
80 IpPrefix.valueOf("127.0.0.1"));
81
82
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070083 private DeviceManager mgr;
84
tom0872a172014-09-23 11:24:26 -070085 protected StoreManager storeManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070086 protected DeviceService service;
87 protected DeviceAdminService admin;
88 protected DeviceProviderRegistry registry;
89 protected DeviceProviderService providerService;
90 protected TestProvider provider;
91 protected TestListener listener = new TestListener();
92 private DistributedDeviceStore dstore;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -070093 private TestMastershipManager masterManager;
94 private EventDeliveryService eventService;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -070095
96 @Before
97 public void setUp() {
98 mgr = new DeviceManager();
99 service = mgr;
100 admin = mgr;
101 registry = mgr;
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -0700102 // TODO should find a way to clean Hazelcast instance without shutdown.
103 Config config = TestStoreManager.getTestConfig();
tom0872a172014-09-23 11:24:26 -0700104
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700105 masterManager = new TestMastershipManager();
106
tom0872a172014-09-23 11:24:26 -0700107 storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
108 storeManager.activate();
109
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700110 dstore = new TestDistributedDeviceStore();
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700111 dstore.activate();
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700112
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700113 mgr.store = dstore;
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700114 eventService = new TestEventDispatcher();
115 mgr.eventDispatcher = eventService;
116 mgr.mastershipService = masterManager;
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700117 mgr.activate();
118
119 service.addListener(listener);
120
121 provider = new TestProvider();
122 providerService = registry.register(provider);
123 assertTrue("provider should be registered",
124 registry.getProviders().contains(provider.id()));
125 }
126
127 @After
128 public void tearDown() {
129 registry.unregister(provider);
130 assertFalse("provider should not be registered",
131 registry.getProviders().contains(provider.id()));
132 service.removeListener(listener);
133 mgr.deactivate();
134
135 dstore.deactivate();
tom0872a172014-09-23 11:24:26 -0700136 storeManager.deactivate();
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700137 }
138
139 private void connectDevice(DeviceId deviceId, String swVersion) {
140 DeviceDescription description =
141 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
142 HW, swVersion, SN);
143 providerService.deviceConnected(deviceId, description);
144 assertNotNull("device should be found", service.getDevice(DID1));
145 }
146
147 @Test
148 public void deviceConnected() {
149 assertNull("device should not be found", service.getDevice(DID1));
150 connectDevice(DID1, SW1);
151 validateEvents(DEVICE_ADDED);
152
153 assertEquals("only one device expected", 1, Iterables.size(service.getDevices()));
154 Iterator<Device> it = service.getDevices().iterator();
155 assertNotNull("one device expected", it.next());
156 assertFalse("only one device expected", it.hasNext());
157
158 assertEquals("incorrect device count", 1, service.getDeviceCount());
159 assertTrue("device should be available", service.isAvailable(DID1));
160 }
161
162 @Test
163 public void deviceDisconnected() {
164 connectDevice(DID1, SW1);
165 connectDevice(DID2, SW1);
tomca55e642014-09-24 18:28:38 -0700166 validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700167 assertTrue("device should be available", service.isAvailable(DID1));
168
169 // Disconnect
170 providerService.deviceDisconnected(DID1);
171 assertNotNull("device should not be found", service.getDevice(DID1));
172 assertFalse("device should not be available", service.isAvailable(DID1));
173 validateEvents(DEVICE_AVAILABILITY_CHANGED);
174
175 // Reconnect
176 connectDevice(DID1, SW1);
177 validateEvents(DEVICE_AVAILABILITY_CHANGED);
178
179 assertEquals("incorrect device count", 2, service.getDeviceCount());
180 }
181
182 @Test
183 public void deviceUpdated() {
184 connectDevice(DID1, SW1);
tomca55e642014-09-24 18:28:38 -0700185 validateEvents(DEVICE_ADDED, DEVICE_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700186
187 connectDevice(DID1, SW2);
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700188 validateEvents(DEVICE_UPDATED, DEVICE_UPDATED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700189 }
190
191 @Test
192 public void getRole() {
193 connectDevice(DID1, SW1);
194 assertEquals("incorrect role", MastershipRole.MASTER, service.getRole(DID1));
195 }
196
197 @Test
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700198 public void updatePorts() {
199 connectDevice(DID1, SW1);
200 List<PortDescription> pds = new ArrayList<>();
201 pds.add(new DefaultPortDescription(P1, true));
202 pds.add(new DefaultPortDescription(P2, true));
203 pds.add(new DefaultPortDescription(P3, true));
204 providerService.updatePorts(DID1, pds);
tomca55e642014-09-24 18:28:38 -0700205 validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700206 pds.clear();
207
208 pds.add(new DefaultPortDescription(P1, false));
209 pds.add(new DefaultPortDescription(P3, true));
210 providerService.updatePorts(DID1, pds);
211 validateEvents(PORT_UPDATED, PORT_REMOVED);
212 }
213
214 @Test
215 public void updatePortStatus() {
216 connectDevice(DID1, SW1);
217 List<PortDescription> pds = new ArrayList<>();
218 pds.add(new DefaultPortDescription(P1, true));
219 pds.add(new DefaultPortDescription(P2, true));
220 providerService.updatePorts(DID1, pds);
tomca55e642014-09-24 18:28:38 -0700221 validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700222
223 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
224 validateEvents(PORT_UPDATED);
225 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
226 assertTrue("no events expected", listener.events.isEmpty());
227 }
228
229 @Test
230 public void getPorts() {
231 connectDevice(DID1, SW1);
232 List<PortDescription> pds = new ArrayList<>();
233 pds.add(new DefaultPortDescription(P1, true));
234 pds.add(new DefaultPortDescription(P2, true));
235 providerService.updatePorts(DID1, pds);
tomca55e642014-09-24 18:28:38 -0700236 validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700237 assertEquals("wrong port count", 2, service.getPorts(DID1).size());
238
239 Port port = service.getPort(DID1, P1);
240 assertEquals("incorrect port", P1, service.getPort(DID1, P1).number());
241 assertEquals("incorrect state", true, service.getPort(DID1, P1).isEnabled());
242 }
243
244 @Test
245 public void removeDevice() {
246 connectDevice(DID1, SW1);
247 connectDevice(DID2, SW2);
248 assertEquals("incorrect device count", 2, service.getDeviceCount());
249 admin.removeDevice(DID1);
tomca55e642014-09-24 18:28:38 -0700250 validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REMOVED);
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700251 assertNull("device should not be found", service.getDevice(DID1));
252 assertNotNull("device should be found", service.getDevice(DID2));
253 assertEquals("incorrect device count", 1, service.getDeviceCount());
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700254 }
255
256 protected void validateEvents(Enum... types) {
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700257 for (Enum type : types) {
258 try {
259 Event event = listener.events.poll(1, TimeUnit.SECONDS);
260 assertNotNull("Timed out waiting for " + event, event);
261 assertEquals("incorrect event type", type, event.type());
262 } catch (InterruptedException e) {
263 fail("Unexpected interrupt");
264 }
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700265 }
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700266 assertTrue("Unexpected events left", listener.events.isEmpty());
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700267 listener.events.clear();
268 }
269
270
271 private class TestProvider extends AbstractProvider implements DeviceProvider {
272 private Device deviceReceived;
273 private MastershipRole roleReceived;
274
275 public TestProvider() {
276 super(PID);
277 }
278
279 @Override
280 public void triggerProbe(Device device) {
281 }
282
283 @Override
284 public void roleChanged(Device device, MastershipRole newRole) {
285 deviceReceived = device;
286 roleReceived = newRole;
287 }
288 }
289
290 private static class TestListener implements DeviceListener {
Yuta HIGUCHI3f6d29b2014-09-25 01:41:15 -0700291 final BlockingQueue<DeviceEvent> events = new LinkedBlockingQueue<>();
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700292
293 @Override
294 public void event(DeviceEvent event) {
295 events.add(event);
296 }
297 }
298
tom85ff08b2014-09-22 17:14:18 -0700299 private class TestDistributedDeviceStore extends DistributedDeviceStore {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700300
301 public TestDistributedDeviceStore() {
302 this.storeService = storeManager;
tom0872a172014-09-23 11:24:26 -0700303 }
304 }
305
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700306 private static class TestMastershipManager extends MastershipServiceAdapter {
Yuta HIGUCHIb4139d82014-09-23 18:41:33 -0700307
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700308 private ConcurrentMap<DeviceId, NodeId> masters = new ConcurrentHashMap<>();
309
310 public TestMastershipManager() {
311 // SELF master of all initially
312 masters.put(DID1, SELF.id());
313 masters.put(DID1, SELF.id());
314 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700315 @Override
tomb41d1ac2014-09-24 01:51:24 -0700316 public MastershipRole getLocalRole(DeviceId deviceId) {
317 return MastershipRole.MASTER;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700318 }
319
320 @Override
321 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700322 HashSet<DeviceId> set = Sets.newHashSet();
323 for (Entry<DeviceId, NodeId> e : masters.entrySet()) {
324 if (e.getValue().equals(nodeId)) {
325 set.add(e.getKey());
326 }
327 }
328 return set;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700329 }
330
331 @Override
332 public MastershipRole requestRoleFor(DeviceId deviceId) {
Yuta HIGUCHIb113c452014-09-24 00:12:03 -0700333 if (SELF.id().equals(masters.get(deviceId))) {
334 return MastershipRole.MASTER;
335 } else {
336 return MastershipRole.STANDBY;
337 }
338 }
339
340 @Override
341 public void relinquishMastership(DeviceId deviceId) {
342 masters.remove(deviceId, SELF.id());
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700343 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700344 }
Yuta HIGUCHIb3b2ac42014-09-21 23:37:11 -0700345}