diff --git a/apps/openstacknode/BUCK b/apps/openstacknode/BUCK index c9ad7ac502..e3a14bdbba 100644 --- a/apps/openstacknode/BUCK +++ b/apps/openstacknode/BUCK @@ -7,8 +7,15 @@ COMPILE_DEPS = [ '//core/store/serializers:onos-core-serializers', ] +TEST_DEPS = [ + '//lib:TEST_ADAPTERS', + '//core/api:onos-api-tests', + '//core/common:onos-core-common-tests', +] + osgi_jar_with_tests ( deps = COMPILE_DEPS, + test_deps = TEST_DEPS, ) onos_app ( diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java index 670d4e8b1a..73136670a2 100644 --- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java +++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java @@ -41,7 +41,7 @@ import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE; /** * Representation of a openstack node. */ -public final class DefaultOpenstackNode implements OpenstackNode { +public class DefaultOpenstackNode implements OpenstackNode { private final String hostname; private final NodeType type; @@ -52,7 +52,7 @@ public final class DefaultOpenstackNode implements OpenstackNode { private final String vlanIntf; private final NodeState state; - private DefaultOpenstackNode(String hostname, + protected DefaultOpenstackNode(String hostname, NodeType type, DeviceId intgBridge, DeviceId routerBridge, @@ -254,6 +254,7 @@ public final class DefaultOpenstackNode implements OpenstackNode { public static Builder from(OpenstackNode osNode) { return new Builder() .hostname(osNode.hostname()) + .type(osNode.type()) .intgBridge(osNode.intgBridge()) .routerBridge(osNode.routerBridge()) .managementIp(osNode.managementIp()) diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java index c0d2c3cd7b..9c06445dc1 100644 --- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java +++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java @@ -34,7 +34,6 @@ import org.onosproject.cluster.LeadershipService; import org.onosproject.cluster.NodeId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; -import org.onosproject.core.GroupId; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Port; @@ -492,7 +491,7 @@ public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler { !device.is(BridgeConfig.class)) { return false; } - BridgeConfig bridgeConfig = device.as(BridgeConfig.class); + BridgeConfig bridgeConfig = device.as(BridgeConfig.class); return bridgeConfig.getBridges().stream() .anyMatch(bridge -> bridge.name().equals(bridgeName)); } @@ -742,22 +741,17 @@ public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler { public void event(GroupEvent event) { switch (event.type()) { case GROUP_ADDED: - log.trace("Group added, ID:{} state:{}", event.subject().id(), - event.subject().state()); eventExecutor.execute(() -> { - OpenstackNode osNode = osNodeByGroupId(event.subject().id()); - if (osNode != null && osNode.state() == PORT_CREATED) { - setState(osNode, COMPLETE); - } + log.trace("Group added, ID:{} state:{}", event.subject().id(), + event.subject().state()); + processGroup(event.subject()); }); break; case GROUP_UPDATED: - log.trace("Group updated, ID:{} state:{}", event.subject().id(), - event.subject().state()); eventExecutor.execute(() -> { - osNodeService.nodes(GATEWAY).stream() - .filter(osNode -> osNode.state() == PORT_CREATED) - .forEach(osNode -> bootstrapNode(osNode)); + log.trace("Group updated, ID:{} state:{}", event.subject().id(), + event.subject().state()); + processGroup(event.subject()); }); break; case GROUP_REMOVED: @@ -768,11 +762,17 @@ public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler { } } - private OpenstackNode osNodeByGroupId(GroupId groupId) { - return osNodeService.nodes().stream() - .filter(n -> n.gatewayGroupId(VXLAN).equals(groupId) || - n.gatewayGroupId(VLAN).equals(groupId)) + private void processGroup(Group group) { + OpenstackNode osNode = osNodeService.nodes().stream() + .filter(n -> n.gatewayGroupId(VXLAN).equals(group.id()) || + n.gatewayGroupId(VLAN).equals(group.id())) .findAny().orElse(null); + if (osNode != null && osNode.state() == PORT_CREATED) { + bootstrapNode(osNode); + } + osNodeService.nodes(GATEWAY).stream() + .filter(gNode -> gNode.state() == PORT_CREATED) + .forEach(DefaultOpenstackNodeHandler.this::bootstrapNode); } } diff --git a/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java new file mode 100644 index 0000000000..aadec13a6a --- /dev/null +++ b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java @@ -0,0 +1,1062 @@ +/* + * Copyright 2017-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.openstacknode.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +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.ChassisId; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.cfg.ComponentConfigAdapter; +import org.onosproject.cluster.ClusterServiceAdapter; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.LeadershipServiceAdapter; +import org.onosproject.cluster.NodeId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreServiceAdapter; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.BridgeConfig; +import org.onosproject.net.behaviour.BridgeDescription; +import org.onosproject.net.behaviour.BridgeName; +import org.onosproject.net.behaviour.ControllerInfo; +import org.onosproject.net.behaviour.DefaultBridgeDescription; +import org.onosproject.net.behaviour.ExtensionTreatmentResolver; +import org.onosproject.net.behaviour.InterfaceConfig; +import org.onosproject.net.behaviour.PatchDescription; +import org.onosproject.net.behaviour.TunnelDescription; +import org.onosproject.net.device.DefaultPortDescription; +import org.onosproject.net.device.DeviceAdminService; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceInterfaceDescription; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceServiceAdapter; +import org.onosproject.net.device.PortDescription; +import org.onosproject.net.driver.Behaviour; +import org.onosproject.net.driver.DriverData; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.flow.instructions.ExtensionPropertyException; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; +import org.onosproject.net.group.DefaultGroup; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupListener; +import org.onosproject.net.group.GroupService; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.openstacknode.api.NodeState; +import org.onosproject.openstacknode.api.OpenstackNode; +import org.onosproject.openstacknode.api.OpenstackNodeAdminService; +import org.onosproject.openstacknode.api.OpenstackNodeListener; +import org.onosproject.openstacknode.api.OpenstackNodeService; +import org.onosproject.ovsdb.controller.OvsdbClientService; +import org.onosproject.ovsdb.controller.OvsdbController; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.AnnotationKeys.PORT_NAME; +import static org.onosproject.net.Device.Type.CONTROLLER; +import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.onosproject.openstacknode.api.Constants.*; +import static org.onosproject.openstacknode.api.NodeState.*; +import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE; +import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY; + +/** + * Unit test for DefaultOpenstackNodeHandler. + */ +public class DefaultOpenstackNodeHandlerTest { + + private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test"); + private static final String ERR_STATE_NOT_MATCH = "Node state did not match"; + private static final NodeId LOCAL_NODE_ID = new NodeId("local"); + private static final ControllerNode LOCAL_CTRL = + new DefaultControllerNode(LOCAL_NODE_ID, IpAddress.valueOf("127.0.0.1")); + + private static final BridgeDescription ROUT_BRIDGE = DefaultBridgeDescription.builder() + .name(ROUTER_BRIDGE) + .failMode(BridgeDescription.FailMode.SECURE) + .disableInBand() + .build(); + + private static final PortDescription PATCH_ROUT = new DefaultPortDescription( + PortNumber.portNumber(1), + true, + DefaultAnnotations.builder() + .set(PORT_NAME, PATCH_ROUT_BRIDGE) + .build() + ); + + private static final String COMPUTE_1_HOSTNAME = "compute_1"; + private static final String COMPUTE_2_HOSTNAME = "compute_2"; + private static final String COMPUTE_3_HOSTNAME = "compute_3"; + private static final String COMPUTE_4_HOSTNAME = "compute_4"; + private static final String GATEWAY_1_HOSTNAME = "gateway_1"; + private static final String GATEWAY_2_HOSTNAME = "gateway_2"; + private static final String GATEWAY_3_HOSTNAME = "gateway_3"; + private static final String GATEWAY_4_HOSTNAME = "gateway_4"; + + private static final IpAddress COMPUTE_1_IP = IpAddress.valueOf("10.100.0.1"); + private static final IpAddress COMPUTE_2_IP = IpAddress.valueOf("10.100.0.2"); + private static final IpAddress COMPUTE_3_IP = IpAddress.valueOf("10.100.0.3"); + private static final IpAddress COMPUTE_4_IP = IpAddress.valueOf("10.100.0.4"); + private static final IpAddress GATEWAY_1_IP = IpAddress.valueOf("10.100.0.5"); + private static final IpAddress GATEWAY_2_IP = IpAddress.valueOf("10.100.0.6"); + private static final IpAddress GATEWAY_3_IP = IpAddress.valueOf("10.100.0.7"); + private static final IpAddress GATEWAY_4_IP = IpAddress.valueOf("10.100.0.8"); + + private static final Device COMPUTE_1_INTG_DEVICE = createOpenFlowDevice(1, INTEGRATION_BRIDGE); + private static final Device COMPUTE_2_INTG_DEVICE = createOpenFlowDevice(2, INTEGRATION_BRIDGE); + private static final Device COMPUTE_3_INTG_DEVICE = createOpenFlowDevice(3, INTEGRATION_BRIDGE); + private static final Device COMPUTE_4_INTG_DEVICE = createOpenFlowDevice(4, INTEGRATION_BRIDGE); + private static final Device GATEWAY_1_INTG_DEVICE = createOpenFlowDevice(5, INTEGRATION_BRIDGE); + private static final Device GATEWAY_1_ROUT_DEVICE = createOpenFlowDevice(6, ROUTER_BRIDGE); + private static final Device GATEWAY_2_INTG_DEVICE = createOpenFlowDevice(7, INTEGRATION_BRIDGE); + private static final Device GATEWAY_2_ROUT_DEVICE = createOpenFlowDevice(8, ROUTER_BRIDGE); + private static final Device GATEWAY_3_INTG_DEVICE = createOpenFlowDevice(9, INTEGRATION_BRIDGE); + private static final Device GATEWAY_3_ROUT_DEVICE = createOpenFlowDevice(10, ROUTER_BRIDGE); + private static final Device GATEWAY_4_INTG_DEVICE = createOpenFlowDevice(11, INTEGRATION_BRIDGE); + private static final Device GATEWAY_4_ROUT_DEVICE = createOpenFlowDevice(12, ROUTER_BRIDGE); + + private static final Device COMPUTE_1_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_1_IP); + private static final Device COMPUTE_2_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_2_IP); + private static final Device COMPUTE_3_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_3_IP); + private static final Device COMPUTE_4_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_4_IP); + private static final Device GATEWAY_1_OVSDB_DEVICE = createOvsdbDevice(GATEWAY_1_IP); + private static final Device GATEWAY_2_OVSDB_DEVICE = createOvsdbDevice(GATEWAY_2_IP); + + private static final OpenstackNode COMPUTE_1 = createNode( + COMPUTE_1_HOSTNAME, + COMPUTE, + COMPUTE_1_INTG_DEVICE, + COMPUTE_1_IP, + INIT + ); + + private static final OpenstackNode COMPUTE_2 = createNode( + COMPUTE_2_HOSTNAME, + COMPUTE, + COMPUTE_2_INTG_DEVICE, + COMPUTE_2_IP, + DEVICE_CREATED + ); + + private static final OpenstackNode COMPUTE_3 = createNode( + COMPUTE_3_HOSTNAME, + COMPUTE, + COMPUTE_3_INTG_DEVICE, + COMPUTE_3_IP, + PORT_CREATED + ); + + private static final OpenstackNode COMPUTE_4 = createNode( + COMPUTE_4_HOSTNAME, + COMPUTE, + COMPUTE_4_INTG_DEVICE, + COMPUTE_4_IP, + COMPLETE + ); + + private static final OpenstackNode GATEWAY_1 = createNode( + GATEWAY_1_HOSTNAME, + GATEWAY, + GATEWAY_1_INTG_DEVICE, + GATEWAY_1_ROUT_DEVICE, + GATEWAY_1_IP, + INIT + ); + + private static final OpenstackNode GATEWAY_2 = createNode( + GATEWAY_2_HOSTNAME, + GATEWAY, + GATEWAY_2_INTG_DEVICE, + GATEWAY_2_ROUT_DEVICE, + GATEWAY_2_IP, + DEVICE_CREATED + ); + + private static final OpenstackNode GATEWAY_3 = createNode( + GATEWAY_3_HOSTNAME, + GATEWAY, + GATEWAY_3_INTG_DEVICE, + GATEWAY_3_ROUT_DEVICE, + GATEWAY_3_IP, + PORT_CREATED + ); + + private static final OpenstackNode GATEWAY_4 = createNode( + GATEWAY_4_HOSTNAME, + GATEWAY, + GATEWAY_4_INTG_DEVICE, + GATEWAY_4_ROUT_DEVICE, + GATEWAY_4_IP, + COMPLETE + ); + + private static final TestDeviceService TEST_DEVICE_SERVICE = new TestDeviceService(); + + private TestOpenstackNodeManager testNodeManager; + private DefaultOpenstackNodeHandler target; + + @Before + public void setUp() throws Exception { + DeviceAdminService mockDeviceAdminService = createMock(DeviceAdminService.class); + mockDeviceAdminService.removeDevice(anyObject()); + replay(mockDeviceAdminService); + + OvsdbClientService mockOvsdbClient = createMock(OvsdbClientService.class); + expect(mockOvsdbClient.isConnected()) + .andReturn(true) + .anyTimes(); + replay(mockOvsdbClient); + + OvsdbController mockOvsdbController = createMock(OvsdbController.class); + expect(mockOvsdbController.getOvsdbClient(anyObject())) + .andReturn(mockOvsdbClient) + .anyTimes(); + replay(mockOvsdbController); + + testNodeManager = new TestOpenstackNodeManager(); + target = new DefaultOpenstackNodeHandler(); + + target.coreService = new TestCoreService(); + target.leadershipService = new TestLeadershipService(); + target.clusterService = new TestClusterService(); + target.deviceService = TEST_DEVICE_SERVICE; + target.deviceAdminService = mockDeviceAdminService; + target.ovsdbController = mockOvsdbController; + target.groupService = new TestGroupService(); + target.osNodeService = testNodeManager; + target.osNodeAdminService = testNodeManager; + target.componentConfigService = new TestComponentConfigService(); + TestUtils.setField(target, "eventExecutor", MoreExecutors.newDirectExecutorService()); + target.activate(); + } + + @After + public void tearDown() { + TEST_DEVICE_SERVICE.clear(); + target.deactivate(); + target = null; + testNodeManager = null; + } + + /** + * Checks if the compute node state changes from INIT to DEVICE_CREATED + * after processing INIT state. + */ + @Test + public void testComputeNodeProcessNodeInitState() { + testNodeManager.createNode(COMPUTE_1); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_1_OVSDB_DEVICE.id(), COMPUTE_1_OVSDB_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, INIT, + testNodeManager.node(COMPUTE_1_HOSTNAME).state()); + target.processInitState(COMPUTE_1); + assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED, + testNodeManager.node(COMPUTE_1_HOSTNAME).state()); + } + + /** + * Checks if the gateway node state changes from INIT to DEVICE_CREATED + * after processing INIT state. + */ + @Test + public void testGatewayNodeProcessNodeInitState() { + testNodeManager.createNode(GATEWAY_1); + TEST_DEVICE_SERVICE.devMap.put(GATEWAY_1_OVSDB_DEVICE.id(), GATEWAY_1_OVSDB_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, INIT, + testNodeManager.node(GATEWAY_1_HOSTNAME).state()); + target.processInitState(GATEWAY_1); + assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED, + testNodeManager.node(GATEWAY_1_HOSTNAME).state()); + } + + /** + * Checks if the compute node state changes from DEVICE_CREATED to + * PORT_CREATED after processing DEVICE_CREATED state. + */ + @Test + public void testComputeNodeProcessDeviceCreatedState() { + testNodeManager.createNode(COMPUTE_2); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_2_OVSDB_DEVICE.id(), COMPUTE_2_OVSDB_DEVICE); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_2_INTG_DEVICE.id(), COMPUTE_2_INTG_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED, + testNodeManager.node(COMPUTE_2_HOSTNAME).state()); + target.processDeviceCreatedState(COMPUTE_2); + assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED, + testNodeManager.node(COMPUTE_2_HOSTNAME).state()); + } + + /** + * Checks if the gateway node state changes from DEVICE_CREATED to + * PORT_CREATED after processing DEVICE_CREATED state. + */ + @Test + public void testGatewayNodeProcessDeviceCreatedState() { + testNodeManager.createNode(GATEWAY_2); + TEST_DEVICE_SERVICE.devMap.put(GATEWAY_2_OVSDB_DEVICE.id(), GATEWAY_2_OVSDB_DEVICE); + TEST_DEVICE_SERVICE.devMap.put(GATEWAY_2_INTG_DEVICE.id(), GATEWAY_2_INTG_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED, + testNodeManager.node(GATEWAY_2_HOSTNAME).state()); + target.processDeviceCreatedState(GATEWAY_2); + assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED, + testNodeManager.node(GATEWAY_2_HOSTNAME).state()); + } + + /** + * Checks if the compute node state changes from PORT_CREATED to + * COMPLETE after processing PORT_CREATED state. + */ + @Test + public void testComputeNodeProcessPortCreatedState() { + testNodeManager.createNode(COMPUTE_3); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_3_OVSDB_DEVICE.id(), COMPUTE_3_OVSDB_DEVICE); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_3_INTG_DEVICE.id(), COMPUTE_3_INTG_DEVICE); + TEST_DEVICE_SERVICE.portList.add(createPort(COMPUTE_3_INTG_DEVICE, DEFAULT_TUNNEL)); + + testNodeManager.createNode(GATEWAY_4); + TEST_DEVICE_SERVICE.devMap.put(GATEWAY_4_INTG_DEVICE.id(), GATEWAY_4_INTG_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED, + testNodeManager.node(COMPUTE_3_HOSTNAME).state()); + target.processPortCreatedState(COMPUTE_3); + assertEquals(ERR_STATE_NOT_MATCH, COMPLETE, + testNodeManager.node(COMPUTE_3_HOSTNAME).state()); + } + + /** + * Checks if the gateway node state changes from PORT_CREATED to + * COMPLETE after processing PORT_CREATED state. + */ + @Test + public void testGatewayNodeProcessPortCreatedState() { + testNodeManager.createNode(COMPUTE_4); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_4_OVSDB_DEVICE.id(), COMPUTE_4_OVSDB_DEVICE); + TEST_DEVICE_SERVICE.devMap.put(COMPUTE_4_INTG_DEVICE.id(), COMPUTE_4_INTG_DEVICE); + TEST_DEVICE_SERVICE.portList.add(createPort(COMPUTE_4_INTG_DEVICE, DEFAULT_TUNNEL)); + + testNodeManager.createNode(GATEWAY_3); + TEST_DEVICE_SERVICE.devMap.put(GATEWAY_3_INTG_DEVICE.id(), GATEWAY_4_INTG_DEVICE); + + assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED, + testNodeManager.node(GATEWAY_3_HOSTNAME).state()); + target.processPortCreatedState(GATEWAY_3); + assertEquals(ERR_STATE_NOT_MATCH, COMPLETE, + testNodeManager.node(GATEWAY_3_HOSTNAME).state()); + } + + /** + * Checks if the compute node state changes from COMPLETE to INCOMPLETE + * when integration bridge is disconnected. + */ + @Test + public void testBackToIncompleteWhenBrIntDisconnected() { + testNodeManager.createNode(COMPUTE_4); + + assertEquals(ERR_STATE_NOT_MATCH, COMPLETE, + testNodeManager.node(COMPUTE_4_HOSTNAME).state()); + TEST_DEVICE_SERVICE.removeDevice(COMPUTE_4_INTG_DEVICE); + assertEquals(ERR_STATE_NOT_MATCH, INCOMPLETE, + testNodeManager.node(COMPUTE_4_HOSTNAME).state()); + } + + /** + * Checks if the compute node state changes from COMPLETE to INCOMPLETE + * when vxlan port is removed from integration bridge. + */ + @Test + public void testBackToIncompleteWhenVxlanRemoved() { + testNodeManager.createNode(COMPUTE_4); + + assertEquals(ERR_STATE_NOT_MATCH, COMPLETE, + testNodeManager.node(COMPUTE_4_HOSTNAME).state()); + TEST_DEVICE_SERVICE.removePort(COMPUTE_4_INTG_DEVICE, createPort( + COMPUTE_4_INTG_DEVICE, DEFAULT_TUNNEL)); + assertEquals(ERR_STATE_NOT_MATCH, INCOMPLETE, + testNodeManager.node(COMPUTE_4_HOSTNAME).state()); + + } + + private static Device createOvsdbDevice(IpAddress ovsdbIp) { + return new TestDevice(new ProviderId("of", "foo"), + DeviceId.deviceId("ovsdb:" + ovsdbIp.toString()), + CONTROLLER, + "manufacturer", + "hwVersion", + "swVersion", + "serialNumber", + new ChassisId(1)); + } + + private static Device createOpenFlowDevice(long devIdNum, String type) { + return new TestDevice(new ProviderId("of", "foo"), + DeviceId.deviceId(String.format("of:%016d", devIdNum)), + SWITCH, + type, + "hwVersion", + "swVersion", + "serialNumber", + new ChassisId(1)); + } + + private static Port createPort(Device device, String portName) { + return new DefaultPort(device, + PortNumber.portNumber(1), + true, + DefaultAnnotations.builder().set(PORT_NAME, portName).build()); + } + + private static OpenstackNode createNode(String hostname, + OpenstackNode.NodeType type, + Device intgBridge, + IpAddress ipAddr, + NodeState state) { + return new TestOpenstackNode( + hostname, + type, + intgBridge.id(), + null, + ipAddr, + ipAddr, + null, state); + } + + private static OpenstackNode createNode(String hostname, + OpenstackNode.NodeType type, + Device intgBridge, + Device routerBridge, + IpAddress ipAddr, + NodeState state) { + return new TestOpenstackNode( + hostname, + type, + intgBridge.id(), + routerBridge.id(), + ipAddr, + ipAddr, + null, state); + } + + private static final class TestDevice extends DefaultDevice { + private TestDevice(ProviderId providerId, + DeviceId id, + Type type, + String manufacturer, + String hwVersion, + String swVersion, + String serialNumber, + ChassisId chassisId, + Annotations... annotations) { + super(providerId, + id, + type, + manufacturer, + hwVersion, + swVersion, + serialNumber, + chassisId, + annotations); + } + + @Override + @SuppressWarnings("unchecked") + public B as(Class projectionClass) { + if (projectionClass.equals(BridgeConfig.class)) { + return (B) new TestBridgeConfig(); + } else if (projectionClass.equals(InterfaceConfig.class)) { + return (B) new TestInterfaceConfig(); + } else if (projectionClass.equals(ExtensionTreatmentResolver.class)) { + ExtensionTreatmentResolver treatmentResolver = createMock(ExtensionTreatmentResolver.class); + expect(treatmentResolver.getExtensionInstruction(anyObject())) + .andReturn(new TestExtensionTreatment()) + .anyTimes(); + replay(treatmentResolver); + return (B) treatmentResolver; + } else { + return null; + } + } + + @Override + public boolean is(Class projectionClass) { + return true; + } + } + + private static final class TestOpenstackNode extends DefaultOpenstackNode { + private TestOpenstackNode(String hostname, + NodeType type, + DeviceId intgBridge, + DeviceId routerBridge, + IpAddress managementIp, + IpAddress dataIp, + String vlanIntf, + NodeState state) { + super(hostname, + type, + intgBridge, + routerBridge, + managementIp, + dataIp, + vlanIntf, + state); + } + + @Override + public PortNumber tunnelPortNum() { + return PortNumber.portNumber(1); + } + + @Override + public PortNumber vlanPortNum() { + return PortNumber.portNumber(1); + } + + @Override + public PortNumber patchPortNum() { + return PortNumber.portNumber(1); + } + + @Override + public MacAddress vlanPortMac() { + return MacAddress.NONE; + } + } + + private static class TestOpenstackNodeManager implements OpenstackNodeService, OpenstackNodeAdminService { + Map osNodeMap = Maps.newHashMap(); + List listeners = Lists.newArrayList(); + + @Override + public Set nodes() { + return ImmutableSet.copyOf(osNodeMap.values()); + } + + @Override + public Set nodes(OpenstackNode.NodeType type) { + return osNodeMap.values().stream() + .filter(osNode -> osNode.type() == type) + .collect(Collectors.toSet()); + } + + @Override + public Set completeNodes() { + return osNodeMap.values().stream() + .filter(osNode -> osNode.state() == COMPLETE) + .collect(Collectors.toSet()); + } + + @Override + public Set completeNodes(OpenstackNode.NodeType type) { + return osNodeMap.values().stream() + .filter(osNode -> osNode.type() == type && osNode.state() == COMPLETE) + .collect(Collectors.toSet()); + } + + @Override + public OpenstackNode node(String hostname) { + return osNodeMap.get(hostname); + } + + @Override + public OpenstackNode node(DeviceId deviceId) { + return osNodeMap.values().stream() + .filter(osNode -> Objects.equals(osNode.intgBridge(), deviceId) || + Objects.equals(osNode.ovsdb(), deviceId) || + Objects.equals(osNode.routerBridge(), deviceId)) + .findFirst().orElse(null); + } + + @Override + public void addListener(OpenstackNodeListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(OpenstackNodeListener listener) { + listeners.remove(listener); + } + + @Override + public void createNode(OpenstackNode osNode) { + osNodeMap.put(osNode.hostname(), osNode); + } + + @Override + public void updateNode(OpenstackNode osNode) { + osNodeMap.put(osNode.hostname(), osNode); + } + + @Override + public OpenstackNode removeNode(String hostname) { + return null; + } + } + + private static class TestDeviceService extends DeviceServiceAdapter { + Map devMap = Maps.newHashMap(); + List portList = Lists.newArrayList(); + List listeners = Lists.newArrayList(); + + @Override + public void addListener(DeviceListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(DeviceListener listener) { + listeners.remove(listener); + } + + @Override + public Device getDevice(DeviceId deviceId) { + return devMap.get(deviceId); + } + + @Override + public List getPorts(DeviceId deviceId) { + return this.portList.stream() + .filter(p -> p.element().id().equals(deviceId)) + .collect(Collectors.toList()); + } + + @Override + public boolean isAvailable(DeviceId deviceId) { + return devMap.containsKey(deviceId); + } + + void addDevice(Device device) { + devMap.put(device.id(), device); + DeviceEvent event = new DeviceEvent(DEVICE_ADDED, device); + listeners.stream().filter(l -> l.isRelevant(event)).forEach(l -> l.event(event)); + } + + void removeDevice(Device device) { + devMap.remove(device.id()); + DeviceEvent event = new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device); + listeners.stream().filter(l -> l.isRelevant(event)).forEach(l -> l.event(event)); + } + + void addPort(Device device, Port port) { + portList.add(port); + DeviceEvent event = new DeviceEvent(PORT_ADDED, device, port); + listeners.stream().filter(l -> l.isRelevant(event)).forEach(l -> l.event(event)); + } + + void removePort(Device device, Port port) { + portList.remove(port); + DeviceEvent event = new DeviceEvent(PORT_REMOVED, device, port); + listeners.stream().filter(l -> l.isRelevant(event)).forEach(l -> l.event(event)); + } + + void clear() { + this.listeners.clear(); + this.devMap.clear(); + this.portList.clear(); + } + } + + private static class TestBridgeConfig implements BridgeConfig { + + @Override + public DriverData data() { + return null; + } + + @Override + public void setData(DriverData data) { + + } + + @Override + public DriverHandler handler() { + return null; + } + + @Override + public void setHandler(DriverHandler handler) { + + } + + @Override + public void addBridge(BridgeName bridgeName) { + + } + + @Override + public void addBridge(BridgeName bridgeName, String dpid, String exPortName) { + + } + + @Override + public boolean addBridge(BridgeName bridgeName, String dpid, List controllers) { + return false; + } + + @Override + public boolean addBridge(BridgeDescription bridge) { + TEST_DEVICE_SERVICE.addDevice(new DefaultDevice(new ProviderId("of", "foo"), + DeviceId.deviceId("of:" + bridge.datapathId().get()), + SWITCH, + bridge.name(), + "hwVersion", + "swVersion", + "serialNumber", + new ChassisId(1))); + return true; + } + + @Override + public void deleteBridge(BridgeName bridgeName) { + + } + + @Override + public Collection getBridges() { + return ImmutableSet.of(ROUT_BRIDGE); + } + + @Override + public void addPort(BridgeName bridgeName, String portName) { + + } + + @Override + public void deletePort(BridgeName bridgeName, String portName) { + + } + + @Override + public Collection getPorts() { + return ImmutableSet.of(PATCH_ROUT); + } + + @Override + public Set getPortNumbers() { + return null; + } + + @Override + public List getLocalPorts(Iterable ifaceIds) { + return null; + } + } + + private static class TestInterfaceConfig implements InterfaceConfig { + + @Override + public DriverData data() { + return null; + } + + @Override + public void setData(DriverData data) { + + } + + @Override + public DriverHandler handler() { + return null; + } + + @Override + public void setHandler(DriverHandler handler) { + + } + + @Override + public boolean addAccessInterface(DeviceId deviceId, String intf, VlanId vlanId) { + return false; + } + + @Override + public boolean addAccessMode(String intf, VlanId vlanId) { + return false; + } + + @Override + public boolean removeAccessInterface(DeviceId deviceId, String intf) { + return false; + } + + @Override + public boolean removeAccessMode(String intf) { + return false; + } + + @Override + public boolean addTrunkInterface(DeviceId deviceId, String intf, List vlanIds) { + return false; + } + + @Override + public boolean addTrunkMode(String intf, List vlanIds) { + return false; + } + + @Override + public boolean removeTrunkInterface(DeviceId deviceId, String intf) { + return false; + } + + @Override + public boolean removeTrunkMode(String intf) { + return false; + } + + @Override + public boolean addRateLimit(String intf, short limit) { + return false; + } + + @Override + public boolean removeRateLimit(String intf) { + return false; + } + + @Override + public boolean addTunnelMode(String intf, TunnelDescription tunnelDesc) { + TEST_DEVICE_SERVICE.devMap.values().stream() + .filter(device -> device.type() == SWITCH && + device.manufacturer().equals(INTEGRATION_BRIDGE)) + .forEach(device -> { + TEST_DEVICE_SERVICE.addPort(device, createPort(device, intf)); + }); + return true; + } + + @Override + public boolean removeTunnelMode(String intf) { + return false; + } + + @Override + public boolean addPatchMode(String ifaceName, PatchDescription patchInterface) { + if (ifaceName.equals(PATCH_INTG_BRIDGE)) { + TEST_DEVICE_SERVICE.devMap.values().stream() + .filter(device -> device.type() == SWITCH && + device.manufacturer().equals(INTEGRATION_BRIDGE)) + .forEach(device -> { + TEST_DEVICE_SERVICE.addPort(device, createPort(device, ifaceName)); + }); + } else if (ifaceName.equals(PATCH_ROUT_BRIDGE)) { + TEST_DEVICE_SERVICE.devMap.values().stream() + .filter(device -> device.type() == SWITCH && + device.manufacturer().equals(ROUTER_BRIDGE)) + .forEach(device -> { + TEST_DEVICE_SERVICE.addPort(device, createPort(device, ifaceName)); + }); + } + return true; + } + + @Override + public boolean removePatchMode(String ifaceName) { + return false; + } + + @Override + public List getInterfaces(DeviceId deviceId) { + return null; + } + + @Override + public List getInterfaces() { + return null; + } + } + + private static class TestGroupService implements GroupService { + Map groupMap = Maps.newHashMap(); + Map groupBucketsMap = Maps.newHashMap(); + List listeners = Lists.newArrayList(); + + @Override + public void addListener(GroupListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(GroupListener listener) { + listeners.remove(listener); + } + + @Override + public void addGroup(GroupDescription groupDesc) { + DefaultGroup group = new DefaultGroup(GroupId.valueOf(groupDesc.givenGroupId()), groupDesc); + group.setState(Group.GroupState.ADDED); + groupMap.put(groupDesc.appCookie(), group); + groupBucketsMap.put(groupDesc.appCookie(), groupDesc.buckets()); + + GroupEvent event = new GroupEvent(GroupEvent.Type.GROUP_ADDED, group); + listeners.stream().filter(listener -> listener.isRelevant(event)) + .forEach(listener -> listener.event(event)); + } + + @Override + public Group getGroup(DeviceId deviceId, GroupKey appCookie) { + return groupMap.get(appCookie); + } + + @Override + public void addBucketsToGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets, + GroupKey newCookie, ApplicationId appId) { + + } + + @Override + public void removeBucketsFromGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets, + GroupKey newCookie, ApplicationId appId) { + + } + + @Override + public void purgeGroupEntries(DeviceId deviceId) { + + } + + @Override + public void removeGroup(DeviceId deviceId, GroupKey appCookie, ApplicationId appId) { + + } + + @Override + public Iterable getGroups(DeviceId deviceId, ApplicationId appId) { + return null; + } + + @Override + public Iterable getGroups(DeviceId deviceId) { + return null; + } + + @Override + public void setBucketsForGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets, + GroupKey newCookie, ApplicationId appId) { + groupBucketsMap.put(newCookie, buckets); + GroupEvent event = new GroupEvent(GroupEvent.Type.GROUP_UPDATED, groupMap.get(newCookie)); + listeners.stream().filter(listener -> listener.isRelevant(event)) + .forEach(listener -> listener.event(event)); + } + + } + + private static class TestExtensionTreatment implements ExtensionTreatment { + Ip4Address tunnelDst; + + @Override + public ExtensionTreatmentType type() { + return null; + } + + @Override + public void setPropertyValue(String key, T value) throws ExtensionPropertyException { + tunnelDst = (Ip4Address) value; + } + + @Override + public T getPropertyValue(String key) throws ExtensionPropertyException { + return null; + } + + @Override + public List getProperties() { + return null; + } + + @Override + public byte[] serialize() { + return new byte[0]; + } + + @Override + public void deserialize(byte[] data) { + + } + + @Override + public boolean equals(Object obj) { + TestExtensionTreatment that = (TestExtensionTreatment) obj; + return Objects.equals(tunnelDst, that.tunnelDst); + } + + @Override + public int hashCode() { + return Objects.hash(tunnelDst); + } + } + + private static class TestCoreService extends CoreServiceAdapter { + + @Override + public ApplicationId getAppId(String name) { + return TEST_APP_ID; + } + } + + private static class TestLeadershipService extends LeadershipServiceAdapter { + + @Override + public NodeId getLeader(String path) { + return LOCAL_NODE_ID; + } + } + + private static class TestClusterService extends ClusterServiceAdapter { + + @Override + public ControllerNode getLocalNode() { + return LOCAL_CTRL; + } + } + + private class TestComponentConfigService extends ComponentConfigAdapter { + + } +} diff --git a/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java new file mode 100644 index 0000000000..fdc7028937 --- /dev/null +++ b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java @@ -0,0 +1,152 @@ +/* + * Copyright 2017-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.openstacknode.impl; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.net.Device; +import org.onosproject.openstacknode.api.NodeState; +import org.onosproject.openstacknode.api.OpenstackNode; + +/** + * Unit tests for DefaultOpenstackNode. + */ +public class DefaultOpenstackNodeTest extends OpenstackNodeTest { + + private static final IpAddress TEST_IP = IpAddress.valueOf("10.100.0.3"); + + private static final String HOSTNAME_1 = "hostname_1"; + private static final String HOSTNAME_2 = "hostname_2"; + private static final Device DEVICE_1 = createDevice(1); + private static final Device DEVICE_2 = createDevice(2); + private static final OpenstackNode OS_NODE_1 = createNode( + HOSTNAME_1, + OpenstackNode.NodeType.COMPUTE, + DEVICE_1, + TEST_IP, + NodeState.INIT); + private static final OpenstackNode OS_NODE_2 = createNode( + HOSTNAME_1, + OpenstackNode.NodeType.COMPUTE, + DEVICE_1, + TEST_IP, + NodeState.COMPLETE); + private static final OpenstackNode OS_NODE_3 = createNode( + HOSTNAME_2, + OpenstackNode.NodeType.COMPUTE, + DEVICE_2, + TEST_IP, + NodeState.INIT); + + /** + * Checks equals method works as expected. + */ + @Test + public void testEquality() { + new EqualsTester().addEqualityGroup(OS_NODE_1, OS_NODE_2) + .addEqualityGroup(OS_NODE_3) + .testEquals(); + } + + /** + * Checks building a node without hostname fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testBuildWithoutHostname() { + DefaultOpenstackNode.builder() + .type(OpenstackNode.NodeType.COMPUTE) + .intgBridge(DEVICE_1.id()) + .managementIp(TEST_IP) + .dataIp(TEST_IP) + .state(NodeState.INIT) + .build(); + } + + /** + * Checks building a node without type fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testBuildWithoutType() { + DefaultOpenstackNode.builder() + .hostname(HOSTNAME_1) + .intgBridge(DEVICE_1.id()) + .managementIp(TEST_IP) + .dataIp(TEST_IP) + .state(NodeState.INIT) + .build(); + } + + /** + * Checks building a node without integration bridge ID fails with + * proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testBuildWithoutIntegrationBridgeId() { + DefaultOpenstackNode.builder() + .hostname(HOSTNAME_1) + .type(OpenstackNode.NodeType.COMPUTE) + .managementIp(TEST_IP) + .dataIp(TEST_IP) + .state(NodeState.INIT) + .build(); + } + + /** + * Checks building a node without management IP address fails with + * proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testBuildWithoutManagementIp() { + DefaultOpenstackNode.builder() + .hostname(HOSTNAME_1) + .type(OpenstackNode.NodeType.COMPUTE) + .intgBridge(DEVICE_1.id()) + .dataIp(TEST_IP) + .state(NodeState.INIT) + .build(); + } + + /** + * Checks building a node without data IP nor VLAN interface name + * fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testBuildWithoutDataIpNorVlanIntf() { + DefaultOpenstackNode.builder() + .hostname(HOSTNAME_1) + .type(OpenstackNode.NodeType.COMPUTE) + .intgBridge(DEVICE_1.id()) + .state(NodeState.INIT) + .build(); + } + + /** + * Checks building a gateway type node without router bridge ID + * fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testGatewayWithoutRouterBridgeId() { + DefaultOpenstackNode.builder() + .hostname(HOSTNAME_1) + .type(OpenstackNode.NodeType.GATEWAY) + .intgBridge(DEVICE_1.id()) + .managementIp(TEST_IP) + .dataIp(TEST_IP) + .state(NodeState.INIT) + .build(); + } +} diff --git a/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java new file mode 100644 index 0000000000..6dd481d26e --- /dev/null +++ b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java @@ -0,0 +1,331 @@ +/* + * Copyright 2017-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.openstacknode.impl; + +import com.google.common.collect.Lists; +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.onosproject.cluster.ClusterServiceAdapter; +import org.onosproject.cluster.LeadershipServiceAdapter; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreServiceAdapter; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.event.Event; +import org.onosproject.net.Device; +import org.onosproject.net.config.NetworkConfigRegistryAdapter; +import org.onosproject.openstacknode.api.NodeState; +import org.onosproject.openstacknode.api.OpenstackNode; +import org.onosproject.openstacknode.api.OpenstackNodeEvent; +import org.onosproject.openstacknode.api.OpenstackNodeListener; +import org.onosproject.store.service.TestStorageService; + +import java.util.List; +import java.util.Objects; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE; +import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY; +import static org.onosproject.openstacknode.api.OpenstackNodeEvent.Type.*; + +/** + * Unit tests for OpenStack node manager. + */ +public class OpenstackNodeManagerTest extends OpenstackNodeTest { + + private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test"); + + private static final String ERR_SIZE = "Number of nodes did not match"; + private static final String ERR_NOT_MATCH = "Node did not match"; + private static final String ERR_NOT_FOUND = "Node did not exist"; + + private static final String COMPUTE_1_HOSTNAME = "compute_1"; + private static final String COMPUTE_2_HOSTNAME = "compute_2"; + private static final String COMPUTE_3_HOSTNAME = "compute_3"; + private static final String GATEWAY_1_HOSTNAME = "gateway_1"; + + private static final Device COMPUTE_1_INTG_DEVICE = createDevice(1); + private static final Device COMPUTE_2_INTG_DEVICE = createDevice(2); + private static final Device COMPUTE_3_INTG_DEVICE = createDevice(3); + private static final Device GATEWAY_1_INTG_DEVICE = createDevice(4); + private static final Device GATEWAY_1_ROUT_DEVICE = createDevice(5); + + private static final OpenstackNode COMPUTE_1 = createNode( + COMPUTE_1_HOSTNAME, + COMPUTE, + COMPUTE_1_INTG_DEVICE, + IpAddress.valueOf("10.100.0.1"), + NodeState.INIT + ); + private static final OpenstackNode COMPUTE_2 = createNode( + COMPUTE_2_HOSTNAME, + COMPUTE, + COMPUTE_2_INTG_DEVICE, + IpAddress.valueOf("10.100.0.2"), + NodeState.INIT + ); + private static final OpenstackNode COMPUTE_3 = createNode( + COMPUTE_3_HOSTNAME, + COMPUTE, + COMPUTE_3_INTG_DEVICE, + IpAddress.valueOf("10.100.0.3"), + NodeState.COMPLETE + ); + private static final OpenstackNode GATEWAY_1 = createNode( + GATEWAY_1_HOSTNAME, + OpenstackNode.NodeType.GATEWAY, + GATEWAY_1_INTG_DEVICE, + GATEWAY_1_ROUT_DEVICE, + IpAddress.valueOf("10.100.0.4"), + NodeState.COMPLETE + ); + + private final TestOpenstackNodeListener testListener = new TestOpenstackNodeListener(); + + private OpenstackNodeManager target; + private DistributedOpenstackNodeStore osNodeStore; + + @Before + public void setUp() { + osNodeStore = new DistributedOpenstackNodeStore(); + TestUtils.setField(osNodeStore, "coreService", new TestCoreService()); + TestUtils.setField(osNodeStore, "storageService", new TestStorageService()); + TestUtils.setField(osNodeStore, "eventExecutor", MoreExecutors.newDirectExecutorService()); + osNodeStore.activate(); + + osNodeStore.createNode(COMPUTE_2); + osNodeStore.createNode(COMPUTE_3); + osNodeStore.createNode(GATEWAY_1); + + target = new OpenstackNodeManager(); + target.coreService = new TestCoreService(); + target.clusterService = new TestClusterService(); + target.leadershipService = new TestLeadershipService(); + target.configRegistry = new TestConfigService(); + target.osNodeStore = osNodeStore; + target.addListener(testListener); + target.activate(); + testListener.events.clear(); + } + + @After + public void tearDown() { + target.removeListener(testListener); + target.deactivate(); + osNodeStore.deactivate(); + osNodeStore = null; + target = null; + } + + /** + * Checks if creating and removing a node work well with proper events. + */ + @Test + public void testCreateAndRemoveNode() { + target.createNode(COMPUTE_1); + assertEquals(ERR_SIZE, 4, target.nodes().size()); + assertTrue(target.node(COMPUTE_1_HOSTNAME) != null); + + target.removeNode(COMPUTE_1_HOSTNAME); + assertEquals(ERR_SIZE, 3, target.nodes().size()); + assertTrue(target.node(COMPUTE_1_HOSTNAME) == null); + + validateEvents(OPENSTACK_NODE_CREATED, OPENSTACK_NODE_REMOVED); + } + + /** + * Checks if creating null node fails with proper exception. + */ + @Test(expected = NullPointerException.class) + public void testCreateNullNode() { + target.createNode(null); + } + + /** + * Checks if creating a duplicated node fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testCreateDuplicateNode() { + target.createNode(COMPUTE_1); + target.createNode(COMPUTE_1); + } + + /** + * Checks if removing null node fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testRemoveNullNode() { + target.removeNode(null); + } + + /** + * Checks if updating a node works well with proper event. + */ + @Test + public void testUpdateNode() { + OpenstackNode updated = DefaultOpenstackNode.from(COMPUTE_2) + .dataIp(IpAddress.valueOf("10.200.0.100")) + .build(); + target.updateNode(updated); + assertEquals(ERR_NOT_MATCH, updated, target.node(COMPUTE_2_INTG_DEVICE.id())); + validateEvents(OPENSTACK_NODE_UPDATED); + } + + /** + * Checks if updating a node state to complete generates proper events. + */ + @Test + public void testUpdateNodeStateComplete() { + OpenstackNode updated = DefaultOpenstackNode.from(COMPUTE_2) + .state(NodeState.COMPLETE) + .build(); + target.updateNode(updated); + assertEquals(ERR_NOT_MATCH, updated, target.node(COMPUTE_2_HOSTNAME)); + validateEvents(OPENSTACK_NODE_UPDATED, OPENSTACK_NODE_COMPLETE); + } + + /** + * Checks if updating a node state to incomplete generates proper events. + */ + @Test + public void testUpdateNodeStateIncomplete() { + OpenstackNode updated = DefaultOpenstackNode.from(COMPUTE_3) + .state(NodeState.INCOMPLETE) + .build(); + target.updateNode(updated); + assertEquals(ERR_NOT_MATCH, updated, target.node(COMPUTE_3_HOSTNAME)); + validateEvents(OPENSTACK_NODE_UPDATED, OPENSTACK_NODE_INCOMPLETE); + } + + /** + * Checks if updating a null node fails with proper exception. + */ + @Test(expected = NullPointerException.class) + public void testUpdateNullNode() { + target.updateNode(null); + } + + /** + * Checks if updating not existing node fails with proper exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testUpdateNotExistingNode() { + target.updateNode(COMPUTE_1); + } + + /** + * Checks if getting all nodes method returns correct set of nodes. + */ + @Test + public void testGetAllNodes() { + assertEquals(ERR_SIZE, 3, target.nodes().size()); + assertTrue(ERR_NOT_FOUND, target.nodes().contains(COMPUTE_2)); + assertTrue(ERR_NOT_FOUND, target.nodes().contains(COMPUTE_3)); + assertTrue(ERR_NOT_FOUND, target.nodes().contains(GATEWAY_1)); + } + + /** + * Checks if getting complete nodes method returns correct set of nodes. + */ + @Test + public void testGetCompleteNodes() { + assertEquals(ERR_SIZE, 2, target.completeNodes().size()); + assertTrue(ERR_NOT_FOUND, target.completeNodes().contains(COMPUTE_3)); + assertTrue(ERR_NOT_FOUND, target.completeNodes().contains(GATEWAY_1)); + } + + /** + * Checks if getting nodes by type method returns correct set of nodes. + */ + @Test + public void testGetNodesByType() { + assertEquals(ERR_SIZE, 2, target.nodes(COMPUTE).size()); + assertTrue(ERR_NOT_FOUND, target.nodes(COMPUTE).contains(COMPUTE_2)); + assertTrue(ERR_NOT_FOUND, target.nodes(COMPUTE).contains(COMPUTE_3)); + + assertEquals(ERR_SIZE, 1, target.nodes(GATEWAY).size()); + assertTrue(ERR_NOT_FOUND, target.nodes(GATEWAY).contains(GATEWAY_1)); + } + + /** + * Checks if getting a node by hostname returns correct node. + */ + @Test + public void testGetNodeByHostname() { + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(COMPUTE_2_HOSTNAME), COMPUTE_2)); + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(COMPUTE_3_HOSTNAME), COMPUTE_3)); + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(GATEWAY_1_HOSTNAME), GATEWAY_1)); + } + + /** + * Checks if getting a node by device ID returns correct node. + */ + @Test + public void testGetNodeByDeviceId() { + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(GATEWAY_1_INTG_DEVICE.id()), GATEWAY_1)); + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(GATEWAY_1.ovsdb()), GATEWAY_1)); + assertTrue(ERR_NOT_FOUND, Objects.equals( + target.node(GATEWAY_1.routerBridge()), GATEWAY_1)); + } + + private void validateEvents(Enum... types) { + int i = 0; + assertEquals("Number of events did not match", types.length, testListener.events.size()); + for (Event event : testListener.events) { + assertEquals("Incorrect event received", types[i], event.type()); + i++; + } + testListener.events.clear(); + } + + private static class TestOpenstackNodeListener implements OpenstackNodeListener { + private List events = Lists.newArrayList(); + + @Override + public void event(OpenstackNodeEvent event) { + events.add(event); + } + } + + private static class TestCoreService extends CoreServiceAdapter { + + @Override + public ApplicationId registerApplication(String name) { + return TEST_APP_ID; + } + } + + private class TestConfigService extends NetworkConfigRegistryAdapter { + + } + + private class TestClusterService extends ClusterServiceAdapter { + + } + + private static class TestLeadershipService extends LeadershipServiceAdapter { + + } +} \ No newline at end of file diff --git a/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java new file mode 100644 index 0000000000..d551efba16 --- /dev/null +++ b/apps/openstacknode/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017-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.openstacknode.impl; + +import org.onlab.packet.ChassisId; +import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.openstacknode.api.NodeState; +import org.onosproject.openstacknode.api.OpenstackNode; +import org.onosproject.openstacknode.api.OpenstackNode.NodeType; + +import static org.onosproject.net.Device.Type.SWITCH; + +/** + * Provides a set of test OpenstackNode parameters for use with OpenstackNode related tests. + */ +abstract class OpenstackNodeTest { + + protected static Device createDevice(long devIdNum) { + return new DefaultDevice(new ProviderId("of", "foo"), + DeviceId.deviceId(String.format("of:%016d", devIdNum)), + SWITCH, + "manufacturer", + "hwVersion", + "swVersion", + "serialNumber", + new ChassisId(1)); + } + + protected static OpenstackNode createNode(String hostname, NodeType type, + Device intgBridge, IpAddress ipAddr, + NodeState state) { + return DefaultOpenstackNode.builder() + .hostname(hostname) + .type(type) + .intgBridge(intgBridge.id()) + .managementIp(ipAddr) + .dataIp(ipAddr) + .state(state) + .build(); + } + + protected static OpenstackNode createNode(String hostname, NodeType type, + Device intgBridge, Device routerBridge, + IpAddress ipAddr, NodeState state) { + return DefaultOpenstackNode.builder() + .hostname(hostname) + .type(type) + .intgBridge(intgBridge.id()) + .routerBridge(routerBridge.id()) + .managementIp(ipAddr) + .dataIp(ipAddr) + .state(state) + .build(); + } +}