package org.opendaylight.controller.sal.connect.netconf.listener;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
-
+import io.netty.util.concurrent.GlobalEventExecutor;
import java.io.ByteArrayInputStream;
+import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
-
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.sal.connect.api.RemoteDevice;
-import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.ListenableFuture;
-
public class NetconfDeviceCommunicatorTest {
@Mock
NetconfClientSession mockSession;
@Mock
- RemoteDevice<NetconfSessionCapabilities, NetconfMessage> mockDevice;
+ RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> mockDevice;
NetconfDeviceCommunicator communicator;
public void setUp() throws Exception {
MockitoAnnotations.initMocks( this );
- communicator = new NetconfDeviceCommunicator( new RemoteDeviceId( "test" ), mockDevice );
+ communicator = new NetconfDeviceCommunicator( new RemoteDeviceId( "test" ), mockDevice);
}
@SuppressWarnings("unchecked")
- void setupSession()
- {
- doReturn( Collections.<String>emptySet() ).when( mockSession ).getServerCapabilities();
- doNothing().when( mockDevice ).onRemoteSessionUp( any( NetconfSessionCapabilities.class ),
- any( RemoteDeviceCommunicator.class ) );
- communicator.onSessionUp( mockSession );
+ void setupSession() {
+ doReturn(Collections.<String>emptySet()).when(mockSession).getServerCapabilities();
+ doNothing().when(mockDevice).onRemoteSessionUp(any(NetconfSessionPreferences.class),
+ any(NetconfDeviceCommunicator.class));
+ communicator.onSessionUp(mockSession);
}
private ListenableFuture<RpcResult<NetconfMessage>> sendRequest() throws Exception {
testCapability );
doReturn( serverCapabilities ).when( mockSession ).getServerCapabilities();
- ArgumentCaptor<NetconfSessionCapabilities> netconfSessionCapabilities =
- ArgumentCaptor.forClass( NetconfSessionCapabilities.class );
- doNothing().when( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+ ArgumentCaptor<NetconfSessionPreferences> NetconfSessionPreferences =
+ ArgumentCaptor.forClass( NetconfSessionPreferences.class );
+ doNothing().when( mockDevice ).onRemoteSessionUp( NetconfSessionPreferences.capture(), eq( communicator ) );
communicator.onSessionUp( mockSession );
verify( mockSession ).getServerCapabilities();
- verify( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+ verify( mockDevice ).onRemoteSessionUp( NetconfSessionPreferences.capture(), eq( communicator ) );
- NetconfSessionCapabilities actualCapabilites = netconfSessionCapabilities.getValue();
- assertEquals( "containsCapability", true, actualCapabilites.containsCapability(
- NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString() ) );
- assertEquals( "containsCapability", true, actualCapabilites.containsCapability( testCapability ) );
+ NetconfSessionPreferences actualCapabilites = NetconfSessionPreferences.getValue();
+ assertEquals( "containsModuleCapability", true, actualCapabilites.containsNonModuleCapability(
+ NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString()) );
+ assertEquals( "containsModuleCapability", false, actualCapabilites.containsNonModuleCapability(testCapability) );
assertEquals( "getModuleBasedCaps", Sets.newHashSet(
QName.create( "urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module" )),
actualCapabilites.getModuleBasedCaps() );
errorInfo.contains( "<bad-element>bar</bad-element>" ) );
}
+ /**
+ * Test whether reconnect is scheduled properly
+ */
+ @Test
+ public void testNetconfDeviceReconnectInCommunicator() throws Exception {
+ final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device = mock(RemoteDevice.class);
+
+ final TimedReconnectStrategy timedReconnectStrategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, 10000, 0, 1.0, null, 100L, null);
+ final ReconnectStrategy reconnectStrategy = spy(new ReconnectStrategy() {
+ @Override
+ public int getConnectTimeout() throws Exception {
+ return timedReconnectStrategy.getConnectTimeout();
+ }
+
+ @Override
+ public Future<Void> scheduleReconnect(final Throwable cause) {
+ return timedReconnectStrategy.scheduleReconnect(cause);
+ }
+
+ @Override
+ public void reconnectSuccessful() {
+ timedReconnectStrategy.reconnectSuccessful();
+ }
+ });
+
+ final EventLoopGroup group = new NioEventLoopGroup();
+ final Timer time = new HashedWheelTimer();
+ try {
+ final NetconfDeviceCommunicator listener = new NetconfDeviceCommunicator(new RemoteDeviceId("test"), device);
+ final NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
+ .withAddress(new InetSocketAddress("localhost", 65000))
+ .withReconnectStrategy(reconnectStrategy)
+ .withConnectStrategyFactory(new ReconnectStrategyFactory() {
+ @Override
+ public ReconnectStrategy createReconnectStrategy() {
+ return reconnectStrategy;
+ }
+ })
+ .withAuthHandler(new LoginPassword("admin", "admin"))
+ .withConnectionTimeoutMillis(10000)
+ .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .withSessionListener(listener)
+ .build();
+
+ listener.initializeRemoteConnection(new NetconfClientDispatcherImpl(group, group, time), cfg);
+
+ verify(reconnectStrategy, timeout((int) TimeUnit.MINUTES.toMillis(3)).times(101)).scheduleReconnect(any(Throwable.class));
+ } finally {
+ time.stop();
+ group.shutdownGracefully();
+ }
+ }
+
@Test
public void testOnResponseMessageWithWrongMessageID() throws Exception {
setupSession();