NETCONF-539: use netconf namespace in base:1.1 capability check 98/71298/2
authorMarek Gradzki <mgradzki@cisco.com>
Wed, 25 Apr 2018 07:32:57 +0000 (09:32 +0200)
committerMarek Gradzki <mgradzki@cisco.com>
Thu, 26 Apr 2018 12:10:43 +0000 (14:10 +0200)
Use Document.getElementsByTagNameNSgetElementsByTagNameNS
with urn:ietf:params:xml:ns:netconf:base:1.0 namespace

instead of getElementsByTagName

to support clients using namespace prefixes in the hello message.

Change-Id: I333bb4522aca566b74db3e4411be1c90ec419aec
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
netconf/netconf-netty-util/pom.xml
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiator.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java [new file with mode: 0644]
netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1.xml [new file with mode: 0644]
netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1_ns.xml [new file with mode: 0644]

index d3dca9abdff528fa70cd93a9e8386e9dc1b08625..eb338a674999eca6caa3f90448bd28d8fb7f798c 100644 (file)
       <artifactId>aaa-encrypt-service</artifactId>
       <version>0.8.0-SNAPSHOT</version>
     </dependency>
+
+    <!-- test dependencies -->
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-util</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
index 30b81146040c8818bc8bf567a18007f642c48f1a..4135896b34d28361a4a9fd6f19d6e09864fccdcc 100644 (file)
@@ -248,7 +248,9 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
     }
 
     private static boolean containsBase11Capability(final Document doc) {
-        final NodeList nList = doc.getElementsByTagName(XmlNetconfConstants.CAPABILITY);
+        final NodeList nList = doc.getElementsByTagNameNS(
+            XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0,
+            XmlNetconfConstants.CAPABILITY);
         for (int i = 0; i < nList.getLength(); i++) {
             if (nList.item(i).getTextContent().contains(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1)) {
                 return true;
diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java
new file mode 100644 (file)
index 0000000..53fe8e6
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 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.Mockito.doReturn;
+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.channel.Channel;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.embedded.EmbeddedChannel;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
+import java.util.Collections;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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.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;
+import org.opendaylight.netconf.util.test.XmlFileLoader;
+import org.w3c.dom.Document;
+
+public class Netconf539Test {
+    @Mock
+    private NetconfSessionListener<TestingNetconfSession> listener;
+    @Mock
+    private Promise<TestingNetconfSession> promise;
+
+    private EmbeddedChannel channel;
+    private AbstractNetconfSessionNegotiator negotiator;
+    private NetconfSessionPreferences prefs;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        channel = new EmbeddedChannel();
+        channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER,
+            new ChannelInboundHandlerAdapter());
+        channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER,
+            new NetconfXMLToHelloMessageDecoder());
+        channel.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER,
+            FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+        channel.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator());
+        final NetconfHelloMessage serverHello = NetconfHelloMessage.createClientHello(Collections
+            .singleton(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1), Optional.absent());
+        doReturn(promise).when(promise).setFailure(any());
+        doReturn(promise).when(promise).setSuccess(any());
+        negotiator = new TestSessionNegotiator(new NetconfSessionPreferences(serverHello), promise, channel,
+            new HashedWheelTimer(), listener, 100L);
+    }
+
+    @Test
+    public void testGetSessionForHelloMessageDefaultNs() throws Exception {
+        testGetSessionForHelloMessage("netconf539/client_hello_1.1.xml");
+    }
+
+    @Test
+    public void testGetSessionForHelloMessageNsPrefix() throws Exception {
+        testGetSessionForHelloMessage("netconf539/client_hello_1.1_ns.xml");
+    }
+
+    private void testGetSessionForHelloMessage(final String fileName) throws Exception {
+        final Document helloDocument = XmlFileLoader.xmlFileToDocument(fileName);
+        negotiator.startNegotiation();
+        final NetconfHelloMessage helloMessage = new NetconfHelloMessage(helloDocument);
+        final AbstractNetconfSession session = negotiator.getSessionForHelloMessage(helloMessage);
+        Assert.assertNotNull(session);
+        Assert.assertTrue("NetconfChunkAggregator was not installed in the Netconf pipeline",
+            channel.pipeline().get(NETCONF_MESSAGE_AGGREGATOR) instanceof NetconfChunkAggregator);
+        Assert.assertTrue("ChunkedFramingMechanismEncoder was not installed in the Netconf pipeline",
+            channel.pipeline().get(NETCONF_MESSAGE_FRAME_ENCODER) instanceof ChunkedFramingMechanismEncoder);
+    }
+
+    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
diff --git a/netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1.xml b/netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1.xml
new file mode 100644 (file)
index 0000000..8c43f33
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2018 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
+  -->
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <capabilities>
+        <capability>urn:ietf:params:netconf:base:1.1</capability>
+    </capabilities>
+</hello>
\ No newline at end of file
diff --git a/netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1_ns.xml b/netconf/netconf-netty-util/src/test/resources/netconf539/client_hello_1.1_ns.xml
new file mode 100644 (file)
index 0000000..8a2d347
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2018 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
+  -->
+<nc:hello xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <nc:capabilities>
+        <nc:capability>urn:ietf:params:netconf:base:1.1</nc:capability>
+    </nc:capabilities>
+</nc:hello>
\ No newline at end of file