/** * Verifies that Annotations created by merging {@code annotations} is equal to actual * Annotations. * * @param actual Annotations to check * @param annotations */ private static void assertAnnotationsEquals( Annotations actual, SparseAnnotations... annotations) { SparseAnnotations expected = DefaultAnnotations.builder().build(); for (SparseAnnotations a : annotations) { expected = DefaultAnnotations.union(expected, a); } assertEquals(expected.keys(), actual.keys()); for (String key : expected.keys()) { assertEquals(expected.value(key), actual.value(key)); } }
// Produces set of annotations from the given JSON node. private SparseAnnotations annotations(JsonNode node) { if (node == null) { return null; } DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); Iterator<String> it = node.fieldNames(); while (it.hasNext()) { String k = it.next(); builder.set(k, node.get(k).asText()); } return builder.build(); }
/** * Generates an annotation from an existing annotation and DeviceConfig. * * @param bdc the device config entity from network config * @param an the annotation * @return annotation combining both sources */ public static SparseAnnotations combine(BasicDeviceConfig bdc, SparseAnnotations an) { DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder(); if (bdc.driver() != an.value(AnnotationKeys.DRIVER)) { newBuilder.set(AnnotationKeys.DRIVER, bdc.driver()); } if (bdc.name() != null) { newBuilder.set(AnnotationKeys.NAME, bdc.name()); } if (bdc.latitude() != DEFAULT_COORD) { newBuilder.set(AnnotationKeys.LATITUDE, Double.toString(bdc.latitude())); } if (bdc.longitude() != DEFAULT_COORD) { newBuilder.set(AnnotationKeys.LONGITUDE, Double.toString(bdc.longitude())); } if (bdc.rackAddress() != null) { newBuilder.set(AnnotationKeys.RACK_ADDRESS, bdc.rackAddress()); } if (bdc.owner() != null) { newBuilder.set(AnnotationKeys.OWNER, bdc.owner()); } DefaultAnnotations newAnnotations = newBuilder.build(); return DefaultAnnotations.union(an, newAnnotations); }
/** Test of the default link description. */ public class DefaultLinkDescriptionTest { private static final DeviceId DID1 = deviceId("of:foo"); private static final DeviceId DID2 = deviceId("of:bar"); private static final PortNumber P1 = portNumber(1); private static final DefaultAnnotations DA = DefaultAnnotations.builder().set("Key", "Value").build(); @Test public void basics() { LinkDescription desc = new DefaultLinkDescription(cp(DID1, P1), cp(DID2, P1), DIRECT, DA); assertEquals("incorrect src", cp(DID1, P1), desc.src()); assertEquals("incorrect dst", cp(DID2, P1), desc.dst()); assertEquals("incorrect type", DIRECT, desc.type()); assertTrue("incorrect annotatios", desc.toString().contains("Key=Value")); } }
private void deviceAdded(RestSBDevice nodeId) { Preconditions.checkNotNull(nodeId, ISNOTNULL); DeviceId deviceId = nodeId.deviceId(); ChassisId cid = new ChassisId(); String ipAddress = nodeId.ip().toString(); SparseAnnotations annotations = DefaultAnnotations.builder().set(IPADDRESS, ipAddress).build(); DeviceDescription deviceDescription = new DefaultDeviceDescription( deviceId.uri(), Device.Type.SWITCH, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations); providerService.deviceConnected(deviceId, deviceDescription); nodeId.setActive(true); controller.addDevice(nodeId); }
@Override public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) { Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); OpenstackPort vPort = openstackService.port(port); if (vPort == null) { log.warn("Failed to get OpenstackPort for {}", getPortName(port)); return; } MacAddress mac = vPort.macAddress(); HostId hostId = HostId.hostId(mac); Host host = hostService.getHost(hostId); if (host != null) { // Host is already known to the system, no HOST_ADDED event is triggered in this case. // It happens when the application is restarted. // TODO check host description if it has all the information serviceVmAdded(host); return; } Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values()); SparseAnnotations annotations = DefaultAnnotations.builder() .set(OPENSTACK_VM_ID, vPort.deviceId()) .set(SERVICE_ID, vPort.networkId()) .set(LOCATION_IP, node.localIp().toString()) .build(); HostDescription hostDesc = new DefaultHostDescription( mac, VlanId.NONE, new HostLocation(connectPoint, System.currentTimeMillis()), ip, annotations); hostProvider.hostDetected(hostId, hostDesc, false); }
@Override public void deviceAdded(NetconfDeviceInfo nodeId) { Preconditions.checkNotNull(nodeId, ISNULL); DeviceId deviceId = nodeId.getDeviceId(); // Netconf configuration object ChassisId cid = new ChassisId(); String ipAddress = nodeId.ip().toString(); SparseAnnotations annotations = DefaultAnnotations.builder() .set(IPADDRESS, ipAddress) .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()) .build(); DeviceDescription deviceDescription = new DefaultDeviceDescription( deviceId.uri(), Device.Type.SWITCH, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations); providerService.deviceConnected(deviceId, deviceDescription); }
/** Test of the gossip based distributed DeviceStore implementation. */ public class GossipDeviceStoreTest { 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(); // local node private static final NodeId NID1 = new NodeId("local"); private static final ControllerNode ONOS1 = new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.0.1")); // remote node private static final NodeId NID2 = new NodeId("remote"); private static final ControllerNode ONOS2 = new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.0.2")); private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList(); private TestGossipDeviceStore testGossipDeviceStore; private GossipDeviceStore gossipDeviceStore; private DeviceStore deviceStore; private DeviceClockService deviceClockService = new TestDeviceClockService(); private ClusterCommunicationService clusterCommunicator; @BeforeClass public static void setUpBeforeClass() throws Exception {} @AfterClass public static void tearDownAfterClass() throws Exception {} @Before public void setUp() throws Exception { clusterCommunicator = createNiceMock(ClusterCommunicationService.class); clusterCommunicator.addSubscriber( anyObject(MessageSubject.class), anyObject(ClusterMessageHandler.class), anyObject(ExecutorService.class)); expectLastCall().anyTimes(); replay(clusterCommunicator); ClusterService clusterService = new TestClusterService(); testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator); testGossipDeviceStore.mastershipService = new TestMastershipService(); TestDatabaseManager testDatabaseManager = new TestDatabaseManager(); testDatabaseManager.init(clusterService, clusterCommunicator); testGossipDeviceStore.storageService = testDatabaseManager; testGossipDeviceStore.deviceClockService = deviceClockService; gossipDeviceStore = testGossipDeviceStore; gossipDeviceStore.activate(); deviceStore = gossipDeviceStore; verify(clusterCommunicator); reset(clusterCommunicator); } @After public void tearDown() throws Exception { gossipDeviceStore.deactivate(); } private void putDevice(DeviceId deviceId, String swVersion, SparseAnnotations... annotations) { DeviceDescription description = new DefaultDeviceDescription( deviceId.uri(), SWITCH, MFR, HW, swVersion, SN, CID, annotations); reset(clusterCommunicator); clusterCommunicator.<InternalDeviceEvent>broadcast( anyObject(InternalDeviceEvent.class), anyObject(MessageSubject.class), anyObject(Function.class)); expectLastCall().anyTimes(); replay(clusterCommunicator); deviceStore.createOrUpdateDevice(PID, deviceId, description); verify(clusterCommunicator); } 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()); } /** * Verifies that Annotations created by merging {@code annotations} is equal to actual * Annotations. * * @param actual Annotations to check * @param annotations */ private static void assertAnnotationsEquals( Annotations actual, SparseAnnotations... annotations) { SparseAnnotations expected = DefaultAnnotations.builder().build(); for (SparseAnnotations a : annotations) { expected = DefaultAnnotations.union(expected, a); } assertEquals(expected.keys(), actual.keys()); for (String key : expected.keys()) { assertEquals(expected.value(key), actual.value(key)); } } private static void assertDeviceDescriptionEquals( DeviceDescription expected, DeviceDescription actual) { if (expected == actual) { return; } assertEquals(expected.deviceURI(), actual.deviceURI()); assertEquals(expected.hwVersion(), actual.hwVersion()); assertEquals(expected.manufacturer(), actual.manufacturer()); assertEquals(expected.serialNumber(), actual.serialNumber()); assertEquals(expected.swVersion(), actual.swVersion()); assertAnnotationsEquals(actual.annotations(), expected.annotations()); } private static void assertDeviceDescriptionEquals( DeviceDescription expected, List<SparseAnnotations> expectedAnnotations, DeviceDescription actual) { if (expected == actual) { return; } assertEquals(expected.deviceURI(), actual.deviceURI()); assertEquals(expected.hwVersion(), actual.hwVersion()); assertEquals(expected.manufacturer(), actual.manufacturer()); assertEquals(expected.serialNumber(), actual.serialNumber()); assertEquals(expected.swVersion(), actual.swVersion()); assertAnnotationsEquals( actual.annotations(), expectedAnnotations.toArray(new SparseAnnotations[0])); } @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)); } private void assertInternalDeviceEvent( NodeId sender, DeviceId deviceId, ProviderId providerId, DeviceDescription expectedDesc, Capture<InternalDeviceEvent> actualEvent, Capture<MessageSubject> actualSubject, Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) { assertTrue(actualEvent.hasCaptured()); assertTrue(actualSubject.hasCaptured()); assertTrue(actualEncoder.hasCaptured()); assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, actualSubject.getValue()); assertEquals(deviceId, actualEvent.getValue().deviceId()); assertEquals(providerId, actualEvent.getValue().providerId()); assertDeviceDescriptionEquals(expectedDesc, actualEvent.getValue().deviceDescription().value()); } private void assertInternalDeviceEvent( NodeId sender, DeviceId deviceId, ProviderId providerId, DeviceDescription expectedDesc, List<SparseAnnotations> expectedAnnotations, Capture<InternalDeviceEvent> actualEvent, Capture<MessageSubject> actualSubject, Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) { assertTrue(actualEvent.hasCaptured()); assertTrue(actualSubject.hasCaptured()); assertTrue(actualEncoder.hasCaptured()); assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, actualSubject.getValue()); assertEquals(deviceId, actualEvent.getValue().deviceId()); assertEquals(providerId, actualEvent.getValue().providerId()); assertDeviceDescriptionEquals( expectedDesc, expectedAnnotations, actualEvent.getValue().deviceDescription().value()); } @Test public final void testCreateOrUpdateDevice() throws IOException { DeviceDescription description = new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, HW, SW1, SN, CID); Capture<InternalDeviceEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); assertEquals(DEVICE_ADDED, event.type()); assertDevice(DID1, SW1, event.subject()); verify(clusterCommunicator); assertInternalDeviceEvent(NID1, DID1, PID, description, message, subject, encoder); DeviceDescription description2 = new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, HW, SW2, SN, CID); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); assertEquals(DEVICE_UPDATED, event2.type()); assertDevice(DID1, SW2, event2.subject()); verify(clusterCommunicator); assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder); reset(clusterCommunicator); assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); } @Test public final void testCreateOrUpdateDeviceAncillary() throws IOException { // add DeviceDescription description = new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, HW, SW1, SN, CID, A2); Capture<ClusterMessage> bcast = new Capture<>(); Capture<InternalDeviceEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); 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)); verify(clusterCommunicator); assertInternalDeviceEvent(NID1, DID1, PIDA, description, message, subject, encoder); // update from primary DeviceDescription description2 = new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, HW, SW2, SN, CID, A1); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); 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)); verify(clusterCommunicator); assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder); // no-op update from primary resetCommunicatorExpectingNoBroadcast(message, subject, encoder); assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); verify(clusterCommunicator); assertFalse("no broadcast expected", bcast.hasCaptured()); // For now, Ancillary is ignored once primary appears resetCommunicatorExpectingNoBroadcast(message, subject, encoder); assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); verify(clusterCommunicator); assertFalse("no broadcast expected", bcast.hasCaptured()); // But, Ancillary annotations will be in effect DeviceDescription description3 = new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, HW, SW1, SN, CID, A2_2); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); 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)); verify(clusterCommunicator); // note: only annotation from PIDA is sent over the wire assertInternalDeviceEvent( NID1, DID1, PIDA, description3, asList(union(A2, A2_2)), message, subject, encoder); } @Test public final void testMarkOffline() { putDevice(DID1, SW1); assertTrue(deviceStore.isAvailable(DID1)); Capture<InternalDeviceEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); DeviceEvent event = deviceStore.markOffline(DID1); assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); assertDevice(DID1, SW1, event.subject()); assertFalse(deviceStore.isAvailable(DID1)); verify(clusterCommunicator); // TODO: verify broadcast message assertTrue(message.hasCaptured()); resetCommunicatorExpectingNoBroadcast(message, subject, encoder); DeviceEvent event2 = deviceStore.markOffline(DID1); assertNull("No change, no event", event2); verify(clusterCommunicator); assertFalse(message.hasCaptured()); } @Test public final void testUpdatePorts() { putDevice(DID1, SW1); List<PortDescription> pds = Arrays.<PortDescription>asList( new DefaultPortDescription(P1, true), new DefaultPortDescription(P2, true)); Capture<InternalDeviceEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); verify(clusterCommunicator); // TODO: verify broadcast message assertTrue(message.hasCaptured()); 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)); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); events = deviceStore.updatePorts(PID, DID1, pds2); verify(clusterCommunicator); // TODO: verify broadcast message assertTrue(message.hasCaptured()); 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)); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); events = deviceStore.updatePorts(PID, DID1, pds3); verify(clusterCommunicator); // TODO: verify broadcast message assertTrue(message.hasCaptured()); 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); Capture<InternalPortStatusEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalPortStatusEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); final DefaultPortDescription desc = new DefaultPortDescription(P1, false); DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc); assertEquals(PORT_UPDATED, event.type()); assertDevice(DID1, SW1, event.subject()); assertEquals(P1, event.port().number()); assertFalse("Port is disabled", event.port().isEnabled()); verify(clusterCommunicator); assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, message, subject, encoder); assertTrue(message.hasCaptured()); } @Test public final void testUpdatePortStatusAncillary() throws IOException { putDeviceAncillary(DID1, SW1); putDevice(DID1, SW1); List<PortDescription> pds = Arrays.<PortDescription>asList(new DefaultPortDescription(P1, true, A1)); deviceStore.updatePorts(PID, DID1, pds); Capture<InternalPortStatusEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalPortStatusEvent, byte[]>> encoder = new Capture<>(); // update port from primary resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2); DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1); 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()); verify(clusterCommunicator); assertInternalPortStatusEvent( NID1, DID1, PID, desc1, asList(A1, A1_2), message, subject, encoder); assertTrue(message.hasCaptured()); // update port from ancillary with no attributes resetCommunicatorExpectingNoBroadcast(message, subject, encoder); final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true); DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2); assertNull("Ancillary is ignored if primary exists", event2); verify(clusterCommunicator); assertFalse(message.hasCaptured()); // but, Ancillary annotation update will be notified resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2); DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3); 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()); verify(clusterCommunicator); assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), message, subject, encoder); assertTrue(message.hasCaptured()); // port only reported from Ancillary will be notified as down resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true); DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4); 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()); verify(clusterCommunicator); // TODO: verify broadcast message content assertInternalPortStatusEvent( NID1, DID1, PIDA, desc4, NO_ANNOTATION, message, subject, encoder); assertTrue(message.hasCaptured()); } private void assertInternalPortStatusEvent( NodeId sender, DeviceId did, ProviderId pid, DefaultPortDescription expectedDesc, List<SparseAnnotations> expectedAnnotations, Capture<InternalPortStatusEvent> actualEvent, Capture<MessageSubject> actualSubject, Capture<Function<InternalPortStatusEvent, byte[]>> actualEncoder) { assertTrue(actualEvent.hasCaptured()); assertTrue(actualSubject.hasCaptured()); assertTrue(actualEncoder.hasCaptured()); assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, actualSubject.getValue()); assertEquals(did, actualEvent.getValue().deviceId()); assertEquals(pid, actualEvent.getValue().providerId()); assertPortDescriptionEquals( expectedDesc, expectedAnnotations, actualEvent.getValue().portDescription().value()); } private void assertPortDescriptionEquals( PortDescription expectedDesc, List<SparseAnnotations> expectedAnnotations, PortDescription actual) { assertEquals(expectedDesc.portNumber(), actual.portNumber()); assertEquals(expectedDesc.isEnabled(), actual.isEnabled()); assertAnnotationsEquals( actual.annotations(), expectedAnnotations.toArray(new SparseAnnotations[0])); } private <T> void resetCommunicatorExpectingNoBroadcast( Capture<T> message, Capture<MessageSubject> subject, Capture<Function<T, byte[]>> encoder) { message.reset(); subject.reset(); encoder.reset(); reset(clusterCommunicator); replay(clusterCommunicator); } private <T> void resetCommunicatorExpectingSingleBroadcast( Capture<T> message, Capture<MessageSubject> subject, Capture<Function<T, byte[]>> encoder) { message.reset(); subject.reset(); encoder.reset(); reset(clusterCommunicator); clusterCommunicator.broadcast(capture(message), capture(subject), capture(encoder)); expectLastCall().once(); replay(clusterCommunicator); } @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); Capture<InternalDeviceEvent> message = new Capture<>(); Capture<MessageSubject> subject = new Capture<>(); Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>(); resetCommunicatorExpectingSingleBroadcast(message, subject, encoder); 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()); verify(clusterCommunicator); // TODO: verify broadcast message assertTrue(message.hasCaptured()); // 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)); } private final class TestMastershipService extends MastershipServiceAdapter { @Override public NodeId getMasterFor(DeviceId deviceId) { return NID1; } @Override public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { return CompletableFuture.completedFuture(null); } } private static final class TestGossipDeviceStore extends GossipDeviceStore { public TestGossipDeviceStore( DeviceClockService deviceClockService, ClusterService clusterService, ClusterCommunicationService clusterCommunicator) { this.deviceClockService = deviceClockService; this.clusterService = clusterService; this.clusterCommunicator = clusterCommunicator; } } private static final class TestClusterService extends StaticClusterService { public TestClusterService() { localNode = ONOS1; nodes.put(NID1, ONOS1); nodeStates.put(NID1, ACTIVE); nodes.put(NID2, ONOS2); nodeStates.put(NID2, ACTIVE); } } private final class TestDeviceClockService extends DeviceClockServiceAdapter { private final AtomicLong ticker = new AtomicLong(); @Override public Timestamp getTimestamp(DeviceId deviceId) { if (DID1.equals(deviceId)) { return new MastershipBasedTimestamp(1, ticker.getAndIncrement()); } else if (DID2.equals(deviceId)) { return new MastershipBasedTimestamp(2, ticker.getAndIncrement()); } else { throw new IllegalStateException(); } } @Override public boolean isTimestampAvailable(DeviceId deviceId) { return DID1.equals(deviceId) || DID2.equals(deviceId); } } private class TestDatabaseManager extends DatabaseManager { void init(ClusterService clusterService, ClusterCommunicationService clusterCommunicator) { this.clusterService = clusterService; this.clusterCommunicator = clusterCommunicator; } } }
/** Test codifying the group service & group provider service contracts. */ public class GroupManagerTest { private static final ProviderId PID = new ProviderId("of", "groupfoo"); private static final DeviceId DID = DeviceId.deviceId("of:001"); private static final ProviderId FOO_PID = new ProviderId("foo", "foo"); private static final DeviceId FOO_DID = DeviceId.deviceId("foo:002"); private static final DefaultAnnotations ANNOTATIONS = DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build(); private static final Device FOO_DEV = new DefaultDevice(FOO_PID, FOO_DID, Device.Type.SWITCH, "", "", "", "", null, ANNOTATIONS); private GroupManager mgr; private GroupService groupService; private GroupProviderRegistry providerRegistry; private TestGroupListener internalListener = new TestGroupListener(); private GroupListener listener = internalListener; private TestGroupProvider internalProvider; private GroupProvider provider; private GroupProviderService providerService; private ApplicationId appId; private TestDriverManager driverService; @Before public void setUp() { mgr = new GroupManager(); groupService = mgr; // mgr.deviceService = new DeviceManager(); mgr.deviceService = new TestDeviceService(); mgr.cfgService = new ComponentConfigAdapter(); mgr.store = new SimpleGroupStore(); injectEventDispatcher(mgr, new TestEventDispatcher()); providerRegistry = mgr; mgr.activate(null); mgr.addListener(listener); driverService = new TestDriverManager(); driverService.addDriver( new DefaultDriver( "foo", ImmutableList.of(), "", "", "", ImmutableMap.of(GroupProgrammable.class, TestGroupProgrammable.class), ImmutableMap.of())); internalProvider = new TestGroupProvider(PID); provider = internalProvider; providerService = providerRegistry.register(provider); appId = new DefaultApplicationId(2, "org.groupmanager.test"); assertTrue( "provider should be registered", providerRegistry.getProviders().contains(provider.id())); } @After public void tearDown() { providerRegistry.unregister(provider); assertFalse( "provider should not be registered", providerRegistry.getProviders().contains(provider.id())); mgr.removeListener(listener); mgr.deactivate(); injectEventDispatcher(mgr, null); } /** Tests group creation before the device group AUDIT completes. */ @Test public void testGroupServiceBasics() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(DID); } /** Tests initial device group AUDIT process. */ @Test public void testGroupServiceInitialAudit() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(DID); // Test initial group audit process testInitialAuditWithPendingGroupRequests(DID); } /** Tests deletion process of any extraneous groups. */ @Test public void testGroupServiceAuditExtraneous() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(DID); // Test audit with extraneous and missing groups testAuditWithExtraneousMissingGroups(DID); } /** * Tests re-apply process of any missing groups tests execution of any pending group creation * request after the device group AUDIT completes and tests event notifications after receiving * confirmation for any operations from data plane. */ @Test public void testGroupServiceAuditConfirmed() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(DID); // Test audit with extraneous and missing groups testAuditWithExtraneousMissingGroups(DID); // Test audit with confirmed groups testAuditWithConfirmedGroups(DID); } /** Tests group bucket modifications (additions and deletions) and Tests group deletion. */ @Test public void testGroupServiceBuckets() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(DID); programmableTestCleanUp(); testAuditWithExtraneousMissingGroups(DID); // Test group add bucket operations testAddBuckets(DID); // Test group remove bucket operations testRemoveBuckets(DID); // Test group remove operations testRemoveGroup(DID); } /** Tests group creation before the device group AUDIT completes with fallback provider. */ @Test public void testGroupServiceFallbackBasics() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(FOO_DID); programmableTestCleanUp(); } /** Tests initial device group AUDIT process with fallback provider. */ @Test public void testGroupServiceFallbackInitialAudit() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(FOO_DID); programmableTestCleanUp(); // Test initial group audit process testInitialAuditWithPendingGroupRequests(FOO_DID); } /** Tests deletion process of any extraneous groups with fallback provider. */ @Test public void testGroupServiceFallbackAuditExtraneous() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(FOO_DID); programmableTestCleanUp(); // Test audit with extraneous and missing groups testAuditWithExtraneousMissingGroups(FOO_DID); } /** * Tests re-apply process of any missing groups tests execution of any pending group creation * request after the device group AUDIT completes and tests event notifications after receiving * confirmation for any operations from data plane with fallback provider. */ @Test public void testGroupServiceFallbackAuditConfirmed() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(FOO_DID); programmableTestCleanUp(); // Test audit with extraneous and missing groups testAuditWithExtraneousMissingGroups(FOO_DID); // Test audit with confirmed groups testAuditWithConfirmedGroups(FOO_DID); } /** * Tests group bucket modifications (additions and deletions) and Tests group deletion with * fallback provider. */ @Test public void testGroupServiceFallbackBuckets() { // Test Group creation before AUDIT process testGroupCreationBeforeAudit(FOO_DID); programmableTestCleanUp(); testAuditWithExtraneousMissingGroups(FOO_DID); // Test group add bucket operations testAddBuckets(FOO_DID); // Test group remove bucket operations testRemoveBuckets(FOO_DID); // Test group remove operations testRemoveGroup(FOO_DID); } private void programmableTestCleanUp() { groupOperations.clear(); lastDeviceIdProgrammable = null; } // Test Group creation before AUDIT process private void testGroupCreationBeforeAudit(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); List<GroupBucket> buckets = new ArrayList<>(); List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(ports1)); outPorts.addAll(Arrays.asList(ports2)); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId, Group.Type.SELECT, groupBuckets, key, null, appId); groupService.addGroup(newGroupDesc); assertEquals(null, groupService.getGroup(deviceId, key)); assertEquals(0, Iterables.size(groupService.getGroups(deviceId, appId))); } // Test initial AUDIT process with pending group requests private void testInitialAuditWithPendingGroupRequests(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; GroupId gId1 = new DefaultGroupId(1); Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId); GroupId gId2 = new DefaultGroupId(2); // Non zero reference count will make the group manager to queue // the extraneous groups until reference count is zero. Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 2, deviceId); List<Group> groupEntries = Arrays.asList(group1, group2); providerService.pushGroupMetrics(deviceId, groupEntries); // First group metrics would trigger the device audit completion // post which all pending group requests are also executed. GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); Group createdGroup = groupService.getGroup(deviceId, key); int createdGroupId = createdGroup.id().id(); assertNotEquals(gId1.id(), createdGroupId); assertNotEquals(gId2.id(), createdGroupId); List<GroupOperation> expectedGroupOps = Arrays.asList( GroupOperation.createDeleteGroupOperation(gId1, Group.Type.SELECT), GroupOperation.createAddGroupOperation( createdGroup.id(), Group.Type.SELECT, createdGroup.buckets())); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } } // Test AUDIT process with extraneous groups and missing groups private void testAuditWithExtraneousMissingGroups(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; GroupId gId1 = new DefaultGroupId(1); Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId); GroupId gId2 = new DefaultGroupId(2); Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 0, deviceId); List<Group> groupEntries = Arrays.asList(group1, group2); providerService.pushGroupMetrics(deviceId, groupEntries); GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); Group createdGroup = groupService.getGroup(deviceId, key); List<GroupOperation> expectedGroupOps = Arrays.asList( GroupOperation.createDeleteGroupOperation(gId1, Group.Type.SELECT), GroupOperation.createDeleteGroupOperation(gId2, Group.Type.SELECT), GroupOperation.createAddGroupOperation( createdGroup.id(), Group.Type.SELECT, createdGroup.buckets())); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } } // Test AUDIT with confirmed groups private void testAuditWithConfirmedGroups(DeviceId deviceId) { GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); Group createdGroup = groupService.getGroup(deviceId, key); createdGroup = new DefaultGroup(createdGroup.id(), deviceId, Group.Type.SELECT, createdGroup.buckets()); List<Group> groupEntries = Collections.singletonList(createdGroup); providerService.pushGroupMetrics(deviceId, groupEntries); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADDED)); } // Test group add bucket operations private void testAddBuckets(DeviceId deviceId) { GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes()); GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes()); Group createdGroup = groupService.getGroup(deviceId, prevKey); List<GroupBucket> buckets = new ArrayList<>(); buckets.addAll(createdGroup.buckets().buckets()); PortNumber[] addPorts = {PortNumber.portNumber(51), PortNumber.portNumber(52)}; List<PortNumber> outPorts; outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(addPorts)); List<GroupBucket> addBuckets; addBuckets = new ArrayList<>(); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets); groupService.addBucketsToGroup(deviceId, prevKey, groupAddBuckets, addKey, appId); GroupBuckets updatedBuckets = new GroupBuckets(buckets); List<GroupOperation> expectedGroupOps = Collections.singletonList( GroupOperation.createModifyGroupOperation( createdGroup.id(), Group.Type.SELECT, updatedBuckets)); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } Group existingGroup = groupService.getGroup(deviceId, addKey); List<Group> groupEntries = Collections.singletonList(existingGroup); providerService.pushGroupMetrics(deviceId, groupEntries); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED)); } // Test group remove bucket operations private void testRemoveBuckets(DeviceId deviceId) { GroupKey removeKey = new DefaultGroupKey("group1RemoveBuckets".getBytes()); GroupKey prevKey = new DefaultGroupKey("group1AddBuckets".getBytes()); Group createdGroup = groupService.getGroup(deviceId, prevKey); List<GroupBucket> buckets = new ArrayList<>(); buckets.addAll(createdGroup.buckets().buckets()); PortNumber[] removePorts = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(removePorts)); List<GroupBucket> removeBuckets = new ArrayList<>(); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); buckets.remove(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets); groupService.removeBucketsFromGroup(deviceId, prevKey, groupRemoveBuckets, removeKey, appId); GroupBuckets updatedBuckets = new GroupBuckets(buckets); List<GroupOperation> expectedGroupOps = Collections.singletonList( GroupOperation.createModifyGroupOperation( createdGroup.id(), Group.Type.SELECT, updatedBuckets)); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } Group existingGroup = groupService.getGroup(deviceId, removeKey); List<Group> groupEntries = Collections.singletonList(existingGroup); providerService.pushGroupMetrics(deviceId, groupEntries); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED)); } // Test group remove operations private void testRemoveGroup(DeviceId deviceId) { GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes()); Group existingGroup = groupService.getGroup(deviceId, currKey); groupService.removeGroup(deviceId, currKey, appId); List<GroupOperation> expectedGroupOps = Collections.singletonList( GroupOperation.createDeleteGroupOperation(existingGroup.id(), Group.Type.SELECT)); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } List<Group> groupEntries = Collections.emptyList(); providerService.pushGroupMetrics(deviceId, groupEntries); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVED)); } /** * Test GroupOperationFailure function in Group Manager. a)GroupAddFailure b)GroupUpdateFailure * c)GroupRemoteFailure */ @Test public void testGroupOperationFailure() { groupOperationFaliure(DID); } /** * Test GroupOperationFailure function in Group Manager with fallback provider. a)GroupAddFailure * b)GroupUpdateFailure c)GroupRemoteFailure */ @Test public void testGroupOperationFailureFallBack() { groupOperationFaliure(FOO_DID); } private void groupOperationFaliure(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; // Test Group creation before AUDIT process GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); List<GroupBucket> buckets = new ArrayList<>(); List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(ports1)); outPorts.addAll(Arrays.asList(ports2)); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId, Group.Type.SELECT, groupBuckets, key, null, appId); groupService.addGroup(newGroupDesc); // Test initial group audit process GroupId gId1 = new DefaultGroupId(1); Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId); GroupId gId2 = new DefaultGroupId(2); // Non zero reference count will make the group manager to queue // the extraneous groups until reference count is zero. Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 2, deviceId); List<Group> groupEntries = Arrays.asList(group1, group2); providerService.pushGroupMetrics(deviceId, groupEntries); Group createdGroup = groupService.getGroup(deviceId, key); // Group Add failure test GroupOperation groupAddOp = GroupOperation.createAddGroupOperation( createdGroup.id(), createdGroup.type(), createdGroup.buckets()); providerService.groupOperationFailed(deviceId, groupAddOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADD_FAILED)); // Group Mod failure test groupService.addGroup(newGroupDesc); createdGroup = groupService.getGroup(deviceId, key); assertNotNull(createdGroup); GroupOperation groupModOp = GroupOperation.createModifyGroupOperation( createdGroup.id(), createdGroup.type(), createdGroup.buckets()); providerService.groupOperationFailed(deviceId, groupModOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATE_FAILED)); // Group Delete failure test groupService.addGroup(newGroupDesc); createdGroup = groupService.getGroup(deviceId, key); assertNotNull(createdGroup); GroupOperation groupDelOp = GroupOperation.createDeleteGroupOperation(createdGroup.id(), createdGroup.type()); providerService.groupOperationFailed(deviceId, groupDelOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED)); } private Group createSouthboundGroupEntry( GroupId gId, List<PortNumber> ports, long referenceCount, DeviceId deviceId) { List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(ports); List<GroupBucket> buckets = new ArrayList<>(); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); StoredGroupEntry group = new DefaultGroup(gId, deviceId, Group.Type.SELECT, groupBuckets); group.setReferenceCount(referenceCount); return group; } private static class TestGroupListener implements GroupListener { final List<GroupEvent> events = new ArrayList<>(); @Override public void event(GroupEvent event) { events.add(event); } public void validateEvent(List<GroupEvent.Type> expectedEvents) { int i = 0; System.err.println("events :" + events); for (GroupEvent e : events) { assertEquals("unexpected event", expectedEvents.get(i), e.type()); i++; } assertEquals("mispredicted number of events", expectedEvents.size(), events.size()); events.clear(); } } private class TestGroupProvider extends AbstractProvider implements GroupProvider { DeviceId lastDeviceId; List<GroupOperation> groupOperations = new ArrayList<>(); protected TestGroupProvider(ProviderId id) { super(id); } @Override public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) { lastDeviceId = deviceId; groupOperations.addAll(groupOps.operations()); } public void validate(DeviceId expectedDeviceId, List<GroupOperation> expectedGroupOps) { if (expectedGroupOps == null) { assertTrue("events generated", groupOperations.isEmpty()); return; } assertEquals(lastDeviceId, expectedDeviceId); assertTrue( (this.groupOperations.containsAll(expectedGroupOps) && expectedGroupOps.containsAll(groupOperations))); groupOperations.clear(); lastDeviceId = null; } } private static class TestDeviceService extends DeviceServiceAdapter { @Override public int getDeviceCount() { return 1; } @Override public Iterable<Device> getDevices() { return ImmutableList.of(FOO_DEV); } @Override public Iterable<Device> getAvailableDevices() { return getDevices(); } @Override public Device getDevice(DeviceId deviceId) { return FOO_DEV; } } private class TestDriverManager extends DriverManager { TestDriverManager() { this.deviceService = mgr.deviceService; activate(); } } private static DeviceId lastDeviceIdProgrammable; private static List<GroupOperation> groupOperations = new ArrayList<>(); public static class TestGroupProgrammable extends AbstractHandlerBehaviour implements GroupProgrammable { @Override public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) { lastDeviceIdProgrammable = deviceId; groupOperations.addAll(groupOps.operations()); } } public void validate(DeviceId expectedDeviceId, List<GroupOperation> expectedGroupOps) { if (expectedGroupOps == null) { assertTrue("events generated", groupOperations.isEmpty()); return; } assertEquals(lastDeviceIdProgrammable, expectedDeviceId); assertTrue( (this.groupOperations.containsAll(expectedGroupOps) && expectedGroupOps.containsAll(groupOperations))); groupOperations.clear(); lastDeviceIdProgrammable = null; } }
// Parses the given node with port information. private PortDescription parsePort(DeviceId deviceId, JsonNode node) { Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER")); // TL1-based ports have a name PortNumber port = null; if (node.has("name")) { for (Port p : deviceService.getPorts(deviceId)) { if (p.number().name().equals(node.get("name").asText())) { port = p.number(); break; } } } else { port = portNumber(node.path("port").asLong(0)); } if (port == null) { log.error("Cannot find port given in node {}", node); return null; } String portName = Strings.emptyToNull(port.name()); SparseAnnotations annotations = null; if (portName != null) { annotations = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, portName).build(); } switch (type) { case COPPER: return new DefaultPortDescription( port, node.path("enabled").asBoolean(true), type, node.path("speed").asLong(1_000), annotations); case FIBER: // Currently, assume OMS when FIBER. Provide sane defaults. annotations = annotations(node.get("annotations")); return new OmsPortDescription( port, node.path("enabled").asBoolean(true), CENTER, CENTER.add(TOTAL), Frequency.ofGHz(100), annotations); case ODUCLT: annotations = annotations(node.get("annotations")); OduCltPort oduCltPort = (OduCltPort) deviceService.getPort(deviceId, port); return new OduCltPortDescription( port, node.path("enabled").asBoolean(true), oduCltPort.signalType(), annotations); case OCH: annotations = annotations(node.get("annotations")); OchPort ochPort = (OchPort) deviceService.getPort(deviceId, port); return new OchPortDescription( port, node.path("enabled").asBoolean(true), ochPort.signalType(), ochPort.isTunable(), ochPort.lambda(), annotations); case OMS: annotations = annotations(node.get("annotations")); OmsPort omsPort = (OmsPort) deviceService.getPort(deviceId, port); return new OmsPortDescription( port, node.path("enabled").asBoolean(true), omsPort.minFrequency(), omsPort.maxFrequency(), omsPort.grid(), annotations); default: log.warn("{}: Unsupported Port Type"); } return new DefaultPortDescription( port, node.path("enabled").asBoolean(true), type, node.path("speed").asLong(1_000), annotations); }