Centralize NetconfNode/InetSocketAddress conversion 14/100814/4
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 17 May 2022 09:53:23 +0000 (11:53 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 17 May 2022 09:59:24 +0000 (11:59 +0200)
The process of creating a RemoteDeviceId and/or the target
InetSocketAddress is duplicated in a number of places, each slightly
different.

Centralize conversion in netconf.topology.spi and use it from there,
which leads us to topology-singleton being able to use non-IP addresses.

JIRA: NETCONF-875
Change-Id: I5c4a610eb4f4b3cd6586198d5e9a4b84b476d351
Signed-off-by: Rohini.Ambika <rohini.ambika@infosys.com>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtilTest.java
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtils.java [new file with mode: 0644]
netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtilsTest.java [new file with mode: 0644]

index 56a2ae5c8352fe9b2c581ad4c96627deef87d29b..0cb78da8aa5d7c7f24875a3612aa866da0023960 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
+import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
 import org.slf4j.Logger;
@@ -60,8 +61,8 @@ class NetconfTopologyContext implements ClusterSingletonService, AutoCloseable {
         this.mountService = mountService;
         this.deviceActionFactory = deviceActionFactory;
 
-        remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
-            netconfTopologyDeviceSetup.getNode().augmentation(NetconfNode.class));
+        final var node = netconfTopologyDeviceSetup.getNode();
+        remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), node.augmentation(NetconfNode.class));
         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId,
             deviceActionFactory);
         netconfNodeManager = createNodeDeviceManager();
@@ -137,8 +138,8 @@ class NetconfTopologyContext implements ClusterSingletonService, AutoCloseable {
      */
     void refresh(final @NonNull NetconfTopologySetup setup) {
         netconfTopologyDeviceSetup = requireNonNull(setup);
-        remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
-                netconfTopologyDeviceSetup.getNode().augmentation(NetconfNode.class));
+        final var node = netconfTopologyDeviceSetup.getNode();
+        remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), node.augmentation(NetconfNode.class));
 
         if (isMaster) {
             remoteDeviceConnector.stopRemoteDeviceConnection();
index 64faa511459e89bbc030efb5f87f70b7ab85a91e..0a0c04f92678469d945a2a10a3200f09438a5cd1 100644 (file)
@@ -50,6 +50,7 @@ import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonS
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup.NetconfTopologySetupBuilder;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeTopologyService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.topology.singleton.config.rev170419.Config;
@@ -179,10 +180,7 @@ public class NetconfTopologyManager
     // TODO change to a specific documented Exception when changed in ClusterSingletonServiceProvider
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void startNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
-        final NetconfNode netconfNode = node.augmentation(NetconfNode.class);
-        requireNonNull(netconfNode);
-        requireNonNull(netconfNode.getHost());
-        requireNonNull(netconfNode.getHost().getIpAddress());
+        final NetconfNode netconfNode = requireNonNull(node.augmentation(NetconfNode.class));
 
         final Timeout actorResponseWaitTime = Timeout.create(
                 Duration.ofSeconds(netconfNode.getActorResponseWaitTime().toJava()));
@@ -304,9 +302,9 @@ public class NetconfTopologyManager
 
     private NetconfTopologySetup createSetup(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
         final NetconfNode netconfNode = node.augmentation(NetconfNode.class);
-        final RemoteDeviceId deviceId = NetconfTopologyUtils.createRemoteDeviceId(node.getNodeId(), netconfNode);
+        final RemoteDeviceId deviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), netconfNode);
 
-        final NetconfTopologySetupBuilder builder = NetconfTopologySetupBuilder.create()
+        return NetconfTopologySetupBuilder.create()
                 .setClusterSingletonServiceProvider(clusterSingletonServiceProvider)
                 .setBaseSchemas(baseSchemas)
                 .setDataBroker(dataBroker)
@@ -324,8 +322,7 @@ public class NetconfTopologyManager
                 .setIdleTimeout(writeTxIdleTimeout)
                 .setPrivateKeyPath(privateKeyPath)
                 .setPrivateKeyPassphrase(privateKeyPassphrase)
-                .setEncryptionService(encryptionService);
-
-        return builder.build();
+                .setEncryptionService(encryptionService)
+                .build();
     }
 }
index 2546015548a91409c9ad446280f7d91b3bcd45dc..0de0ea6bc3d39bc6921b985382b7c66e4c1035ac 100644 (file)
@@ -53,8 +53,7 @@ import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.OdlHelloMessageCapabilities;
@@ -257,18 +256,6 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
         return Optional.of(NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined));
     }
 
-    //TODO: duplicate code
-    private static InetSocketAddress getSocketAddress(final Host host, final int port) {
-        if (host.getDomainName() != null) {
-            return new InetSocketAddress(host.getDomainName().getValue(), port);
-        } else {
-            final IpAddress ipAddress = host.getIpAddress();
-            final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() :
-                    ipAddress.getIpv6Address().getValue();
-            return new InetSocketAddress(ip, port);
-        }
-    }
-
     @VisibleForTesting
     NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
                                                            final NetconfNode node) {
@@ -286,7 +273,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
         final Decimal64 sleepFactor = node.getSleepFactor() == null
                 ? NetconfTopologyUtils.DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
 
-        final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue().toJava());
+        final InetSocketAddress socketAddress = NetconfNodeUtils.toInetSocketAddress(node);
 
         final ReconnectStrategyFactory sf =
             new TimedReconnectStrategyFactory(netconfTopologyDeviceSetup.getEventExecutor(), maxConnectionAttempts,
index e0341a94c15f45496e5479c8a671093558417df5..eba7cde7c7a7b98b10c1c9333451acb283bf4a25 100644 (file)
@@ -7,11 +7,8 @@
  */
 package org.opendaylight.netconf.topology.singleton.impl.utils;
 
-import java.net.InetSocketAddress;
 import org.opendaylight.netconf.api.DocumentedException;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
@@ -39,15 +36,7 @@ public final class NetconfTopologyUtils {
     public static final Decimal64 DEFAULT_SLEEP_FACTOR = Decimal64.valueOf("1.5");
 
     private NetconfTopologyUtils() {
-
-    }
-
-    public static RemoteDeviceId createRemoteDeviceId(final NodeId nodeId, final NetconfNode node) {
-        final IpAddress ipAddress = node.getHost().getIpAddress();
-        final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
-                ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
-                node.getPort().getValue().toJava());
-        return new RemoteDeviceId(nodeId.getValue(), address);
+        // Hidden on purpose
     }
 
     public static String createActorPath(final String masterMember, final String name) {
index 9f95da5779c1887f7d3b56a34bfc0737606ffa69..648e38b4e556b0a2fe4a98cb1dfc9b31f62f5389 100644 (file)
@@ -5,41 +5,18 @@
  * 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.topology.singleton.impl.utils;
 
 import static org.junit.Assert.assertEquals;
 
 import org.junit.Test;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.Uint16;
 
 public class NetconfTopologyUtilTest {
-
-    @Test
-    public void testCreateRemoteDeviceId() {
-        final Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
-        final NetconfNode netconfNode = new NetconfNodeBuilder().setHost(host)
-                .setPort(new PortNumber(Uint16.valueOf(9999))).build();
-        final NodeId nodeId = new NodeId("testing-node");
-        final RemoteDeviceId id = NetconfTopologyUtils.createRemoteDeviceId(nodeId, netconfNode);
-
-        assertEquals("testing-node", id.getName());
-        assertEquals(host, id.getHost());
-        assertEquals(9999, id.getAddress().getPort());
-    }
-
     @Test
     public void testCreateActorPath() {
         final String actorPath = NetconfTopologyUtils.createActorPath("member", "name");
@@ -57,5 +34,4 @@ public class NetconfTopologyUtilTest {
         assertEquals("topologyId",  NetconfTopologyUtils.createTopologyNodePath("topologyId")
                 .firstKeyOf(Topology.class).getTopologyId().getValue());
     }
-
 }
index 4f0dff3d0ba16ee3ba3af947464b2ea950e4df77..740ad3a869867a9cd5e498ce1a2605e27fcb50ea 100644 (file)
@@ -18,7 +18,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import io.netty.util.concurrent.EventExecutor;
-import java.net.InetSocketAddress;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -60,9 +59,6 @@ import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSc
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl;
 import org.opendaylight.netconf.topology.api.NetconfTopology;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev190614.NetconfNodeAugmentedOptional;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
@@ -203,17 +199,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
 
     protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
             final NetconfNodeAugmentedOptional nodeOptional) {
-        final Host host = node.getHost();
-        final IpAddress ipAddress = host.getIpAddress();
-        final InetSocketAddress address;
-        if (ipAddress != null) {
-            address = new InetSocketAddress(IetfInetUtil.INSTANCE.inetAddressFor(ipAddress),
-                    node.getPort().getValue().toJava());
-        } else {
-            address = new InetSocketAddress(host.getDomainName().getValue(),
-                    node.getPort().getValue().toJava());
-        }
-        final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
+        final RemoteDeviceId remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(nodeId, node);
 
         final long keepaliveDelay = node.requireKeepaliveDelay().toJava();
         RemoteDeviceHandler<NetconfSessionPreferences> salFacade = createSalFacade(remoteDeviceId);
@@ -264,7 +250,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
         return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade, yanglibRegistrations);
     }
 
-    private List<SchemaSourceRegistration<?>> registerDeviceSchemaSources(final RemoteDeviceId remoteDeviceId,
+    private static List<SchemaSourceRegistration<?>> registerDeviceSchemaSources(final RemoteDeviceId remoteDeviceId,
             final NetconfNode node, final SchemaResourcesDTO resources) {
         final YangLibrary yangLibrary = node.getYangLibrary();
         if (yangLibrary != null) {
@@ -340,7 +326,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
         }
 
         return reconnectingClientConfigurationBuilder
-                .withAddress(getSocketAddress(node.getHost(), node.getPort().getValue().toJava()))
+                .withAddress(NetconfNodeUtils.toInetSocketAddress(node))
                 .withConnectionTimeoutMillis(node.requireConnectionTimeoutMillis().toJava())
                 .withReconnectStrategy(sf.createReconnectStrategy())
                 .withConnectStrategyFactory(sf)
@@ -377,17 +363,6 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
 
     protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
 
-    private static InetSocketAddress getSocketAddress(final Host host, final int port) {
-        if (host.getDomainName() != null) {
-            return new InetSocketAddress(host.getDomainName().getValue(), port);
-        }
-
-        final IpAddress ipAddress = host.getIpAddress();
-        final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue()
-                : ipAddress.getIpv6Address().getValue();
-        return new InetSocketAddress(ip, port);
-    }
-
     private static Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
         // if none of yang-module-capabilities or non-module-capabilities is specified
         // just return absent
diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtils.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtils.java
new file mode 100644 (file)
index 0000000..085680f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 PANTHEON.tech, 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.netconf.topology.spi;
+
+import java.net.InetSocketAddress;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+
+/**
+ * Utility methods to work with {@link NetconfNode} information.
+ */
+public final class NetconfNodeUtils {
+    private NetconfNodeUtils() {
+        // Hidden on purpose
+    }
+
+    public static @NonNull InetSocketAddress toInetSocketAddress(final NetconfNode node) {
+        final Host host = node.requireHost();
+        final int port = node.requirePort().getValue().toJava();
+        final IpAddress ipAddress = host.getIpAddress();
+        return ipAddress != null ? new InetSocketAddress(IetfInetUtil.INSTANCE.inetAddressFor(ipAddress), port)
+            : new InetSocketAddress(host.getDomainName().getValue(), port);
+    }
+
+    public static @NonNull RemoteDeviceId toRemoteDeviceId(final NodeId nodeId, final NetconfNode node) {
+        return new RemoteDeviceId(nodeId.getValue(), toInetSocketAddress(node));
+    }
+}
diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtilsTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeUtilsTest.java
new file mode 100644 (file)
index 0000000..a779f69
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 PANTHEON.tech, 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.netconf.topology.spi;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.common.Uint16;
+
+public class NetconfNodeUtilsTest {
+    @Test
+    public void testCreateRemoteDeviceId() {
+        final Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
+        final RemoteDeviceId id = NetconfNodeUtils.toRemoteDeviceId(new NodeId("testing-node"), new NetconfNodeBuilder()
+            .setHost(host)
+            .setPort(new PortNumber(Uint16.valueOf(9999)))
+            .build());
+
+        assertEquals("testing-node", id.getName());
+        assertEquals(host, id.getHost());
+        assertEquals(9999, id.getAddress().getPort());
+    }
+}