Add netconf-netty-util tests 74/47474/1
authorAndrej Mak <andrej.mak@pantheon.tech>
Fri, 21 Oct 2016 12:41:09 +0000 (14:41 +0200)
committerAndrej Mak <andrej.mak@pantheon.tech>
Tue, 25 Oct 2016 06:56:12 +0000 (08:56 +0200)
Change-Id: I34adb433d6e078f3c95fd4a1516d44ce8ee0463a
Signed-off-by: Andrej Mak <andrej.mak@pantheon.tech>
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ThreadLocalTransformers.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java [new file with mode: 0644]
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionTest.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestingNetconfSession.java [new file with mode: 0644]
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/handler/ThreadLocalTransformersTest.java [new file with mode: 0644]

index b8161f0bc1c1af6da7a6134a4466638688d21786..35146e1f1029a5cec4e6b334a26b7ef0e273759f 100644 (file)
@@ -22,39 +22,28 @@ final class ThreadLocalTransformers {
     private static final ThreadLocal<Transformer> DEFAULT_TRANSFORMER = new ThreadLocal<Transformer>() {
         @Override
         protected Transformer initialValue() {
-            try {
-                return FACTORY.newTransformer();
-            } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
-                throw new IllegalStateException("Unexpected error while instantiating a Transformer", e);
-            }
-        };
+            return createTransformer();
+        }
 
         @Override
         public void set(final Transformer value) {
             throw new UnsupportedOperationException();
-        };
+        }
     };
 
     private static final ThreadLocal<Transformer> PRETTY_TRANSFORMER = new ThreadLocal<Transformer>() {
         @Override
         protected Transformer initialValue() {
-            final Transformer ret;
-
-            try {
-                ret = FACTORY.newTransformer();
-            } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
-                throw new IllegalStateException("Unexpected error while instantiating a Transformer", e);
-            }
-
+            final Transformer ret = createTransformer();
             ret.setOutputProperty(OutputKeys.INDENT, "yes");
             ret.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
             return ret;
-        };
+        }
 
         @Override
         public void set(final Transformer value) {
             throw new UnsupportedOperationException();
-        };
+        }
     };
 
     private ThreadLocalTransformers() {
@@ -66,7 +55,7 @@ final class ThreadLocalTransformers {
      *
      * @return A transformer with default configuration based on the default implementation.
      */
-    public static Transformer getDefaultTransformer() {
+    static Transformer getDefaultTransformer() {
         return DEFAULT_TRANSFORMER.get();
     }
 
@@ -76,7 +65,15 @@ final class ThreadLocalTransformers {
      *
      * @return A transformer with human-friendly configuration.
      */
-    public static Transformer getPrettyTransformer() {
+    static Transformer getPrettyTransformer() {
         return PRETTY_TRANSFORMER.get();
     }
+
+    private static Transformer createTransformer() {
+        try {
+            return FACTORY.newTransformer();
+        } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
+            throw new IllegalStateException("Unexpected error while instantiating a Transformer", e);
+        }
+    }
 }
diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java
new file mode 100644 (file)
index 0000000..4da5b2c
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, 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.netconf.nettyutil;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR;
+import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER;
+
+import com.google.common.base.Optional;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelOutboundHandler;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.embedded.EmbeddedChannel;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.Promise;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
+import org.opendaylight.netconf.api.NetconfSessionListener;
+import org.opendaylight.netconf.api.NetconfSessionPreferences;
+import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
+import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
+import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder;
+import org.opendaylight.netconf.nettyutil.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
+import org.opendaylight.netconf.nettyutil.handler.NetconfEOMAggregator;
+import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder;
+import org.opendaylight.netconf.util.messages.FramingMechanism;
+
+public class AbstractNetconfSessionNegotiatorTest {
+
+    @Mock
+    private NetconfSessionListener<TestingNetconfSession> listener;
+    @Mock
+    private Promise<TestingNetconfSession> promise;
+    @Mock
+    private SslHandler sslHandler;
+    private EmbeddedChannel channel;
+    private AbstractNetconfSessionNegotiator negotiator;
+    private NetconfHelloMessage hello;
+    private NetconfHelloMessage helloBase11;
+    private NetconfXMLToHelloMessageDecoder xmlToHello;
+    private NetconfSessionPreferences prefs;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        channel = new EmbeddedChannel();
+        xmlToHello = new NetconfXMLToHelloMessageDecoder();
+        channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, new ChannelInboundHandlerAdapter());
+        channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, xmlToHello);
+        channel.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+        channel.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator());
+        hello = NetconfHelloMessage.createClientHello(Collections.emptySet(), Optional.absent());
+        helloBase11 = NetconfHelloMessage.createClientHello(Collections.singleton(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1), Optional.absent());
+        prefs = new NetconfSessionPreferences(helloBase11);
+        doReturn(promise).when(promise).setFailure(any());
+        doReturn(promise).when(promise).setSuccess(any());
+        negotiator = new TestSessionNegotiator(prefs, promise, channel, new HashedWheelTimer(), listener, 100L);
+    }
+
+    @Test
+    public void testStartNegotiation() throws Exception {
+        negotiator.startNegotiation();
+        Assert.assertEquals(helloBase11, channel.readOutbound());
+    }
+
+    @Test
+    public void testStartNegotiationSsl() throws Exception {
+        doReturn(true).when(sslHandler).isSharable();
+        doNothing().when(sslHandler).handlerAdded(any());
+        doNothing().when(sslHandler).write(any(), any(), any());
+        final Future<EmbeddedChannel> handshakeFuture = channel.eventLoop().newSucceededFuture(channel);
+        doReturn(handshakeFuture).when(sslHandler).handshakeFuture();
+        channel.pipeline().addLast(sslHandler);
+        negotiator.startNegotiation();
+        verify(sslHandler, timeout(1000)).write(any(), eq(helloBase11), any());
+
+    }
+
+    @Test
+    public void testStartNegotiationNotEstablished() throws Exception {
+        final ChannelOutboundHandler closedDetector = Mockito.spy(new ChannelOutboundHandlerAdapter());
+        channel.pipeline().addLast("closedDetector", closedDetector);
+        doReturn(false).when(promise).isDone();
+        doReturn(false).when(promise).isCancelled();
+        negotiator.startNegotiation();
+        verify(closedDetector, timeout(2000)).close(any(), any());
+    }
+
+    @Test
+    public void testGetSessionPreferences() throws Exception {
+        Assert.assertEquals(prefs, negotiator.getSessionPreferences());
+    }
+
+    @Test
+    public void testGetSessionForHelloMessage() throws Exception {
+        negotiator.startNegotiation();
+        final AbstractNetconfSession session = negotiator.getSessionForHelloMessage(hello);
+        Assert.assertNotNull(session);
+        Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_AGGREGATOR) instanceof NetconfEOMAggregator);
+        Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_FRAME_ENCODER) instanceof EOMFramingMechanismEncoder);
+    }
+
+    @Test
+    public void testGetSessionForHelloMessageBase11() throws Exception {
+        negotiator.startNegotiation();
+        final AbstractNetconfSession session = negotiator.getSessionForHelloMessage(helloBase11);
+        Assert.assertNotNull(session);
+        Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_AGGREGATOR) instanceof NetconfChunkAggregator);
+        Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_FRAME_ENCODER) instanceof ChunkedFramingMechanismEncoder);
+    }
+
+    @Test
+    public void testReplaceHelloMessageInboundHandler() throws Exception {
+        final List<Object> out = new ArrayList<>();
+        final byte[] msg = "<rpc/>".getBytes();
+        final ByteBuf msgBuf = Unpooled.wrappedBuffer(msg);
+        final ByteBuf helloBuf = Unpooled.wrappedBuffer(XmlUtil.toString(hello.getDocument()).getBytes());
+        negotiator.startNegotiation();
+        xmlToHello.decode(null, helloBuf, out);
+        xmlToHello.decode(null, msgBuf, out);
+        final AbstractNetconfSession session = mock(AbstractNetconfSession.class);
+        doNothing().when(session).handleMessage(any());
+        negotiator.replaceHelloMessageInboundHandler(session);
+        verify(session, times(1)).handleMessage(any());
+    }
+
+    @Test
+    public void testNegotiationFail() throws Exception {
+        negotiator.startNegotiation();
+        final RuntimeException cause = new RuntimeException("failure cause");
+        channel.pipeline().fireExceptionCaught(cause);
+        verify(promise).setFailure(cause);
+    }
+
+    private static class TestSessionNegotiator extends
+            AbstractNetconfSessionNegotiator<NetconfSessionPreferences,
+                    TestingNetconfSession, NetconfSessionListener<TestingNetconfSession>> {
+
+
+        TestSessionNegotiator(final NetconfSessionPreferences sessionPreferences,
+                              final Promise<TestingNetconfSession> promise, final Channel channel,
+                              final Timer timer,
+                              final NetconfSessionListener<TestingNetconfSession> sessionListener,
+                              final long connectionTimeoutMillis) {
+            super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
+        }
+
+        @Override
+        protected TestingNetconfSession getSession(final NetconfSessionListener sessionListener, final Channel channel,
+                                                   final NetconfHelloMessage message) throws NetconfDocumentedException {
+            return new TestingNetconfSession(sessionListener, channel, 0L);
+        }
+
+        @Override
+        protected void handleMessage(final NetconfHelloMessage netconfHelloMessage) throws Exception {
+
+        }
+    }
+
+
+}
\ No newline at end of file
index 5c2bb755b1befe22128f1e901b752476724a5b9e..8edfca9296bb7df336415822dc5622e6fd5af912 100644 (file)
@@ -38,18 +38,17 @@ import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.api.NetconfSession;
 import org.opendaylight.netconf.api.NetconfSessionListener;
 import org.opendaylight.netconf.api.NetconfTerminationReason;
-import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.openexi.proc.common.EXIOptions;
 
 public class AbstractNetconfSessionTest {
 
     @Mock
-    private NetconfSessionListener<NetconfSession> listener;
+    private NetconfSessionListener<TestingNetconfSession> listener;
     @Mock
     private Channel channel;
     @Mock
@@ -64,10 +63,10 @@ public class AbstractNetconfSessionTest {
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        doNothing().when(listener).onMessage(any(NetconfSession.class), any(NetconfMessage.class));
-        doNothing().when(listener).onSessionUp(any(NetconfSession.class));
-        doNothing().when(listener).onSessionDown(any(NetconfSession.class), any(Exception.class));
-        doNothing().when(listener).onSessionTerminated(any(NetconfSession.class), any(NetconfTerminationReason.class));
+        doNothing().when(listener).onMessage(any(TestingNetconfSession.class), any(NetconfMessage.class));
+        doNothing().when(listener).onSessionUp(any(TestingNetconfSession.class));
+        doNothing().when(listener).onSessionDown(any(TestingNetconfSession.class), any(Exception.class));
+        doNothing().when(listener).onSessionTerminated(any(TestingNetconfSession.class), any(NetconfTerminationReason.class));
 
         doReturn(writeFuture).when(writeFuture).addListener(any(GenericFutureListener.class));
 
@@ -81,7 +80,7 @@ public class AbstractNetconfSessionTest {
         doReturn(eventLoop).when(channel).eventLoop();
         doAnswer(new Answer<Void>() {
             @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
+            public Void answer(final InvocationOnMock invocation) throws Throwable {
                 final Object[] args = invocation.getArguments();
                 final Runnable runnable = (Runnable) args[0];
                 runnable.run();
@@ -113,7 +112,7 @@ public class AbstractNetconfSessionTest {
         testingNetconfSession.sessionUp();
         testingNetconfSession.close();
         verify(channel).close();
-        verify(listener).onSessionTerminated(any(NetconfSession.class), any(NetconfTerminationReason.class));
+        verify(listener).onSessionTerminated(any(TestingNetconfSession.class), any(NetconfTerminationReason.class));
     }
 
     @Test
@@ -149,7 +148,7 @@ public class AbstractNetconfSessionTest {
         verifyZeroInteractions(listener);
         testingNetconfSession.sessionUp();
         testingNetconfSession.endOfInput();
-        verify(listener).onSessionDown(any(NetconfSession.class), any(Exception.class));
+        verify(listener).onSessionDown(any(TestingNetconfSession.class), any(Exception.class));
     }
 
     @Test
@@ -160,21 +159,4 @@ public class AbstractNetconfSessionTest {
         verify(channel).writeAndFlush(clientHello);
     }
 
-    private static class TestingNetconfSession extends AbstractNetconfSession<NetconfSession, NetconfSessionListener<NetconfSession>> {
-
-        protected TestingNetconfSession(final NetconfSessionListener<NetconfSession> sessionListener, final Channel channel, final long sessionId) {
-            super(sessionListener, channel, sessionId);
-        }
-
-        @Override
-        protected NetconfSession thisInstance() {
-            return this;
-        }
-
-        @Override
-        protected void addExiHandlers(final ByteToMessageDecoder decoder, final MessageToByteEncoder<NetconfMessage> encoder) {}
-
-        @Override
-        public void stopExiCommunication() {}
-    }
 }
\ No newline at end of file
diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestingNetconfSession.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestingNetconfSession.java
new file mode 100644 (file)
index 0000000..b7a1c6c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, 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.netconf.nettyutil;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.codec.MessageToByteEncoder;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.api.NetconfSessionListener;
+
+class TestingNetconfSession extends AbstractNetconfSession<TestingNetconfSession, NetconfSessionListener<TestingNetconfSession>> {
+
+    TestingNetconfSession(final NetconfSessionListener<TestingNetconfSession> sessionListener, final Channel channel, final long sessionId) {
+        super(sessionListener, channel, sessionId);
+    }
+
+    @Override
+    protected TestingNetconfSession thisInstance() {
+        return this;
+    }
+
+    @Override
+    protected void addExiHandlers(final ByteToMessageDecoder decoder, final MessageToByteEncoder<NetconfMessage> encoder) {
+    }
+
+    @Override
+    public void stopExiCommunication() {
+    }
+}
diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/handler/ThreadLocalTransformersTest.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/handler/ThreadLocalTransformersTest.java
new file mode 100644 (file)
index 0000000..456663b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, 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.netconf.nettyutil.handler;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import javax.xml.transform.Transformer;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ThreadLocalTransformersTest {
+
+    private ExecutorService executorService;
+
+    @Before
+    public void setUp() throws Exception {
+        executorService = Executors.newSingleThreadExecutor();
+    }
+
+    @Test
+    public void testGetDefaultTransformer() throws Exception {
+        final Transformer t1 = ThreadLocalTransformers.getDefaultTransformer();
+        final Transformer t2 = ThreadLocalTransformers.getDefaultTransformer();
+        Assert.assertSame(t1, t2);
+        final Future<Transformer> future = executorService.submit(ThreadLocalTransformers::getDefaultTransformer);
+        Assert.assertNotSame(t1, future.get());
+    }
+
+    @Test
+    public void testGetPrettyTransformer() throws Exception {
+        final Transformer t1 = ThreadLocalTransformers.getPrettyTransformer();
+        final Transformer t2 = ThreadLocalTransformers.getPrettyTransformer();
+        Assert.assertSame(t1, t2);
+        final Future<Transformer> future = executorService.submit(ThreadLocalTransformers::getPrettyTransformer);
+        Assert.assertNotSame(t1, future.get());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        executorService.shutdown();
+    }
+}
\ No newline at end of file