blob: a0d6e1c05ba0bda16159712501b230f43dc3bbf3 [file] [log] [blame]
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -07001/**
2 *
3 */
tomea961ff2014-10-01 12:45:15 -07004package org.onlab.onos.store.trivial.impl;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -07005
6import static org.junit.Assert.*;
7import static org.onlab.onos.net.Device.Type.SWITCH;
8import static org.onlab.onos.net.DeviceId.deviceId;
9import static org.onlab.onos.net.device.DeviceEvent.Type.*;
10
11import java.util.Arrays;
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.concurrent.CountDownLatch;
17import java.util.concurrent.TimeUnit;
18
19import org.junit.After;
20import org.junit.AfterClass;
21import org.junit.Before;
22import org.junit.BeforeClass;
23import org.junit.Ignore;
24import org.junit.Test;
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070025import org.onlab.onos.net.Annotations;
26import org.onlab.onos.net.DefaultAnnotations;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070027import org.onlab.onos.net.Device;
28import org.onlab.onos.net.DeviceId;
29import org.onlab.onos.net.Port;
30import org.onlab.onos.net.PortNumber;
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070031import org.onlab.onos.net.SparseAnnotations;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070032import org.onlab.onos.net.device.DefaultDeviceDescription;
33import org.onlab.onos.net.device.DefaultPortDescription;
34import org.onlab.onos.net.device.DeviceDescription;
35import org.onlab.onos.net.device.DeviceEvent;
36import org.onlab.onos.net.device.DeviceStore;
37import org.onlab.onos.net.device.DeviceStoreDelegate;
38import org.onlab.onos.net.device.PortDescription;
39import org.onlab.onos.net.provider.ProviderId;
40
41import com.google.common.collect.Iterables;
42import com.google.common.collect.Sets;
43
44/**
45 * Test of the simple DeviceStore implementation.
46 */
47public class SimpleDeviceStoreTest {
48
49 private static final ProviderId PID = new ProviderId("of", "foo");
Yuta HIGUCHI8e493792014-10-01 19:36:32 -070050 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070051 private static final DeviceId DID1 = deviceId("of:foo");
52 private static final DeviceId DID2 = deviceId("of:bar");
53 private static final String MFR = "whitebox";
54 private static final String HW = "1.1.x";
55 private static final String SW1 = "3.8.1";
56 private static final String SW2 = "3.9.5";
57 private static final String SN = "43311-12345";
58
59 private static final PortNumber P1 = PortNumber.portNumber(1);
60 private static final PortNumber P2 = PortNumber.portNumber(2);
61 private static final PortNumber P3 = PortNumber.portNumber(3);
62
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070063 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
64 .set("A1", "a1")
65 .set("B1", "b1")
66 .build();
67 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
68 .remove("A1")
69 .set("B3", "b3")
70 .build();
71 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
72 .set("A2", "a2")
73 .set("B2", "b2")
74 .build();
75 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
76 .remove("A2")
77 .set("B4", "b4")
78 .build();
79
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070080 private SimpleDeviceStore simpleDeviceStore;
81 private DeviceStore deviceStore;
82
83
84
85 @BeforeClass
86 public static void setUpBeforeClass() throws Exception {
87 }
88
89 @AfterClass
90 public static void tearDownAfterClass() throws Exception {
91 }
92
93
94 @Before
95 public void setUp() throws Exception {
96 simpleDeviceStore = new SimpleDeviceStore();
97 simpleDeviceStore.activate();
98 deviceStore = simpleDeviceStore;
99 }
100
101 @After
102 public void tearDown() throws Exception {
103 simpleDeviceStore.deactivate();
104 }
105
106 private void putDevice(DeviceId deviceId, String swVersion) {
107 DeviceDescription description =
108 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
109 HW, swVersion, SN);
110 deviceStore.createOrUpdateDevice(PID, deviceId, description);
111 }
112
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700113 private void putDeviceAncillary(DeviceId deviceId, String swVersion) {
114 DeviceDescription description =
115 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
116 HW, swVersion, SN);
117 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
118 }
119
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700120 private static void assertDevice(DeviceId id, String swVersion, Device device) {
121 assertNotNull(device);
122 assertEquals(id, device.id());
123 assertEquals(MFR, device.manufacturer());
124 assertEquals(HW, device.hwVersion());
125 assertEquals(swVersion, device.swVersion());
126 assertEquals(SN, device.serialNumber());
127 }
128
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700129 /**
130 * Verifies that Annotations created by merging {@code annotations} is
131 * equal to actual Annotations.
132 *
133 * @param actual Annotations to check
134 * @param annotations
135 */
136 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
137 DefaultAnnotations expected = DefaultAnnotations.builder().build();
138 for (SparseAnnotations a : annotations) {
139 expected = DefaultAnnotations.merge(expected, a);
140 }
141 assertEquals(expected.keys(), actual.keys());
142 for (String key : expected.keys()) {
143 assertEquals(expected.value(key), actual.value(key));
144 }
145 }
146
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700147 @Test
148 public final void testGetDeviceCount() {
149 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
150
151 putDevice(DID1, SW1);
152 putDevice(DID2, SW2);
153 putDevice(DID1, SW1);
154
155 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
156 }
157
158 @Test
159 public final void testGetDevices() {
160 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
161
162 putDevice(DID1, SW1);
163 putDevice(DID2, SW2);
164 putDevice(DID1, SW1);
165
166 assertEquals("expect 2 uniq devices",
167 2, Iterables.size(deviceStore.getDevices()));
168
169 Map<DeviceId, Device> devices = new HashMap<>();
170 for (Device device : deviceStore.getDevices()) {
171 devices.put(device.id(), device);
172 }
173
174 assertDevice(DID1, SW1, devices.get(DID1));
175 assertDevice(DID2, SW2, devices.get(DID2));
176
177 // add case for new node?
178 }
179
180 @Test
181 public final void testGetDevice() {
182
183 putDevice(DID1, SW1);
184
185 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
186 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
187 }
188
189 @Test
190 public final void testCreateOrUpdateDevice() {
191 DeviceDescription description =
192 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
193 HW, SW1, SN);
194 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
195 assertEquals(DEVICE_ADDED, event.type());
196 assertDevice(DID1, SW1, event.subject());
197
198 DeviceDescription description2 =
199 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
200 HW, SW2, SN);
201 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
202 assertEquals(DEVICE_UPDATED, event2.type());
203 assertDevice(DID1, SW2, event2.subject());
204
205 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
206 }
207
208 @Test
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700209 public final void testCreateOrUpdateDeviceAncillary() {
210 DeviceDescription description =
211 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700212 HW, SW1, SN, A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700213 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
214 assertEquals(DEVICE_ADDED, event.type());
215 assertDevice(DID1, SW1, event.subject());
216 assertEquals(PIDA, event.subject().providerId());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700217 assertAnnotationsEquals(event.subject().annotations(), A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700218 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
219
220 DeviceDescription description2 =
221 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700222 HW, SW2, SN, A1);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700223 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
224 assertEquals(DEVICE_UPDATED, event2.type());
225 assertDevice(DID1, SW2, event2.subject());
226 assertEquals(PID, event2.subject().providerId());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700227 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700228 assertTrue(deviceStore.isAvailable(DID1));
229
230 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
231
232 // For now, Ancillary is ignored once primary appears
233 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700234
235 // But, Ancillary annotations will be in effect
236 DeviceDescription description3 =
237 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
238 HW, SW1, SN, A2_2);
239 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
240 assertEquals(DEVICE_UPDATED, event3.type());
241 // basic information will be the one from Primary
242 assertDevice(DID1, SW2, event3.subject());
243 assertEquals(PID, event3.subject().providerId());
244 // but annotation from Ancillary will be merged
245 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
246 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700247 }
248
249
250 @Test
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700251 public final void testMarkOffline() {
252
253 putDevice(DID1, SW1);
254 assertTrue(deviceStore.isAvailable(DID1));
255
256 DeviceEvent event = deviceStore.markOffline(DID1);
257 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
258 assertDevice(DID1, SW1, event.subject());
259 assertFalse(deviceStore.isAvailable(DID1));
260
261 DeviceEvent event2 = deviceStore.markOffline(DID1);
262 assertNull("No change, no event", event2);
263}
264
265 @Test
266 public final void testUpdatePorts() {
267 putDevice(DID1, SW1);
268 List<PortDescription> pds = Arrays.<PortDescription>asList(
269 new DefaultPortDescription(P1, true),
270 new DefaultPortDescription(P2, true)
271 );
272
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700273 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700274
275 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
276 for (DeviceEvent event : events) {
277 assertEquals(PORT_ADDED, event.type());
278 assertDevice(DID1, SW1, event.subject());
279 assertTrue("PortNumber is one of expected",
280 expectedPorts.remove(event.port().number()));
281 assertTrue("Port is enabled", event.port().isEnabled());
282 }
283 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
284
285
286 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
287 new DefaultPortDescription(P1, false),
288 new DefaultPortDescription(P2, true),
289 new DefaultPortDescription(P3, true)
290 );
291
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700292 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700293 assertFalse("event should be triggered", events.isEmpty());
294 for (DeviceEvent event : events) {
295 PortNumber num = event.port().number();
296 if (P1.equals(num)) {
297 assertEquals(PORT_UPDATED, event.type());
298 assertDevice(DID1, SW1, event.subject());
299 assertFalse("Port is disabled", event.port().isEnabled());
300 } else if (P2.equals(num)) {
301 fail("P2 event not expected.");
302 } else if (P3.equals(num)) {
303 assertEquals(PORT_ADDED, event.type());
304 assertDevice(DID1, SW1, event.subject());
305 assertTrue("Port is enabled", event.port().isEnabled());
306 } else {
307 fail("Unknown port number encountered: " + num);
308 }
309 }
310
311 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
312 new DefaultPortDescription(P1, false),
313 new DefaultPortDescription(P2, true)
314 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700315 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700316 assertFalse("event should be triggered", events.isEmpty());
317 for (DeviceEvent event : events) {
318 PortNumber num = event.port().number();
319 if (P1.equals(num)) {
320 fail("P1 event not expected.");
321 } else if (P2.equals(num)) {
322 fail("P2 event not expected.");
323 } else if (P3.equals(num)) {
324 assertEquals(PORT_REMOVED, event.type());
325 assertDevice(DID1, SW1, event.subject());
326 assertTrue("Port was enabled", event.port().isEnabled());
327 } else {
328 fail("Unknown port number encountered: " + num);
329 }
330 }
331
332 }
333
334 @Test
335 public final void testUpdatePortStatus() {
336 putDevice(DID1, SW1);
337 List<PortDescription> pds = Arrays.<PortDescription>asList(
338 new DefaultPortDescription(P1, true)
339 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700340 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700341
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700342 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1,
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700343 new DefaultPortDescription(P1, false));
344 assertEquals(PORT_UPDATED, event.type());
345 assertDevice(DID1, SW1, event.subject());
346 assertEquals(P1, event.port().number());
347 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700348
349 }
350 @Test
351 public final void testUpdatePortStatusAncillary() {
352 putDeviceAncillary(DID1, SW1);
353 putDevice(DID1, SW1);
354 List<PortDescription> pds = Arrays.<PortDescription>asList(
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700355 new DefaultPortDescription(P1, true, A1)
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700356 );
357 deviceStore.updatePorts(PID, DID1, pds);
358
359 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700360 new DefaultPortDescription(P1, false, A1_2));
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700361 assertEquals(PORT_UPDATED, event.type());
362 assertDevice(DID1, SW1, event.subject());
363 assertEquals(P1, event.port().number());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700364 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700365 assertFalse("Port is disabled", event.port().isEnabled());
366
367 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1,
368 new DefaultPortDescription(P1, true));
369 assertNull("Ancillary is ignored if primary exists", event2);
370
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700371 // but, Ancillary annotation update will be notified
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700372 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700373 new DefaultPortDescription(P1, true, A2));
374 assertEquals(PORT_UPDATED, event3.type());
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700375 assertDevice(DID1, SW1, event3.subject());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700376 assertEquals(P1, event3.port().number());
377 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
378 assertFalse("Port is disabled", event3.port().isEnabled());
379
380 // port only reported from Ancillary will be notified as down
381 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1,
382 new DefaultPortDescription(P2, true));
383 assertEquals(PORT_ADDED, event4.type());
384 assertDevice(DID1, SW1, event4.subject());
385 assertEquals(P2, event4.port().number());
386 assertAnnotationsEquals(event4.port().annotations());
387 assertFalse("Port is disabled if not given from primary provider",
388 event4.port().isEnabled());
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700389 }
390
391 @Test
392 public final void testGetPorts() {
393 putDevice(DID1, SW1);
394 putDevice(DID2, SW1);
395 List<PortDescription> pds = Arrays.<PortDescription>asList(
396 new DefaultPortDescription(P1, true),
397 new DefaultPortDescription(P2, true)
398 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700399 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700400
401 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
402 List<Port> ports = deviceStore.getPorts(DID1);
403 for (Port port : ports) {
404 assertTrue("Port is enabled", port.isEnabled());
405 assertTrue("PortNumber is one of expected",
406 expectedPorts.remove(port.number()));
407 }
408 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
409
410
411 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
412 }
413
414 @Test
415 public final void testGetPort() {
416 putDevice(DID1, SW1);
417 putDevice(DID2, SW1);
418 List<PortDescription> pds = Arrays.<PortDescription>asList(
419 new DefaultPortDescription(P1, true),
420 new DefaultPortDescription(P2, false)
421 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700422 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700423
424 Port port1 = deviceStore.getPort(DID1, P1);
425 assertEquals(P1, port1.number());
426 assertTrue("Port is enabled", port1.isEnabled());
427
428 Port port2 = deviceStore.getPort(DID1, P2);
429 assertEquals(P2, port2.number());
430 assertFalse("Port is disabled", port2.isEnabled());
431
432 Port port3 = deviceStore.getPort(DID1, P3);
433 assertNull("P3 not expected", port3);
434 }
435
436 @Test
437 public final void testRemoveDevice() {
438 putDevice(DID1, SW1);
439 putDevice(DID2, SW1);
440
441 assertEquals(2, deviceStore.getDeviceCount());
442
443 DeviceEvent event = deviceStore.removeDevice(DID1);
444 assertEquals(DEVICE_REMOVED, event.type());
445 assertDevice(DID1, SW1, event.subject());
446
447 assertEquals(1, deviceStore.getDeviceCount());
448 }
449
450 // If Delegates should be called only on remote events,
451 // then Simple* should never call them, thus not test required.
452 // TODO add test for Port events when we have them
453 @Ignore("Ignore until Delegate spec. is clear.")
454 @Test
455 public final void testEvents() throws InterruptedException {
456 final CountDownLatch addLatch = new CountDownLatch(1);
457 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
458 @Override
459 public void notify(DeviceEvent event) {
460 assertEquals(DEVICE_ADDED, event.type());
461 assertDevice(DID1, SW1, event.subject());
462 addLatch.countDown();
463 }
464 };
465 final CountDownLatch updateLatch = new CountDownLatch(1);
466 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
467 @Override
468 public void notify(DeviceEvent event) {
469 assertEquals(DEVICE_UPDATED, event.type());
470 assertDevice(DID1, SW2, event.subject());
471 updateLatch.countDown();
472 }
473 };
474 final CountDownLatch removeLatch = new CountDownLatch(1);
475 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
476 @Override
477 public void notify(DeviceEvent event) {
478 assertEquals(DEVICE_REMOVED, event.type());
479 assertDevice(DID1, SW2, event.subject());
480 removeLatch.countDown();
481 }
482 };
483
484 DeviceDescription description =
485 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
486 HW, SW1, SN);
487 deviceStore.setDelegate(checkAdd);
488 deviceStore.createOrUpdateDevice(PID, DID1, description);
489 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
490
491
492 DeviceDescription description2 =
493 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
494 HW, SW2, SN);
495 deviceStore.unsetDelegate(checkAdd);
496 deviceStore.setDelegate(checkUpdate);
497 deviceStore.createOrUpdateDevice(PID, DID1, description2);
498 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
499
500 deviceStore.unsetDelegate(checkUpdate);
501 deviceStore.setDelegate(checkRemove);
502 deviceStore.removeDevice(DID1);
503 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
504 }
505}