/** * Copyright IBM Corporation, 2013. 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.openflowplugin.openflow.md.core.session; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener; import org.opendaylight.openflowplugin.openflow.md.ModelDrivenSwitch; import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductor; import org.opendaylight.openflowplugin.openflow.md.core.ErrorHandler; import org.opendaylight.openflowplugin.openflow.md.core.NotificationEnqueuer; import org.opendaylight.openflowplugin.openflow.md.core.NotificationQueueWrapper; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; import org.opendaylight.openflowplugin.openflow.md.queue.QueueProcessor; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoReplyInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetConfigInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetConfigInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetConfigOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetQueueConfigInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetQueueConfigInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetQueueConfigOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GroupModInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MeterModInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortModInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.SetAsyncInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.SetConfigInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.TableModInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.TableModInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener; import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; /** * test for {@link MessageDispatchServiceImpl} */ public class MessageDispatchServiceImplTest { MockSessionContext session; /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { session = new MockSessionContext(0); } /** * Test barrier message for null cookie * * @throws Exception */ @Test public void testBarrierMessageForPrimary() throws Exception { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); BarrierInputBuilder barrierMsg = new BarrierInputBuilder(); session.getMessageDispatchService().barrier(barrierMsg.build(), cookie); Assert.assertEquals(MessageType.BARRIER, session.getPrimaryConductor().getMessageType()); } /** * Test experimenter message for null cookie */ @Test public void testExperimenter() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); ExperimenterInputBuilder experimenterInputBuilder = new ExperimenterInputBuilder(); session.getMessageDispatchService().experimenter(experimenterInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test get async input with null cookie */ @Test public void testGetAsync() throws ExecutionException, InterruptedException { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); GetAsyncInputBuilder getAsyncInputBuilder = new GetAsyncInputBuilder(); session.getMessageDispatchService().getAsync(getAsyncInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test get async output with null cookie */ @Test public void testGetConfig() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); GetConfigInputBuilder getConfigInputBuilder = new GetConfigInputBuilder(); session.getMessageDispatchService().getConfig(getConfigInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test get features with null cookie */ @Test public void testGetFeatures() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); GetFeaturesInputBuilder getFeaturesInputBuilder = new GetFeaturesInputBuilder(); session.getMessageDispatchService().getFeatures(getFeaturesInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test get queue config with null cookie */ @Test public void testGetQueueConfig() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); GetQueueConfigInputBuilder getQueueConfigInputBuilder = new GetQueueConfigInputBuilder(); session.getMessageDispatchService().getQueueConfig(getQueueConfigInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test multipart request with null cookie */ @Test public void testGetMultipart() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); MultipartRequestInputBuilder multipartRequestInputBuilder = new MultipartRequestInputBuilder(); session.getMessageDispatchService().multipartRequest(multipartRequestInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test role request with null cookie */ @Test public void testRoleRequest() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); RoleRequestInputBuilder roleRequestInputBuilder = new RoleRequestInputBuilder(); session.getMessageDispatchService().roleRequest(roleRequestInputBuilder.build(), cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); } /** * Test table mod with null cookie */ @Test public void testTableMod() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); TableModInputBuilder tableModInputBuilder = new TableModInputBuilder(); session.getMessageDispatchService().tableMod(tableModInputBuilder.build(), cookie); Assert.assertEquals(MessageType.TABLEMOD, session.getPrimaryConductor().getMessageType()); } /** * Test packet out message for primary connection * * @throws Exception */ @Test public void testPacketOutMessageForPrimary() throws Exception { session.getMessageDispatchService().packetOut(null, null); Assert.assertEquals(MessageType.PACKETOUT, session.getPrimaryConductor().getMessageType()); } /** * Test packet out message for auxiliary connection * * @throws Exception */ @Test public void testPacketOutMessageForAuxiliary() throws Exception { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); session.addAuxiliaryConductor(cookie, conductor); session.getMessageDispatchService().packetOut(null, cookie); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); conductor = (MockConnectionConductor) session.getAuxiliaryConductor(cookie); Assert.assertEquals(MessageType.PACKETOUT, conductor.getMessageType()); } /** * Test packet out message when multiple auxiliary connection exist * * @throws Exception */ @Test public void testPacketOutMessageForMultipleAuxiliary() throws Exception { MockConnectionConductor conductor1 = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie1 = conductor1.getAuxiliaryKey(); session.addAuxiliaryConductor(cookie1, conductor1); MockConnectionConductor conductor2 = new MockConnectionConductor(2); SwitchConnectionDistinguisher cookie2 = conductor2.getAuxiliaryKey(); session.addAuxiliaryConductor(cookie2, conductor2); MockConnectionConductor conductor3 = new MockConnectionConductor(3); SwitchConnectionDistinguisher cookie3 = conductor3.getAuxiliaryKey(); session.addAuxiliaryConductor(cookie3, conductor3); PacketOutInputBuilder builder = new PacketOutInputBuilder(); // send message session.getMessageDispatchService().packetOut(builder.build(), cookie2); Assert.assertEquals(MessageType.NONE, session.getPrimaryConductor().getMessageType()); conductor3 = (MockConnectionConductor) session.getAuxiliaryConductor(cookie3); Assert.assertEquals(MessageType.NONE, conductor3.getMessageType()); conductor2 = (MockConnectionConductor) session.getAuxiliaryConductor(cookie2); Assert.assertEquals(MessageType.PACKETOUT, conductor2.getMessageType()); conductor1 = (MockConnectionConductor) session.getAuxiliaryConductor(cookie1); Assert.assertEquals(MessageType.NONE, conductor1.getMessageType()); } /** * Test for invalid session * * @throws Exception */ @Test public void testInvalidSession() throws Exception { session.setValid(false); Future> resultFuture = session.getMessageDispatchService().packetOut(null, null); if (resultFuture.isDone()) { RpcResult rpcResult = resultFuture.get(); Assert.assertTrue(!rpcResult.getErrors().isEmpty()); Iterator it = rpcResult.getErrors().iterator(); RpcError rpcError = it.next(); Assert.assertTrue(rpcError.getApplicationTag().equals(OFConstants.APPLICATION_TAG)); Assert.assertTrue(rpcError.getTag().equals(OFConstants.ERROR_TAG_TIMEOUT)); Assert.assertTrue(rpcError.getErrorType().equals(RpcError.ErrorType.TRANSPORT)); } } } class MockSessionContext implements SessionContext { private MockConnectionConductor conductor; private Map map; private IMessageDispatchService messageService; private boolean isValid = true; private CompositeObjectRegistration registration; private int seed; MockSessionContext(int conductorNum) { conductor = new MockConnectionConductor(conductorNum); map = new HashMap(); messageService = new MessageDispatchServiceImpl(this); } @Override public MockConnectionConductor getPrimaryConductor() { // TODO Auto-generated method stub return conductor; } @Override public GetFeaturesOutput getFeatures() { // TODO Auto-generated method stub return null; } @Override public ConnectionConductor getAuxiliaryConductor(SwitchConnectionDistinguisher auxiliaryKey) { return map.get(auxiliaryKey); } @Override public Set> getAuxiliaryConductors() { // TODO Auto-generated method stub return null; } @Override public void addAuxiliaryConductor(SwitchConnectionDistinguisher auxiliaryKey, ConnectionConductor conductorArg) { map.put(auxiliaryKey, conductorArg); } @Override public ConnectionConductor removeAuxiliaryConductor(SwitchConnectionDistinguisher connectionCookie) { return map.remove(connectionCookie); } @Override public boolean isValid() { // TODO Auto-generated method stub return isValid; } @Override public void setValid(boolean valid) { isValid = valid; } @Override public SwitchSessionKeyOF getSessionKey() { // TODO Auto-generated method stub return null; } @Override public IMessageDispatchService getMessageDispatchService() { // TODO Auto-generated method stub return messageService; } @Override public Long getNextXid() { // TODO Auto-generated method stub return null; } @Override public Map getPhysicalPorts() { // TODO Auto-generated method stub return null; } @Override public Set getPorts() { // TODO Auto-generated method stub return null; } @Override public PortGrouping getPhysicalPort(Long portNumber) { // TODO Auto-generated method stub return null; } @Override public Boolean getPortBandwidth(Long portNumber) { // TODO Auto-generated method stub return null; } @Override public boolean isPortEnabled(long portNumber) { // TODO Auto-generated method stub return false; } @Override public boolean isPortEnabled(PortGrouping port) { // TODO Auto-generated method stub return false; } @Override public List getEnabledPorts() { // TODO Auto-generated method stub return null; } @Override public Map getPortsBandwidth() { // TODO Auto-generated method stub return null; } @Override public CompositeObjectRegistration getProviderRegistration() { return registration; } @Override public void setProviderRegistration( CompositeObjectRegistration registration) { this.registration = registration; } @Override public int getSeed() { return seed; } /** * @param seed the seed to set */ public void setSeed(int seed) { this.seed = seed; } @Override public NotificationEnqueuer getNotificationEnqueuer() { return conductor; } } class MockConnectionConductor implements ConnectionConductor, NotificationEnqueuer { private int conductorNum; private MockConnectionAdapter adapter; public MockConnectionConductor(int conductorNumber) { conductorNum = conductorNumber; adapter = new MockConnectionAdapter(); } @Override public void init() { // TODO Auto-generated method stub } @Override public Short getVersion() { // TODO Auto-generated method stub return null; } @Override public CONDUCTOR_STATE getConductorState() { // TODO Auto-generated method stub return null; } @Override public void setConductorState(CONDUCTOR_STATE conductorState) { // TODO Auto-generated method stub } @Override public Future disconnect() { // TODO Auto-generated method stub return null; } @Override public void setSessionContext(SessionContext context) { // TODO Auto-generated method stub } @Override public void setConnectionCookie(SwitchConnectionDistinguisher auxiliaryKey) { // TODO Auto-generated method stub } @Override public SessionContext getSessionContext() { // TODO Auto-generated method stub return null; } @Override public SwitchConnectionDistinguisher getAuxiliaryKey() { if (0 != conductorNum) { SwitchConnectionCookieOFImpl key = new SwitchConnectionCookieOFImpl(); key.setAuxiliaryId((short) conductorNum); key.init(42); return key; } return null; } @Override public ConnectionAdapter getConnectionAdapter() { // TODO Auto-generated method stub return adapter; } public MessageType getMessageType() { return adapter.getMessageType(); } @Override public void setQueueProcessor(QueueProcessor queueKeeper) { // NOOP } @Override public void setErrorHandler(ErrorHandler errorHandler) { // NOOP } @Override public void setId(int conductorId) { // NOOP } @Override public void enqueueNotification(NotificationQueueWrapper notification) { // NOOP } } enum MessageType { NONE, BARRIER, FLOWMOD, TABLEMOD, PACKETOUT; } class MockConnectionAdapter implements ConnectionAdapter { private MessageType messageType; private ConnectionReadyListener connectionReadyListener; public MockConnectionAdapter() { setMessageType(MessageType.NONE); } @Override public Future> barrier(BarrierInput input) { setMessageType(MessageType.BARRIER); return null; } @Override public Future> echo(EchoInput input) { // TODO Auto-generated method stub return null; } @Override public Future> echoReply(EchoReplyInput input) { // TODO Auto-generated method stub return null; } @Override public Future> experimenter(ExperimenterInput input) { // TODO Auto-generated method stub return null; } @Override public Future> flowMod(FlowModInput input) { setMessageType(MessageType.FLOWMOD); return null; } @Override public Future> getAsync(GetAsyncInput input) { // TODO Auto-generated method stub return null; } @Override public Future> getConfig(GetConfigInput input) { // TODO Auto-generated method stub return null; } @Override public Future> getFeatures(GetFeaturesInput input) { // TODO Auto-generated method stub return null; } @Override public Future> getQueueConfig(GetQueueConfigInput input) { // TODO Auto-generated method stub return null; } @Override public Future> groupMod(GroupModInput input) { // TODO Auto-generated method stub return null; } @Override public Future> hello(HelloInput input) { // TODO Auto-generated method stub return null; } @Override public Future> meterMod(MeterModInput input) { // TODO Auto-generated method stub return null; } @Override public Future> packetOut(PacketOutInput input) { setMessageType(MessageType.PACKETOUT); return null; } @Override public Future> portMod(PortModInput input) { // TODO Auto-generated method stub return null; } @Override public Future> roleRequest(RoleRequestInput input) { // TODO Auto-generated method stub return null; } @Override public Future> setAsync(SetAsyncInput input) { // TODO Auto-generated method stub return null; } @Override public Future> setConfig(SetConfigInput input) { // TODO Auto-generated method stub return null; } @Override public Future> tableMod(TableModInput input) { setMessageType(MessageType.TABLEMOD); return null; } @Override public Future disconnect() { // TODO Auto-generated method stub return null; } @Override public boolean isAlive() { // TODO Auto-generated method stub return false; } @Override public void setMessageListener(OpenflowProtocolListener messageListener) { // TODO Auto-generated method stub } @Override public void setSystemListener(SystemNotificationsListener systemListener) { // TODO Auto-generated method stub } @Override public void checkListeners() { // TODO Auto-generated method stub } /** * @return the messageType */ public MessageType getMessageType() { return messageType; } /** * @param messageType the messageType to set */ public void setMessageType(MessageType messageType) { this.messageType = messageType; } @Override public void fireConnectionReadyNotification() { connectionReadyListener.onConnectionReady(); } @Override public void setConnectionReadyListener( ConnectionReadyListener connectionReadyListener) { this.connectionReadyListener = connectionReadyListener; } @Override public Future> multipartRequest( MultipartRequestInput input) { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter#getRemoteAddress() */ @Override public InetSocketAddress getRemoteAddress() { // TODO Auto-generated method stub return null; } }