| /* |
| * Copyright 2015-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * |
| */ |
| package org.onosproject.store.trivial; |
| |
| import static org.junit.Assert.*; |
| import static org.onosproject.net.Device.Type.SWITCH; |
| import static org.onosproject.net.DeviceId.deviceId; |
| import static org.onosproject.net.device.DeviceEvent.Type.*; |
| import static org.onosproject.net.NetTestTools.assertAnnotationsEquals; |
| |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.junit.After; |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.onosproject.net.DefaultAnnotations; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.Port; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.SparseAnnotations; |
| import org.onosproject.net.device.DefaultDeviceDescription; |
| import org.onosproject.net.device.DefaultPortDescription; |
| import org.onosproject.net.device.DeviceDescription; |
| import org.onosproject.net.device.DeviceEvent; |
| import org.onosproject.net.device.DeviceStore; |
| import org.onosproject.net.device.DeviceStoreDelegate; |
| import org.onosproject.net.device.PortDescription; |
| import org.onosproject.net.provider.ProviderId; |
| |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Sets; |
| |
| import org.onlab.packet.ChassisId; |
| |
| /** |
| * Test of the simple DeviceStore implementation. |
| */ |
| public class SimpleDeviceStoreTest { |
| |
| private static final ProviderId PID = new ProviderId("of", "foo"); |
| private static final ProviderId PIDA = new ProviderId("of", "bar", true); |
| private static final DeviceId DID1 = deviceId("of:foo"); |
| private static final DeviceId DID2 = deviceId("of:bar"); |
| private static final String MFR = "whitebox"; |
| private static final String HW = "1.1.x"; |
| private static final String SW1 = "3.8.1"; |
| private static final String SW2 = "3.9.5"; |
| private static final String SN = "43311-12345"; |
| private static final ChassisId CID = new ChassisId(); |
| |
| private static final PortNumber P1 = PortNumber.portNumber(1); |
| private static final PortNumber P2 = PortNumber.portNumber(2); |
| private static final PortNumber P3 = PortNumber.portNumber(3); |
| |
| private static final SparseAnnotations A1 = DefaultAnnotations.builder() |
| .set("A1", "a1") |
| .set("B1", "b1") |
| .build(); |
| private static final SparseAnnotations A1_2 = DefaultAnnotations.builder() |
| .remove("A1") |
| .set("B3", "b3") |
| .build(); |
| private static final SparseAnnotations A2 = DefaultAnnotations.builder() |
| .set("A2", "a2") |
| .set("B2", "b2") |
| .build(); |
| private static final SparseAnnotations A2_2 = DefaultAnnotations.builder() |
| .remove("A2") |
| .set("B4", "b4") |
| .build(); |
| |
| private SimpleDeviceStore simpleDeviceStore; |
| private DeviceStore deviceStore; |
| |
| |
| |
| @BeforeClass |
| public static void setUpBeforeClass() throws Exception { |
| } |
| |
| @AfterClass |
| public static void tearDownAfterClass() throws Exception { |
| } |
| |
| |
| @Before |
| public void setUp() throws Exception { |
| simpleDeviceStore = new SimpleDeviceStore(); |
| simpleDeviceStore.activate(); |
| deviceStore = simpleDeviceStore; |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| simpleDeviceStore.deactivate(); |
| } |
| |
| private void putDevice(DeviceId deviceId, String swVersion, |
| SparseAnnotations... annotations) { |
| DeviceDescription description = |
| new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, |
| HW, swVersion, SN, CID, annotations); |
| deviceStore.createOrUpdateDevice(PID, deviceId, description); |
| } |
| |
| private void putDeviceAncillary(DeviceId deviceId, String swVersion, |
| SparseAnnotations... annotations) { |
| DeviceDescription description = |
| new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, |
| HW, swVersion, SN, CID, annotations); |
| deviceStore.createOrUpdateDevice(PIDA, deviceId, description); |
| } |
| |
| private static void assertDevice(DeviceId id, String swVersion, Device device) { |
| assertNotNull(device); |
| assertEquals(id, device.id()); |
| assertEquals(MFR, device.manufacturer()); |
| assertEquals(HW, device.hwVersion()); |
| assertEquals(swVersion, device.swVersion()); |
| assertEquals(SN, device.serialNumber()); |
| } |
| |
| @Test |
| public final void testGetDeviceCount() { |
| assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); |
| |
| putDevice(DID1, SW1); |
| putDevice(DID2, SW2); |
| putDevice(DID1, SW1); |
| |
| assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount()); |
| } |
| |
| @Test |
| public final void testGetDevices() { |
| assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices())); |
| |
| putDevice(DID1, SW1); |
| putDevice(DID2, SW2); |
| putDevice(DID1, SW1); |
| |
| assertEquals("expect 2 uniq devices", |
| 2, Iterables.size(deviceStore.getDevices())); |
| |
| Map<DeviceId, Device> devices = new HashMap<>(); |
| for (Device device : deviceStore.getDevices()) { |
| devices.put(device.id(), device); |
| } |
| |
| assertDevice(DID1, SW1, devices.get(DID1)); |
| assertDevice(DID2, SW2, devices.get(DID2)); |
| |
| // add case for new node? |
| } |
| |
| @Test |
| public final void testGetDevice() { |
| |
| putDevice(DID1, SW1); |
| |
| assertDevice(DID1, SW1, deviceStore.getDevice(DID1)); |
| assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); |
| } |
| |
| @Test |
| public final void testCreateOrUpdateDevice() { |
| DeviceDescription description = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW1, SN, CID); |
| DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); |
| assertEquals(DEVICE_ADDED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| |
| DeviceDescription description2 = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW2, SN, CID); |
| DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); |
| assertEquals(DEVICE_UPDATED, event2.type()); |
| assertDevice(DID1, SW2, event2.subject()); |
| |
| assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); |
| } |
| |
| @Test |
| public final void testCreateOrUpdateDeviceAncillary() { |
| DeviceDescription description = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW1, SN, CID, A2); |
| DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); |
| assertEquals(DEVICE_ADDED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertEquals(PIDA, event.subject().providerId()); |
| assertAnnotationsEquals(event.subject().annotations(), A2); |
| assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); |
| |
| DeviceDescription description2 = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW2, SN, CID, A1); |
| DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); |
| assertEquals(DEVICE_UPDATED, event2.type()); |
| assertDevice(DID1, SW2, event2.subject()); |
| assertEquals(PID, event2.subject().providerId()); |
| assertAnnotationsEquals(event2.subject().annotations(), A1, A2); |
| assertTrue(deviceStore.isAvailable(DID1)); |
| |
| assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); |
| |
| // For now, Ancillary is ignored once primary appears |
| assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); |
| |
| // But, Ancillary annotations will be in effect |
| DeviceDescription description3 = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW1, SN, CID, A2_2); |
| DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); |
| assertEquals(DEVICE_UPDATED, event3.type()); |
| // basic information will be the one from Primary |
| assertDevice(DID1, SW2, event3.subject()); |
| assertEquals(PID, event3.subject().providerId()); |
| // but annotation from Ancillary will be merged |
| assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); |
| assertTrue(deviceStore.isAvailable(DID1)); |
| } |
| |
| |
| @Test |
| public final void testMarkOffline() { |
| |
| putDevice(DID1, SW1); |
| assertTrue(deviceStore.isAvailable(DID1)); |
| |
| DeviceEvent event = deviceStore.markOffline(DID1); |
| assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertFalse(deviceStore.isAvailable(DID1)); |
| |
| DeviceEvent event2 = deviceStore.markOffline(DID1); |
| assertNull("No change, no event", event2); |
| } |
| |
| @Test |
| public final void testUpdatePorts() { |
| putDevice(DID1, SW1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true), |
| new DefaultPortDescription(P2, true) |
| ); |
| |
| List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
| |
| Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
| for (DeviceEvent event : events) { |
| assertEquals(PORT_ADDED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertTrue("PortNumber is one of expected", |
| expectedPorts.remove(event.port().number())); |
| assertTrue("Port is enabled", event.port().isEnabled()); |
| } |
| assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); |
| |
| |
| List<PortDescription> pds2 = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, false), |
| new DefaultPortDescription(P2, true), |
| new DefaultPortDescription(P3, true) |
| ); |
| |
| events = deviceStore.updatePorts(PID, DID1, pds2); |
| assertFalse("event should be triggered", events.isEmpty()); |
| for (DeviceEvent event : events) { |
| PortNumber num = event.port().number(); |
| if (P1.equals(num)) { |
| assertEquals(PORT_UPDATED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertFalse("Port is disabled", event.port().isEnabled()); |
| } else if (P2.equals(num)) { |
| fail("P2 event not expected."); |
| } else if (P3.equals(num)) { |
| assertEquals(PORT_ADDED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertTrue("Port is enabled", event.port().isEnabled()); |
| } else { |
| fail("Unknown port number encountered: " + num); |
| } |
| } |
| |
| List<PortDescription> pds3 = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, false), |
| new DefaultPortDescription(P2, true) |
| ); |
| events = deviceStore.updatePorts(PID, DID1, pds3); |
| assertFalse("event should be triggered", events.isEmpty()); |
| for (DeviceEvent event : events) { |
| PortNumber num = event.port().number(); |
| if (P1.equals(num)) { |
| fail("P1 event not expected."); |
| } else if (P2.equals(num)) { |
| fail("P2 event not expected."); |
| } else if (P3.equals(num)) { |
| assertEquals(PORT_REMOVED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertTrue("Port was enabled", event.port().isEnabled()); |
| } else { |
| fail("Unknown port number encountered: " + num); |
| } |
| } |
| |
| } |
| |
| @Test |
| public final void testUpdatePortStatus() { |
| putDevice(DID1, SW1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds); |
| |
| DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
| new DefaultPortDescription(P1, false)); |
| assertEquals(PORT_UPDATED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertEquals(P1, event.port().number()); |
| assertFalse("Port is disabled", event.port().isEnabled()); |
| |
| } |
| |
| @Test |
| public final void testUpdatePortStatusAncillary() { |
| putDeviceAncillary(DID1, SW1); |
| putDevice(DID1, SW1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true, A1) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds); |
| |
| DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
| new DefaultPortDescription(P1, false, A1_2)); |
| assertEquals(PORT_UPDATED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| assertEquals(P1, event.port().number()); |
| assertAnnotationsEquals(event.port().annotations(), A1, A1_2); |
| assertFalse("Port is disabled", event.port().isEnabled()); |
| |
| DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, |
| new DefaultPortDescription(P1, true)); |
| assertNull("Ancillary is ignored if primary exists", event2); |
| |
| // but, Ancillary annotation update will be notified |
| DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, |
| new DefaultPortDescription(P1, true, A2)); |
| assertEquals(PORT_UPDATED, event3.type()); |
| assertDevice(DID1, SW1, event3.subject()); |
| assertEquals(P1, event3.port().number()); |
| assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); |
| assertFalse("Port is disabled", event3.port().isEnabled()); |
| |
| // port only reported from Ancillary will be notified as down |
| DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, |
| new DefaultPortDescription(P2, true)); |
| assertEquals(PORT_ADDED, event4.type()); |
| assertDevice(DID1, SW1, event4.subject()); |
| assertEquals(P2, event4.port().number()); |
| assertAnnotationsEquals(event4.port().annotations()); |
| assertFalse("Port is disabled if not given from primary provider", |
| event4.port().isEnabled()); |
| } |
| |
| @Test |
| public final void testGetPorts() { |
| putDevice(DID1, SW1); |
| putDevice(DID2, SW1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true), |
| new DefaultPortDescription(P2, true) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds); |
| |
| Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
| List<Port> ports = deviceStore.getPorts(DID1); |
| for (Port port : ports) { |
| assertTrue("Port is enabled", port.isEnabled()); |
| assertTrue("PortNumber is one of expected", |
| expectedPorts.remove(port.number())); |
| } |
| assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); |
| |
| |
| assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty()); |
| } |
| |
| @Test |
| public final void testGetPort() { |
| putDevice(DID1, SW1); |
| putDevice(DID2, SW1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true), |
| new DefaultPortDescription(P2, false) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds); |
| |
| Port port1 = deviceStore.getPort(DID1, P1); |
| assertEquals(P1, port1.number()); |
| assertTrue("Port is enabled", port1.isEnabled()); |
| |
| Port port2 = deviceStore.getPort(DID1, P2); |
| assertEquals(P2, port2.number()); |
| assertFalse("Port is disabled", port2.isEnabled()); |
| |
| Port port3 = deviceStore.getPort(DID1, P3); |
| assertNull("P3 not expected", port3); |
| } |
| |
| @Test |
| public final void testRemoveDevice() { |
| putDevice(DID1, SW1, A1); |
| List<PortDescription> pds = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true, A2) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds); |
| putDevice(DID2, SW1); |
| |
| assertEquals(2, deviceStore.getDeviceCount()); |
| assertEquals(1, deviceStore.getPorts(DID1).size()); |
| assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1); |
| assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2); |
| |
| DeviceEvent event = deviceStore.removeDevice(DID1); |
| assertEquals(DEVICE_REMOVED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| |
| assertEquals(1, deviceStore.getDeviceCount()); |
| assertEquals(0, deviceStore.getPorts(DID1).size()); |
| |
| // putBack Device, Port w/o annotation |
| putDevice(DID1, SW1); |
| List<PortDescription> pds2 = Arrays.<PortDescription>asList( |
| new DefaultPortDescription(P1, true) |
| ); |
| deviceStore.updatePorts(PID, DID1, pds2); |
| |
| // annotations should not survive |
| assertEquals(2, deviceStore.getDeviceCount()); |
| assertEquals(1, deviceStore.getPorts(DID1).size()); |
| assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations()); |
| assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations()); |
| } |
| |
| // If Delegates should be called only on remote events, |
| // then Simple* should never call them, thus not test required. |
| // TODO add test for Port events when we have them |
| @Ignore("Ignore until Delegate spec. is clear.") |
| @Test |
| public final void testEvents() throws InterruptedException { |
| final CountDownLatch addLatch = new CountDownLatch(1); |
| DeviceStoreDelegate checkAdd = event -> { |
| assertEquals(DEVICE_ADDED, event.type()); |
| assertDevice(DID1, SW1, event.subject()); |
| addLatch.countDown(); |
| }; |
| final CountDownLatch updateLatch = new CountDownLatch(1); |
| DeviceStoreDelegate checkUpdate = event -> { |
| assertEquals(DEVICE_UPDATED, event.type()); |
| assertDevice(DID1, SW2, event.subject()); |
| updateLatch.countDown(); |
| }; |
| final CountDownLatch removeLatch = new CountDownLatch(1); |
| DeviceStoreDelegate checkRemove = event -> { |
| assertEquals(DEVICE_REMOVED, event.type()); |
| assertDevice(DID1, SW2, event.subject()); |
| removeLatch.countDown(); |
| }; |
| |
| DeviceDescription description = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW1, SN, CID); |
| deviceStore.setDelegate(checkAdd); |
| deviceStore.createOrUpdateDevice(PID, DID1, description); |
| assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); |
| |
| |
| DeviceDescription description2 = |
| new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
| HW, SW2, SN, CID); |
| deviceStore.unsetDelegate(checkAdd); |
| deviceStore.setDelegate(checkUpdate); |
| deviceStore.createOrUpdateDevice(PID, DID1, description2); |
| assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS)); |
| |
| deviceStore.unsetDelegate(checkUpdate); |
| deviceStore.setDelegate(checkRemove); |
| deviceStore.removeDevice(DID1); |
| assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); |
| } |
| } |