/*
* Copyright (c) 2016 Ericsson Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.sfc.genius.util;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.opendaylight.sfc.genius.impl.utils.SfcGeniusConstants;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfDataPlaneLocatorName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SftTypeName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocator;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocatorBuilder;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocatorKey;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionBuilder;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.IpBuilder;
import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.functions.service.function.sf.data.plane.locator.locator.type.LogicalInterfaceBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* Unit Testing for the SfcGeniusDataUtils class.
*
* @author Miguel Duarte (miguel.duarte.de.mora.barroso@ericsson.com)
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(SfcGeniusUtilsDataGetter.class)
public class SfcGeniusDataUtilsTest {
private final String ifName = "40c552e0-3695-472d-bace-7618786aba27";
private final String macAddress = "b2:0e:19:ad:1e:22";
private final BigInteger theDpnId = new BigInteger("79268612506848");
private final String logicalIfName = "tap40c552e0-36";
@Captor
ArgumentCaptor<Interface> interfaceCaptor;
public SfcGeniusDataUtilsTest() {
}
@Before
public void setUp() {
PowerMockito.mockStatic(SfcGeniusUtilsDataGetter.class);
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceName(anyString()))
.thenReturn(Optional.of(logicalIfName));
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceState(anyString()))
.thenReturn(Optional.of(new InterfaceBuilder().setKey(new InterfaceKey(logicalIfName))
.setPhysAddress(new PhysAddress("11:22:33:44:55:66")).setLowerLayerIf(new ArrayList<String>() {
{
add("openflow:79268612506848:1");
}
}).setType(L2vlan.class).build()));
OvsdbTerminationPointAugmentationBuilder ovsdbTpAug = new OvsdbTerminationPointAugmentationBuilder();
ovsdbTpAug.setPortUuid(new Uuid("451f440a-a828-41ad-993c-93aaec43eb31"));
ovsdbTpAug.setOfport((long) 1);
List<InterfaceExternalIds> theInterfaces = new ArrayList<InterfaceExternalIds>() {
{
add(new InterfaceExternalIdsBuilder().setExternalIdKey("attached-mac").setExternalIdValue(macAddress)
.build());
}
};
ovsdbTpAug.setInterfaceExternalIds(theInterfaces);
TerminationPoint theTerminationPoint = new TerminationPointBuilder()
.setKey(new TerminationPointKey(new TerminationPointKey(new TpId(logicalIfName))))
.addAugmentation(OvsdbTerminationPointAugmentation.class, ovsdbTpAug.build()).build();
String ovsdbNodeId = "ovsdb://uuid/e94d439a-57cf-4b8f-9247-56cdd692fa33/bridge/br-int";
Node theOvsNode = new NodeBuilder().setNodeId(new NodeId(ovsdbNodeId))
.setTerminationPoint(new ArrayList<TerminationPoint>() {
{
add(theTerminationPoint);
}
}).build();
InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIID = InstanceIdentifier.create(
org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network
.topology.rev131021.NetworkTopology.class)
.child(Topology.class, new TopologyKey(SfcGeniusConstants.OVSDB_TOPOLOGY_ID))
.child(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network
.topology.rev131021.network.topology.topology.Node.class,
theOvsNode.getKey())
.augmentation(OvsdbBridgeAugmentation.class);
BridgeRefEntry theBridge = new BridgeRefEntryBuilder().setKey(new BridgeRefEntryKey(theDpnId))
.setBridgeReference(new OvsdbBridgeRef(bridgeIID)).build();
PowerMockito.when(SfcGeniusUtilsDataGetter.readOvsNodeInterfaces(anyString(), anyString()))
.thenReturn(theInterfaces);
PowerMockito.when(SfcGeniusUtilsDataGetter.getBridgeFromDpnId(any(BigInteger.class)))
.thenReturn(Optional.of(theBridge));
}
/**
* Negative test when the interface does not exist in the CONFIG DS.
*
*/
@Test(expected = RuntimeException.class)
public void readMacAddressInterfaceDoesNotExist() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceName(ifName)).thenReturn(null);
SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
}
/**
* Positive test.
*
*/
@Test
public void readRemoteMacAddress() {
Optional<MacAddress> mac = SfcGeniusDataUtils.getServiceFunctionForwarderPortMacAddress(ifName);
Assert.assertTrue(mac.isPresent());
}
/**
* Negative test when the interface does not exist in the CONFIG DS.
*
*/
@Test(expected = RuntimeException.class)
public void readRemoteMacAddressInterfaceDoesNotExist() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceState(ifName)).thenReturn(null);
SfcGeniusDataUtils.getServiceFunctionForwarderPortMacAddress(ifName);
}
/**
* Negative test when the interface exists, but does not have a physical
* address.
*/
@Test(expected = RuntimeException.class)
public void readRemoteMacAddressPhysicalAddressDoesNotExists() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceState(ifName))
.thenReturn(Optional.of(new InterfaceBuilder().setKey(new InterfaceKey(logicalIfName))
.setPhysAddress(null).setLowerLayerIf(new ArrayList<String>() {
{
add("openflow:79268612506848:1");
}
}).setType(L2vlan.class).build()));
SfcGeniusDataUtils.getServiceFunctionForwarderPortMacAddress(ifName);
}
/**
* Negative test when the interface features in the CONFIG DS but does not
* feature in the OPERATIONAL DS.
*
*/
@Test(expected = RuntimeException.class)
public void readMacAddressInterfaceNotProperlyConfigured() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceState(ifName)).thenReturn(null);
SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
}
/**
* Negative test when the interface features in the CONFIG DS, features in
* the OPERATIONAL DS, but we cannot retrieve a BridgeRefEntry from the
* model.
*
*/
@Test(expected = RuntimeException.class)
public void readMacAddressInterfaceWrongBridge() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getBridgeFromDpnId(theDpnId)).thenReturn(null);
SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
}
/**
* Negative test when the interface features in the CONFIG DS, features in
* the OPERATIONAL DS, we can get a BridgeRefEntry, but the bridge does not
* belong to an OVS switch.
*
*/
@Test(expected = RuntimeException.class)
public void readMacAddressNotOvsBridge() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getBridgeFromDpnId(theDpnId))
.thenReturn(Optional.of(new BridgeRefEntryBuilder().setKey(new BridgeRefEntryKey(theDpnId)).build()));
SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
}
/**
* Negative test when the interface features in the CONFIG DS, features in
* the OPERATIONAL DS, we can get a BridgeRefEntry, the bridge belongs to an
* OVS switch, but there's no TerminationPoint.
*
*/
@Test(expected = org.opendaylight.sfc.genius.impl.utils.SfcGeniusRuntimeException.class)
public void readMacAddressInvalidDpnId() {
PowerMockito.when(SfcGeniusUtilsDataGetter.getServiceFunctionAttachedInterfaceState(ifName))
.thenReturn(Optional.of(new InterfaceBuilder().setKey(new InterfaceKey(logicalIfName))
.setPhysAddress(new PhysAddress("52:c1:91:54:fc:7a")).setLowerLayerIf(new ArrayList<String>() {
{
add("qua-qua");
}
}).setType(L2vlan.class).build()));
SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
}
/**
* Negative test when the interface features in the CONFIG DS, features in
* the OPERATIONAL DS, we can get a BridgeRefEntry, the bridge belongs to an
* OVS switch, there's a TerminationPoint, *BUT* it does not have an
* attached MAC.
*
*/
@Test
public void readMacAddressInvalidTerminationPoint() {
// this InterfaceExternalIds list does not have the
// 'attached-mac-address' key
List<InterfaceExternalIds> theInterfaces = new ArrayList<InterfaceExternalIds>() {
{
add(new InterfaceExternalIdsBuilder().build());
}
};
PowerMockito.when(SfcGeniusUtilsDataGetter.readOvsNodeInterfaces(anyString(), anyString()))
.thenReturn(theInterfaces);
Optional<MacAddress> theMac = SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
Assert.assertFalse(theMac.isPresent());
}
/**
* Positive test, where we can get the MAC Address of a SF attached to a
* SFF.
*
*/
@Test
public void readMacAddress() {
Optional<MacAddress> theMac = SfcGeniusDataUtils.getServiceFunctionMacAddress(ifName);
Assert.assertTrue(theMac.isPresent());
Assert.assertEquals(new MacAddress(macAddress), theMac.get());
}
/**
* Negative test, where we cannot retrieve the interface name of the
* LogicalInterface to which the SF is connected to, because it does not
* have a dataplane locator set.
*
*/
@Test(expected = IllegalArgumentException.class)
public void getSfLogicalInterfaceNegativeTestNoDpl() {
SfName sf1Name = new SfName("dpi");
String dpiIpAddress = "192.168.1.30";
ServiceFunctionKey dpiKey = new ServiceFunctionKey(sf1Name);
List<SfDataPlaneLocator> dpLocators = new ArrayList<SfDataPlaneLocator>() {
{
add(new SfDataPlaneLocatorBuilder()
.setKey(new SfDataPlaneLocatorKey(new SfDataPlaneLocatorName("dpi-1-dpl")))
.setServiceFunctionForwarder(new SffName("sfflogical1")).build());
}
};
ServiceFunction dpiNode = new ServiceFunctionBuilder().setKey(dpiKey)
.setIpMgmtAddress(new IpAddress(dpiIpAddress.toCharArray()))
.setRestUri(new Uri(dpiIpAddress.concat(":5000"))).setType(new SftTypeName("dpi"))
.setSfDataPlaneLocator(dpLocators).build();
SfcGeniusDataUtils.getSfLogicalInterface(dpiNode);
}
/**
* Negative test, where we cannot retrieve the interface name of the
* LogicalInterface to which the SF is connected to, because it has a
* different DataPlaneLocator type.
*
*/
@Test(expected = IllegalArgumentException.class)
public void getSfLogicalInterfaceNegativeTest() {
SfName sf1Name = new SfName("dpi");
String dpiIpAddress = "192.168.1.30";
ServiceFunctionKey dpiKey = new ServiceFunctionKey(sf1Name);
List<SfDataPlaneLocator> dpLocators = new ArrayList<SfDataPlaneLocator>() {
{
add(new SfDataPlaneLocatorBuilder()
.setKey(new SfDataPlaneLocatorKey(new SfDataPlaneLocatorName("dpi-1-dpl")))
.setServiceFunctionForwarder(new SffName("sfflogical1")).setLocatorType(new IpBuilder()
.setIp(new IpAddress(dpiIpAddress.toCharArray())).setPort(new PortNumber(8181)).build())
.build());
}
};
ServiceFunction dpiNode = new ServiceFunctionBuilder().setKey(dpiKey)
.setIpMgmtAddress(new IpAddress(dpiIpAddress.toCharArray()))
.setRestUri(new Uri(dpiIpAddress.concat(":5000"))).setType(new SftTypeName("dpi"))
.setSfDataPlaneLocator(dpLocators).build();
Assert.assertFalse(SfcGeniusDataUtils.isSfUsingALogicalInterface(dpiNode));
SfcGeniusDataUtils.getSfLogicalInterface(dpiNode);
}
/**
* Negative test, where we cannot retrieve the interface name of the
* LogicalInterface to which the SF is connected to, because it has multiple
* LogicalInterface data-plane locators, and we cannot know which is the
* correct one.
*/
@Test(expected = IllegalArgumentException.class)
public void getSfLogicalInterfaceWithMultipleLocatorsNegativeTest() {
SfName sf1Name = new SfName("dpi");
String dpiIpAddress = "192.168.1.30";
ServiceFunctionKey dpiKey = new ServiceFunctionKey(sf1Name);
List<SfDataPlaneLocator> dpLocators = new ArrayList<SfDataPlaneLocator>() {
{
add(new SfDataPlaneLocatorBuilder()
.setKey(new SfDataPlaneLocatorKey(new SfDataPlaneLocatorName("dpi-1-dpl")))
.setServiceFunctionForwarder(new SffName("sfflogical1"))
.setLocatorType(new LogicalInterfaceBuilder()
.setInterfaceName("40c552e0-3695-472d-bace-7618786aba27").build())
.build());
add(new SfDataPlaneLocatorBuilder()
.setKey(new SfDataPlaneLocatorKey(new SfDataPlaneLocatorName("dpi-2-dpl")))
.setServiceFunctionForwarder(new SffName("sfflogical1"))
.setLocatorType(new LogicalInterfaceBuilder()
.setInterfaceName("12345678-3695-472d-bace-7618786aba27").build())
.build());
}
};
ServiceFunction dpiNode = new ServiceFunctionBuilder().setKey(dpiKey)
.setIpMgmtAddress(new IpAddress(dpiIpAddress.toCharArray()))
.setRestUri(new Uri(dpiIpAddress.concat(":5000"))).setType(new SftTypeName("dpi"))
.setSfDataPlaneLocator(dpLocators).build();
Assert.assertTrue(SfcGeniusDataUtils.isSfUsingALogicalInterface(dpiNode));
SfcGeniusDataUtils.getSfLogicalInterface(dpiNode);
}
/**
* Positive test, where we can get the name of the LogicalInterface to which
* the SF is connected to.
*/
@Test
public void getSfLogicalInterface() {
SfName sf1Name = new SfName("dpi");
String dpiIpAddress = "192.168.1.30";
ServiceFunctionKey dpiKey = new ServiceFunctionKey(sf1Name);
List<SfDataPlaneLocator> dpLocators = new ArrayList<SfDataPlaneLocator>() {
{
add(new SfDataPlaneLocatorBuilder()
.setKey(new SfDataPlaneLocatorKey(new SfDataPlaneLocatorName("dpi-1-dpl")))
.setServiceFunctionForwarder(new SffName("sfflogical1"))
.setLocatorType(new LogicalInterfaceBuilder()
.setInterfaceName("40c552e0-3695-472d-bace-7618786aba27").build())
.build());
}
};
ServiceFunction dpiNode = new ServiceFunctionBuilder().setKey(dpiKey)
.setIpMgmtAddress(new IpAddress(dpiIpAddress.toCharArray()))
.setRestUri(new Uri(dpiIpAddress.concat(":5000"))).setType(new SftTypeName("dpi"))
.setSfDataPlaneLocator(dpLocators).build();
Assert.assertTrue(SfcGeniusDataUtils.isSfUsingALogicalInterface(dpiNode));
Assert.assertEquals("40c552e0-3695-472d-bace-7618786aba27", SfcGeniusDataUtils.getSfLogicalInterface(dpiNode));
}
}