/* * Copyright (c) 2014 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.core.connection; import static org.mockito.Matchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; 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.BarrierOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder; 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.PacketInMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEvent; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEventBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEvent; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEventBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener; import org.opendaylight.yangtools.yang.binding.DataObject; /** * @author michal.polkorab * @author madamjak * */ public class ConnectionAdapterImplTest { private static final int RPC_RESPONSE_EXPIRATION = 1; private static final RemovalListener<RpcResponseKey, ResponseExpectedRpcListener<?>> REMOVAL_LISTENER = new RemovalListener<RpcResponseKey, ResponseExpectedRpcListener<?>>() { @Override public void onRemoval( final RemovalNotification<RpcResponseKey, ResponseExpectedRpcListener<?>> notification) { notification.getValue().discard(); } }; @Mock SocketChannel channel; @Mock ChannelPipeline pipeline; @Mock OpenflowProtocolListener messageListener; @Mock SystemNotificationsListener systemListener; @Mock ConnectionReadyListener readyListener; @Mock Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> mockCache; @Mock ChannelFuture channelFuture; private ConnectionAdapterImpl adapter; private Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> cache; /** * Initializes ConnectionAdapter */ @Before public void setUp() { MockitoAnnotations.initMocks(this); when(channel.pipeline()).thenReturn(pipeline); adapter = new ConnectionAdapterImpl(channel, InetSocketAddress.createUnresolved("10.0.0.1", 6653), true); adapter.setMessageListener(messageListener); adapter.setSystemListener(systemListener); adapter.setConnectionReadyListener(readyListener); cache = CacheBuilder.newBuilder().concurrencyLevel(1).expireAfterWrite(RPC_RESPONSE_EXPIRATION, TimeUnit.MINUTES) .removalListener(REMOVAL_LISTENER).build(); adapter.setResponseCache(cache); when(channel.disconnect()).thenReturn(channelFuture); } /** * Tests {@link ConnectionAdapterImpl#consume(DataObject)} with notifications */ @Test public void testConsume() { DataObject message = new EchoRequestMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onEchoRequestMessage((EchoRequestMessage) message); message = new ErrorMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onErrorMessage((ErrorMessage) message); message = new ExperimenterMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onExperimenterMessage((ExperimenterMessage) message); message = new FlowRemovedMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onFlowRemovedMessage((FlowRemovedMessage) message); message = new HelloMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onHelloMessage((HelloMessage) message); message = new MultipartReplyMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onMultipartReplyMessage((MultipartReplyMessage) message); message = new PacketInMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onPacketInMessage((PacketInMessage) message); message = new PortStatusMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onPortStatusMessage((PortStatusMessage) message); message = new SwitchIdleEventBuilder().build(); adapter.consume(message); verify(systemListener, times(1)).onSwitchIdleEvent((SwitchIdleEvent) message); message = new DisconnectEventBuilder().build(); adapter.consume(message); verify(systemListener, times(1)).onDisconnectEvent((DisconnectEvent) message); message = new EchoRequestMessageBuilder().build(); adapter.consume(message); verify(messageListener, times(1)).onEchoRequestMessage((EchoRequestMessage) message); } /** * Tests {@link ConnectionAdapterImpl#consume(DataObject)} with unexpected rpc */ @Test public void testConsume2() { adapter.setResponseCache(mockCache); final BarrierOutputBuilder barrierBuilder = new BarrierOutputBuilder(); barrierBuilder.setXid(42L); final BarrierOutput barrier = barrierBuilder.build(); adapter.consume(barrier); verify(mockCache, times(1)).getIfPresent(any(RpcResponseKey.class)); } /** * Tests {@link ConnectionAdapterImpl#consume(DataObject)} with expected rpc */ @Test public void testConsume3() { final BarrierInputBuilder inputBuilder = new BarrierInputBuilder(); inputBuilder.setVersion((short) EncodeConstants.OF13_VERSION_ID); inputBuilder.setXid(42L); final BarrierInput barrierInput = inputBuilder.build(); final RpcResponseKey key = new RpcResponseKey(42L, "org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput"); final ResponseExpectedRpcListener<OfHeader> listener = new ResponseExpectedRpcListener<>(barrierInput, "failure", mockCache, key); cache.put(key, listener); final BarrierOutputBuilder barrierBuilder = new BarrierOutputBuilder(); barrierBuilder.setXid(42L); final BarrierOutput barrierOutput = barrierBuilder.build(); adapter.consume(barrierOutput); final ResponseExpectedRpcListener<?> ifPresent = cache.getIfPresent(key); Assert.assertNull("Listener was not discarded", ifPresent); } /** * Test IsAlive method */ @Test public void testIsAlive(){ final int port = 9876; final String host ="localhost"; final InetSocketAddress inetSockAddr = InetSocketAddress.createUnresolved(host, port); final ConnectionAdapterImpl connAddapter = new ConnectionAdapterImpl(channel, inetSockAddr, true); Assert.assertEquals("Wrong - diffrence between channel.isOpen() and ConnectionAdapterImpl.isAlive()", channel.isOpen(), connAddapter.isAlive()); connAddapter.disconnect(); Assert.assertFalse("Wrong - ConnectionAdapterImpl can not be alive after disconnet.", connAddapter.isAlive()); } /** * Test throw exception if no listeners are present */ @Test(expected = java.lang.IllegalStateException.class) public void testMissingListeners(){ final int port = 9876; final String host ="localhost"; final InetSocketAddress inetSockAddr = InetSocketAddress.createUnresolved(host, port); final ConnectionAdapterImpl connAddapter = new ConnectionAdapterImpl(channel, inetSockAddr, true); connAddapter.setSystemListener(null); connAddapter.setMessageListener(null); connAddapter.setConnectionReadyListener(null); connAddapter.checkListeners(); } }