package org.opennaas.itests.openflowswitch;
import static org.openengsb.labs.paxexam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
import static org.opennaas.itests.helpers.OpennaasExamOptions.includeFeatures;
import static org.opennaas.itests.helpers.OpennaasExamOptions.noConsole;
import static org.opennaas.itests.helpers.OpennaasExamOptions.opennaasDistributionConfiguration;
import static org.ops4j.pax.exam.CoreOptions.options;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import junit.framework.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opennaas.core.resources.IModel;
import org.opennaas.core.resources.IResource;
import org.opennaas.core.resources.IResourceManager;
import org.opennaas.core.resources.ResourceException;
import org.opennaas.core.resources.capability.CapabilityException;
import org.opennaas.core.resources.descriptor.CapabilityDescriptor;
import org.opennaas.core.resources.descriptor.ResourceDescriptor;
import org.opennaas.core.resources.helpers.ResourceHelper;
import org.opennaas.core.resources.protocol.IProtocolManager;
import org.opennaas.core.resources.protocol.IProtocolSessionManager;
import org.opennaas.core.resources.protocol.ProtocolException;
import org.opennaas.extensions.openflowswitch.capability.IOpenflowForwardingCapability;
import org.opennaas.extensions.openflowswitch.capability.OpenflowForwardingCapability;
import org.opennaas.extensions.openflowswitch.driver.floodlight.protocol.FloodlightProtocolSession;
import org.opennaas.extensions.openflowswitch.driver.floodlight.protocol.client.IFloodlightStaticFlowPusherClient;
import org.opennaas.extensions.openflowswitch.driver.floodlight.protocol.client.mockup.FloodlightMockClientFactory;
import org.opennaas.extensions.openflowswitch.model.FloodlightOFAction;
import org.opennaas.extensions.openflowswitch.model.FloodlightOFFlow;
import org.opennaas.extensions.openflowswitch.model.FloodlightOFMatch;
import org.opennaas.extensions.openflowswitch.model.OFFlowTable;
import org.opennaas.extensions.openflowswitch.model.OpenflowSwitchModel;
import org.opennaas.itests.helpers.InitializerTestHelper;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.ExamReactorStrategy;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;
import org.ops4j.pax.exam.util.Filter;
import org.osgi.service.blueprint.container.BlueprintContainer;
//import static org.opennaas.itests.helpers.OpennaasExamOptions.openDebugSocket;
@RunWith(JUnit4TestRunner.class)
@ExamReactorStrategy(EagerSingleStagedReactorFactory.class)
public class OpenflowForwardingCapabilityIntegrationTest {
private final static Log log = LogFactory.getLog(OpenflowForwardingCapabilityIntegrationTest.class);
private static final String SWITCH_ID = "00:00:00:00:00:00:00:01";
private static final String ACTIONSET_NAME = "floodlight";
private static final String ACTIONSET_VERSION = "0.90";
private static final String CAPABILITY_URI = "mock://user:pass@host.net:2212/mocksubsystem";
private static final String RESOURCE_TYPE = "openflowswitch";
private static final String RESOURCE_URI = "mock://user:pass@host.net:2212/mocksubsystem";
private static final String RESOURCE_INFO_NAME = "ofswitch";
private static final String PROTOCOL = FloodlightProtocolSession.FLOODLIGHT_PROTOCOL_TYPE;
private static final String SWITCH_ID_NAME = FloodlightProtocolSession.SWITCHID_CONTEXT_PARAM_NAME;
private static final String WS_URI = "http://localhost:8888/opennaas/" + RESOURCE_TYPE + "/" + RESOURCE_INFO_NAME + "/" + OpenflowForwardingCapability.CAPABILITY_TYPE;
private static final String WS_USERNAME = "admin";
private static final String WS_PASSWORD = "123456";
private IResource ofSwitchResource;
/**
* Make sure blueprint for specified bundle has finished its initialization
*/
@SuppressWarnings("unused")
@Inject
@Filter(value = "(osgi.blueprint.container.symbolicname=org.opennaas.extensions.openflowswitch)", timeout = 20000)
private BlueprintContainer switchBlueprintContainer;
@SuppressWarnings("unused")
@Inject
@Filter(value = "(osgi.blueprint.container.symbolicname=org.opennaas.extensions.openflowswitch.driver.floodlight)", timeout = 20000)
private BlueprintContainer floodlightDriverBundleContainer;
@Inject
private IResourceManager resourceManager;
@Inject
private IProtocolManager protocolManager;
@Configuration
public static Option[] configuration() {
return options(opennaasDistributionConfiguration(),
includeFeatures("opennaas-openflow-switch", "opennaas-openflow-switch-driver-floodlight", "itests-helpers"),
noConsole(),
keepRuntimeFolder());
}
@Before
public void initBundle() throws ResourceException, ProtocolException {
InitializerTestHelper.removeResources(resourceManager);
// sleep to get time for dosgi to unregister the WS endpoints
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
// ignored
}
startResource();
// sleep to get time for dosgi to register the WS endpoints
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
// ignored
}
log.info("INFO: Initialized!");
}
@After
public void stopBundle() throws ResourceException {
InitializerTestHelper.removeResources(resourceManager);
ofSwitchResource = null;
// sleep to get time for dosgi to unregister the WS endpoints
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
// ignored
}
log.info("INFO: Stopped!");
}
@Test
public void isCapabilityAccesibleFromResource() throws ResourceException {
Assert.assertEquals("Resource should have only one capability.", 1, ofSwitchResource.getCapabilities().size());
Assert.assertNotNull("Resource should contain OpenflowForwardingCapability capability.",
ofSwitchResource.getCapabilityByInterface(IOpenflowForwardingCapability.class));
}
/**
* This test checks that, when a flow is created, the model is populated if there's no error in capability method execution.
*
* @throws ResourceException
* @throws ProtocolException
*/
@Test
public void createOpenflowForwardingRuleTest() throws ResourceException, ProtocolException {
IModel model = ofSwitchResource.getModel();
Assert.assertNotNull("Openflowswitch model should not be null after starting.", model);
Assert.assertTrue("Model is OpenflowSwitchModel", model instanceof OpenflowSwitchModel);
OpenflowSwitchModel switchModel = (OpenflowSwitchModel) model;
Assert.assertNotNull("Openflowswitch model should contain forwardingRule tables.", switchModel.getOfTables());
Assert.assertEquals("Openflowswitch model should contain one forwardingRule table after starting.", 1, switchModel.getOfTables().size());
OFFlowTable ofTable = switchModel.getOfTables().get(0);
Assert.assertNotNull("Openflow rules should not be null in forwardingRules table.", ofTable.getOfForwardingRules());
Assert.assertTrue("Openflow table should not contain any forwarding rule.", ofTable.getOfForwardingRules().isEmpty());
IOpenflowForwardingCapability capability = (IOpenflowForwardingCapability) ofSwitchResource
.getCapabilityByInterface(IOpenflowForwardingCapability.class);
FloodlightOFFlow forwardingRule = generateSampleFloodlightOFFlow("flow1", "1", "dstPort=12");
capability.createOpenflowForwardingRule(forwardingRule);
Assert.assertNotNull("Openflowswitch model should contain forwardingRule tables.", switchModel.getOfTables());
Assert.assertEquals("Openflowswitch model should contain one forwardingRule table after action execution.", 1, switchModel.getOfTables()
.size());
Assert.assertEquals("Incorrect switchId in model", SWITCH_ID, switchModel.getSwitchId());
OFFlowTable ofNewTable = switchModel.getOfTables().get(0);
Assert.assertNotNull("Openflow rules should not be null in forwardingRules table.", ofNewTable.getOfForwardingRules());
Assert.assertEquals("Openflow table should contain one forwarding rule.", 1, ofNewTable.getOfForwardingRules().size());
Assert.assertEquals("Model forwarding rule should be the one created for the action.", forwardingRule,
ofNewTable.getOfForwardingRules().get(0));
FloodlightOFFlow newForwardingRule = generateSampleFloodlightOFFlow("flow1", "1", "dstPort=12");
capability.createOpenflowForwardingRule(newForwardingRule);
Assert.assertNotNull("Openflowswitch model should contain forwardingRule tables.", switchModel.getOfTables());
Assert.assertEquals("Openflowswitch model should contain one forwardingRule table after action execution.", 1, switchModel.getOfTables()
.size());
Assert.assertEquals("Incorrect switchId in model", SWITCH_ID, switchModel.getSwitchId());
OFFlowTable ofModelTable = switchModel.getOfTables().get(0);
Assert.assertNotNull("Openflow rules should not be null in forwardingRules table.", ofModelTable.getOfForwardingRules());
Assert.assertEquals("Openflow table should contain two forwarding rules.", 2, ofModelTable.getOfForwardingRules().size());
Assert.assertEquals("Model forwarding rule should be the one created for the action.", forwardingRule,
ofModelTable.getOfForwardingRules().get(0));
Assert.assertEquals("Model forwarding rule should be the one created for the action.", newForwardingRule,
ofModelTable.getOfForwardingRules().get(1));
}
/**
* Test create a forwarding rule with a wrong actionId, since forwardingCapability supports only "output" actions.
*
* @throws ResourceException
*/
@Test(expected = CapabilityException.class)
public void wrongActionTest() throws ResourceException {
IOpenflowForwardingCapability capability = (IOpenflowForwardingCapability) ofSwitchResource
.getCapabilityByInterface(IOpenflowForwardingCapability.class);
FloodlightOFFlow forwardingRule = new FloodlightOFFlow();
forwardingRule.setName("flow1");
forwardingRule.setPriority("1");
FloodlightOFAction floodlightAction = new FloodlightOFAction();
floodlightAction.setType("wrongActionName");
floodlightAction.setValue("dstPort=12");
List<FloodlightOFAction> actions = new ArrayList<FloodlightOFAction>();
actions.add(floodlightAction);
forwardingRule.setActions(actions);
capability.createOpenflowForwardingRule(forwardingRule);
}
@Test
public void createDeleteGetTest() throws Exception {
IOpenflowForwardingCapability capability = (IOpenflowForwardingCapability) ofSwitchResource
.getCapabilityByInterface(IOpenflowForwardingCapability.class);
createDeleteGetPerformAndCheck(capability);
}
@Test
public void createDeleteGetWSTest() throws Exception {
IOpenflowForwardingCapability capabilityWSClient = InitializerTestHelper.createRestClient(WS_URI, IOpenflowForwardingCapability.class, null,
WS_USERNAME, WS_PASSWORD);
createDeleteGetPerformAndCheck(capabilityWSClient);
}
private void createDeleteGetPerformAndCheck(IOpenflowForwardingCapability capability) throws Exception {
FloodlightOFFlow forwardingRule1 = generateSampleFloodlightOFFlow("flow1", "1", "dstPort=12");
forwardingRule1.setSwitchId(SWITCH_ID);
FloodlightOFFlow forwardingRule2 = generateSampleFloodlightOFFlow("flow2", "2", "dstPort=12");
forwardingRule2.setSwitchId(SWITCH_ID);
Assert.assertTrue("No rules in a freshly created switch", capability.getOpenflowForwardingRules().isEmpty());
capability.createOpenflowForwardingRule(forwardingRule1);
Assert.assertEquals("There is one single rule after creating one", 1, capability.getOpenflowForwardingRules().size());
Assert.assertEquals("forwardingRule1 has been correctly created", forwardingRule1, capability
.getOpenflowForwardingRules().get(0));
capability.createOpenflowForwardingRule(forwardingRule2);
Assert.assertEquals("There are two rules after creating two", 2, capability.getOpenflowForwardingRules().size());
Assert.assertEquals("forwardingRule2 has been correctly created", forwardingRule2, capability
.getOpenflowForwardingRules().get(1));
capability.removeOpenflowForwardingRule(forwardingRule1.getDPID(),forwardingRule1.getName());
Assert.assertEquals("There is one single rule after deleting forwardingRule1", 1, capability.getOpenflowForwardingRules().size());
Assert.assertEquals("forwardingRule2 is still in the switch after deleting forwardingRule1", forwardingRule2, capability
.getOpenflowForwardingRules().get(0));
capability.removeOpenflowForwardingRule(forwardingRule2.getDPID(), forwardingRule2.getName());
Assert.assertTrue("There is no rule after 2 deletions", capability.getOpenflowForwardingRules().isEmpty());
}
private void startResource() throws ResourceException, ProtocolException {
/* initialize model */
List<CapabilityDescriptor> lCapabilityDescriptors = new ArrayList<CapabilityDescriptor>();
CapabilityDescriptor ofForwardingDescriptor = ResourceHelper.newCapabilityDescriptor(ACTIONSET_NAME,
ACTIONSET_VERSION,
OpenflowForwardingCapability.CAPABILITY_TYPE,
CAPABILITY_URI);
lCapabilityDescriptors.add(ofForwardingDescriptor);
// OFSwitch Resource Descriptor
ResourceDescriptor resourceDescriptor = ResourceHelper.newResourceDescriptor(lCapabilityDescriptors, RESOURCE_TYPE,
RESOURCE_URI,
RESOURCE_INFO_NAME);
ofSwitchResource = resourceManager.createResource(resourceDescriptor);
Map<String, Object> sessionParameters = new HashMap<String, Object>();
sessionParameters.put(SWITCH_ID_NAME, SWITCH_ID);
// If not exists the protocol session manager, it's created and add the session context
InitializerTestHelper.addSessionContextWithSessionParams(protocolManager, ofSwitchResource.getResourceIdentifier().getId(), RESOURCE_URI,
PROTOCOL, sessionParameters);
// Start resource
resourceManager.startResource(ofSwitchResource.getResourceIdentifier());
prepareClient();
}
private void prepareClient() throws ProtocolException {
IProtocolSessionManager sessionManager = protocolManager.getProtocolSessionManager(ofSwitchResource.getResourceIdentifier().getId());
FloodlightProtocolSession session = (FloodlightProtocolSession) sessionManager.obtainSessionByProtocol(
FloodlightProtocolSession.FLOODLIGHT_PROTOCOL_TYPE, false);
session.setClientFactory(new FloodlightMockClientFactory());
IFloodlightStaticFlowPusherClient client = session.getClientFactory().createClient(session.getSessionContext());
session.setFloodlightClient(client);
}
private static FloodlightOFFlow generateSampleFloodlightOFFlow(String name, String inputPort, String outputPort) {
FloodlightOFFlow forwardingRule = new FloodlightOFFlow();
forwardingRule.setName(name);
forwardingRule.setPriority("1");
FloodlightOFMatch match = new FloodlightOFMatch();
match.setIngressPort(inputPort);
forwardingRule.setMatch(match);
FloodlightOFAction floodlightAction = new FloodlightOFAction();
floodlightAction.setType("output");
floodlightAction.setValue(outputPort);
List<FloodlightOFAction> actions = new ArrayList<FloodlightOFAction>();
actions.add(floodlightAction);
forwardingRule.setActions(actions);
return forwardingRule;
}
}