Add unit test for openstack switching host provider
Change-Id: If2ff5cf7d361d3857aca14b67e8d66ced0aacaa6
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index b19d78d..01e1099 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -46,7 +46,6 @@
import org.onosproject.net.host.HostService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
-import org.onosproject.openstacknetworking.api.InstancePortAdminService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
import org.onosproject.openstacknode.api.OpenstackNode;
import org.onosproject.openstacknode.api.OpenstackNodeEvent;
@@ -105,18 +104,15 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackNodeService osNodeService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected InstancePortAdminService instancePortAdminService;
+ private HostProviderService hostProviderService;
- private final ExecutorService deviceEventExecutor =
+ private final ExecutorService executor =
Executors.newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "device-event"));
private final InternalDeviceListener internalDeviceListener =
new InternalDeviceListener();
private final InternalOpenstackNodeListener internalNodeListener =
new InternalOpenstackNodeListener();
- private HostProviderService hostProvider;
-
/**
* Creates OpenStack switching host provider.
*/
@@ -129,7 +125,7 @@
coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
deviceService.addListener(internalDeviceListener);
osNodeService.addListener(internalNodeListener);
- hostProvider = hostProviderRegistry.register(this);
+ hostProviderService = hostProviderRegistry.register(this);
log.info("Started");
}
@@ -140,7 +136,7 @@
osNodeService.removeListener(internalNodeListener);
deviceService.removeListener(internalDeviceListener);
- deviceEventExecutor.shutdown();
+ executor.shutdown();
log.info("Stopped");
}
@@ -151,6 +147,32 @@
}
/**
+ * A helper method which logs the port addition event and performs port
+ * addition action.
+ *
+ * @param event device event
+ */
+ protected void portAddedHelper(DeviceEvent event) {
+ log.debug("Instance port {} is detected from {}",
+ event.port().annotations().value(PORT_NAME),
+ event.subject().id());
+ processPortAdded(event.port());
+ }
+
+ /**
+ * A helper method which logs the port removal event and performs port
+ * removal action.
+ *
+ * @param event device event
+ */
+ protected void portRemovedHelper(DeviceEvent event) {
+ log.debug("Instance port {} is removed from {}",
+ event.port().annotations().value(PORT_NAME),
+ event.subject().id());
+ processPortRemoved(event.port());
+ }
+
+ /**
* Processes port addition event.
* Once a port addition event is detected, it tries to create a host instance
* with openstack augmented host information such as networkId, portId,
@@ -158,7 +180,7 @@
*
* @param port port object used in ONOS
*/
- private void processPortAdded(Port port, Device device) {
+ protected void processPortAdded(Port port) {
// TODO check the node state is COMPLETE
org.openstack4j.model.network.Port osPort = osNetworkService.port(port);
if (osPort == null) {
@@ -228,17 +250,17 @@
// newly added location is not in the existing location list,
// therefore, we simply add this into the location list
if (locations.size() == 0) {
- hostProvider.addLocationToHost(hostId,
+ hostProviderService.addLocationToHost(hostId,
new HostLocation(connectPoint, createTime));
}
// newly added location is in the existing location list,
// the hostDetected method invocation in turn triggers host Update event
if (locations.size() == 1) {
- hostProvider.hostDetected(hostId, hostDesc, false);
+ hostProviderService.hostDetected(hostId, hostDesc, false);
}
} else {
- hostProvider.hostDetected(hostId, hostDesc, false);
+ hostProviderService.hostDetected(hostId, hostDesc, false);
}
}
@@ -248,10 +270,9 @@
* instance through host provider by giving connect point information,
* and vanishes it.
*
- * @param event device event
+ * @param port ONOS port
*/
- private void processPortRemoved(DeviceEvent event) {
- Port port = event.port();
+ protected void processPortRemoved(Port port) {
ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
Set<Host> hosts = hostService.getConnectedHosts(connectPoint);
@@ -263,13 +284,13 @@
// if the host contains only one filtered location, we remove the host
if (h.locations().size() == 1) {
- hostProvider.hostVanished(h.id());
+ hostProviderService.hostVanished(h.id());
}
// if the host contains multiple locations, we simply remove the
// host location
if (h.locations().size() > 1 && hostLocation.isPresent()) {
- hostProvider.removeLocationFromHost(h.id(), hostLocation.get());
+ hostProviderService.removeLocationFromHost(h.id(), hostLocation.get());
}
});
}
@@ -298,7 +319,7 @@
}
private boolean isDirectPort(String portName) {
- return portNamePrefixMap().values().stream().filter(p -> portName.startsWith(p)).findAny().isPresent();
+ return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
}
@Override
@@ -307,16 +328,16 @@
switch (event.type()) {
case PORT_UPDATED:
if (!event.port().isEnabled()) {
- portRemovedHelper(deviceEventExecutor, event);
+ executor.execute(() -> portRemovedHelper(event));
} else if (event.port().isEnabled()) {
- portAddedHelper(deviceEventExecutor, event);
+ executor.execute(() -> portAddedHelper(event));
}
break;
case PORT_ADDED:
- portAddedHelper(deviceEventExecutor, event);
+ executor.execute(() -> portAddedHelper(event));
break;
case PORT_REMOVED:
- portRemovedHelper(deviceEventExecutor, event);
+ executor.execute(() -> portRemovedHelper(event));
break;
default:
break;
@@ -324,38 +345,6 @@
}
}
- /**
- * A helper method which logs the port addition event and performs port
- * addition action.
- *
- * @param executor device executor service
- * @param event device event
- */
- private void portAddedHelper(ExecutorService executor, DeviceEvent event) {
- executor.execute(() -> {
- log.debug("Instance port {} is detected from {}",
- event.port().annotations().value(PORT_NAME),
- event.subject().id());
- processPortAdded(event.port(), event.subject());
- });
- }
-
- /**
- * A helper method which logs the port removal event and performs port
- * removal action.
- *
- * @param executor device executor service
- * @param event device event
- */
- private void portRemovedHelper(ExecutorService executor, DeviceEvent event) {
- executor.execute(() -> {
- log.debug("Instance port {} is removed from {}",
- event.port().annotations().value(PORT_NAME),
- event.subject().id());
- processPortRemoved(event);
- });
- }
-
private class InternalOpenstackNodeListener implements OpenstackNodeListener {
@Override
@@ -378,10 +367,8 @@
switch (event.type()) {
case OPENSTACK_NODE_COMPLETE:
- deviceEventExecutor.execute(() -> {
- log.info("COMPLETE node {} is detected", osNode.hostname());
- processCompleteNode(event.subject());
- });
+ log.info("COMPLETE node {} is detected", osNode.hostname());
+ executor.execute(() -> processCompleteNode(event.subject()));
break;
case OPENSTACK_NODE_INCOMPLETE:
log.warn("{} is changed to INCOMPLETE state", osNode);
@@ -405,23 +392,20 @@
log.debug("Instance port {} is detected from {}",
port.annotations().value(PORT_NAME),
osNode.hostname());
- processPortAdded(port,
- deviceService.getDevice(osNode.intgBridge()));
+ processPortAdded(port);
});
- portNamePrefixMap().values().forEach(portNamePrefix -> {
- deviceService.getPorts(osNode.intgBridge()).stream()
- .filter(port -> port.annotations().value(PORT_NAME)
- .startsWith(portNamePrefix) &&
- port.isEnabled())
- .forEach(port -> {
- log.debug("Instance port {} is detected from {}",
- port.annotations().value(portNamePrefix),
- osNode.hostname());
- processPortAdded(port,
- deviceService.getDevice(osNode.intgBridge()));
- });
- });
+ portNamePrefixMap().values().forEach(portNamePrefix ->
+ deviceService.getPorts(osNode.intgBridge()).stream()
+ .filter(port -> port.annotations().value(PORT_NAME)
+ .startsWith(portNamePrefix) &&
+ port.isEnabled())
+ .forEach(port -> {
+ log.debug("Instance port {} is detected from {}",
+ port.annotations().value(portNamePrefix),
+ osNode.hostname());
+ processPortAdded(port);
+ }));
Tools.stream(hostService.getHosts())
.filter(host -> deviceService.getPort(
@@ -429,7 +413,7 @@
host.location().port()) == null)
.forEach(host -> {
log.info("Remove stale host {}", host.id());
- hostProvider.hostVanished(host.id());
+ hostProviderService.hostVanished(host.id());
});
}
}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProviderTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProviderTest.java
new file mode 100644
index 0000000..e968d26
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProviderTest.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.openstacknetworking.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.host.HostServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.openstack.networking.domain.NeutronNetwork;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_NETWORK_ID;
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
+
+/**
+ * Unit tests for Openstack Switching Host Provider.
+ */
+public class OpenstackSwitchingHostProviderTest {
+
+ private static final String PORT_ID = "65c0ee9f-d634-4522-8954-51021b570b0d";
+ private static final String NETWORK_ID = "396f12f8-521e-4b91-8e21-2e003500433a";
+ private static final String IP_ADDRESS = "10.10.10.2";
+ private static final String SUBNET_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22";
+ private static final String MAC_ADDRESS = "00:11:22:33:44:55";
+ private static final String MAC_ADDRESS2 = "11:22:33:44:55:66";
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+ private static final DefaultAnnotations ANNOTATIONS =
+ DefaultAnnotations.builder()
+ .set(ANNOTATION_NETWORK_ID, NETWORK_ID)
+ .set(ANNOTATION_PORT_ID, PORT_ID).build();
+
+ // Host Mac, VLAN
+ private static final ProviderId PROVIDER_ID = ProviderId.NONE;
+ private static final MacAddress HOST_MAC = MacAddress.valueOf(MAC_ADDRESS);
+ private static final MacAddress HOST_MAC2 = MacAddress.valueOf(MAC_ADDRESS2);
+
+ private static final VlanId HOST_VLAN_UNTAGGED = VlanId.NONE;
+ private static final HostId HOST_ID_UNTAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_UNTAGGED);
+
+ private static final String SEGMENT_ID = "1";
+
+ // Host IP
+ private static final IpAddress HOST_IP11 = IpAddress.valueOf("10.0.1.1");
+
+ // Device
+ private static final DeviceId DEV_ID1 = DeviceId.deviceId("of:0000000000000001");
+ private static final DeviceId DEV_ID2 = DeviceId.deviceId("of:0000000000000002");
+
+ private static final Device DEV1 =
+ new DefaultDevice(PID, DEV_ID1, Device.Type.SWITCH, "", "", "", "", null);
+ private static final Device DEV2 =
+ new DefaultDevice(PID, DEV_ID2, Device.Type.SWITCH, "", "", "", "", null);
+
+ // Port
+ private static final PortNumber P1 = PortNumber.portNumber(1);
+ private static final PortNumber P2 = PortNumber.portNumber(2);
+
+ // Connect Point
+ private static final ConnectPoint CP11 = new ConnectPoint(DEV_ID1, P1);
+ private static final HostLocation HOST_LOC11 = new HostLocation(CP11, 0);
+ private static final ConnectPoint CP12 = new ConnectPoint(DEV_ID1, P2);
+ private static final HostLocation HOST_LOC12 = new HostLocation(CP12, 0);
+ private static final ConnectPoint CP21 = new ConnectPoint(DEV_ID2, P1);
+
+ private Map<HostId, Host> hostMap = Maps.newHashMap();
+ private Map<ConnectPoint, MacAddress> macMap = Maps.newHashMap();
+
+ private OpenstackSwitchingHostProvider target;
+
+ private HostDescription resultHostDesc;
+ private HostId resultHostId;
+ private HostLocation resultHostLocation;
+
+ /**
+ * Initial setup for this unit test.
+ */
+ @Before
+ public void setUp() {
+ target = new OpenstackSwitchingHostProvider();
+ TestUtils.setField(target, "coreService", new TestCoreService());
+ TestUtils.setField(target, "deviceService", new TestDeviceService());
+ TestUtils.setField(target, "hostService", new TestHostService());
+ TestUtils.setField(target, "mastershipService", new TestMastershipService());
+ TestUtils.setField(target, "osNodeService", new TestOpenstackNodeService());
+ TestUtils.setField(target, "osNetworkService", new TestOpenstackNetworkService());
+ TestUtils.setField(target, "hostProviderRegistry", new TestHostProviderRegistry());
+ TestUtils.setField(target, "executor", MoreExecutors.newDirectExecutorService());
+
+ Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+ Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
+ hostMap.put(HOST_ID_UNTAGGED, host1);
+
+ macMap.put(CP11, HOST_MAC);
+ macMap.put(CP12, HOST_MAC);
+ macMap.put(CP21, HOST_MAC2);
+
+ target.activate();
+ }
+
+ /**
+ * Tears down this unit test.
+ */
+ @After
+ public void tearDown() {
+ target.deactivate();
+ target = null;
+ }
+
+ /**
+ * Tests the process port added method for new addition case.
+ */
+ @Test
+ public void testProcessPortAddedForNewAddition() {
+ org.onosproject.net.Port port = new DefaultPort(DEV2, P1, true, ANNOTATIONS);
+ target.processPortAdded(port);
+
+ HostId hostId = HostId.hostId(HOST_MAC2);
+ HostDescription hostDesc = new DefaultHostDescription(
+ HOST_MAC2,
+ VlanId.NONE,
+ new HostLocation(CP21, System.currentTimeMillis()),
+ ImmutableSet.of(),
+ ANNOTATIONS
+
+ );
+
+ verifyHostResult(hostId, hostDesc);
+ }
+
+ /**
+ * Tests the process port added method for updating case.
+ */
+ @Test
+ public void testProcessPortAddedForUpdate() {
+ org.onosproject.net.Port port = new DefaultPort(DEV1, P1, true, ANNOTATIONS);
+ target.processPortAdded(port);
+
+ HostId hostId = HostId.hostId(HOST_MAC);
+ HostDescription hostDesc = new DefaultHostDescription(
+ HOST_MAC,
+ VlanId.NONE,
+ new HostLocation(CP11, System.currentTimeMillis()),
+ ImmutableSet.of(),
+ ANNOTATIONS
+ );
+
+ verifyHostResult(hostId, hostDesc);
+ }
+
+ /**
+ * Tests the process port added method for migration case.
+ */
+ @Test
+ public void testProcessPortAddedForMigration() {
+ org.onosproject.net.Port port = new DefaultPort(DEV1, P2, true, ANNOTATIONS);
+ target.processPortAdded(port);
+
+ HostId hostId = HostId.hostId(HOST_MAC);
+
+ verifyHostLocationResult(hostId, HOST_LOC12);
+ }
+
+ /**
+ * Mocks the CoreService.
+ */
+ private class TestCoreService extends CoreServiceAdapter {
+
+ @Override
+ public ApplicationId registerApplication(String name) {
+ return new DefaultApplicationId(100, "hostProviderTestApp");
+ }
+ }
+
+ /**
+ * Mocks the DeviceService.
+ */
+ private class TestDeviceService extends DeviceServiceAdapter {
+ }
+
+ /**
+ * Mocks the HostService.
+ */
+ private class TestHostService extends HostServiceAdapter {
+
+ @Override
+ public Host getHost(HostId hostId) {
+ return hostMap.get(hostId);
+ }
+ }
+
+ /**
+ * Mocks the HostProviderService.
+ */
+ private class TestHostProviderService implements HostProviderService {
+
+ @Override
+ public void hostDetected(HostId hostId, HostDescription hostDescription,
+ boolean replaceIps) {
+ resultHostId = hostId;
+ resultHostDesc = hostDescription;
+ }
+
+ @Override
+ public void hostVanished(HostId hostId) {
+
+ }
+
+ @Override
+ public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
+
+ }
+
+ @Override
+ public void removeLocationFromHost(HostId hostId, HostLocation location) {
+
+ }
+
+ @Override
+ public void addLocationToHost(HostId hostId, HostLocation location) {
+ resultHostId = hostId;
+ resultHostLocation = location;
+ }
+
+ @Override
+ public HostProvider provider() {
+ return null;
+ }
+ }
+
+ /**
+ * Mocks the HostProviderRegistry.
+ */
+ private class TestHostProviderRegistry implements HostProviderRegistry {
+
+ @Override
+ public HostProviderService register(HostProvider provider) {
+ return new TestHostProviderService();
+ }
+
+ @Override
+ public void unregister(HostProvider provider) {
+
+ }
+
+ @Override
+ public Set<ProviderId> getProviders() {
+ return null;
+ }
+ }
+
+ /**
+ * Mocks the MastershipService.
+ */
+ private class TestMastershipService extends MastershipServiceAdapter {
+ }
+
+ /**
+ * Mocks the OpenstackNodeService.
+ */
+ private class TestOpenstackNodeService extends OpenstackNodeServiceAdapter {
+ }
+
+ /**
+ * Mocks the OpenstackNetworkService.
+ */
+ private class TestOpenstackNetworkService extends OpenstackNetworkServiceAdapter {
+
+ @Override
+ public Port port(org.onosproject.net.Port port) {
+ Port osPort = NeutronPort.builder()
+ .networkId(NETWORK_ID)
+ .fixedIp(IP_ADDRESS, SUBNET_ID)
+ .macAddress(macMap.get(
+ new ConnectPoint(port.element().id(),
+ port.number())).toString())
+ .build();
+ osPort.setId(PORT_ID);
+
+ return osPort;
+ }
+
+ @Override
+ public Network network(String networkId) {
+ Network osNetwork = NeutronNetwork.builder()
+ .networkType(NetworkType.VXLAN)
+ .segmentId(SEGMENT_ID)
+ .build();
+ osNetwork.setId(NETWORK_ID);
+ return osNetwork;
+ }
+ }
+
+ /**
+ * Verifies the HostId and HostDescription.
+ *
+ * @param hostId host identifier
+ * @param hostDesc host description
+ */
+ private void verifyHostResult(HostId hostId, HostDescription hostDesc) {
+ assertEquals(hostId, resultHostId);
+ assertEquals(hostDesc.hwAddress(), resultHostDesc.hwAddress());
+ assertEquals(hostDesc.annotations().value(NETWORK_ID),
+ resultHostDesc.annotations().value(NETWORK_ID));
+ }
+
+ /**
+ * Verifies the HostId and HostLocation.
+ *
+ * @param hostId host identifier
+ * @param hostLocation host location
+ */
+ private void verifyHostLocationResult(HostId hostId, HostLocation hostLocation) {
+ assertEquals(hostId, resultHostId);
+ assertEquals(hostLocation.deviceId(), resultHostLocation.deviceId());
+ assertEquals(hostLocation.port(), resultHostLocation.port());
+ }
+}