2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.topology.impl;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.mockito.ArgumentMatchers.any;
16 import static org.mockito.Mockito.doNothing;
17 import static org.mockito.Mockito.doReturn;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.spy;
20 import static org.mockito.Mockito.times;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.when;
23 import static org.opendaylight.mdsal.common.api.CommitInfo.emptyFluentFuture;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.MoreExecutors;
28 import io.netty.util.concurrent.EventExecutor;
29 import java.util.Collection;
30 import java.util.HashSet;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.Mock;
35 import org.mockito.junit.MockitoJUnitRunner;
36 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
37 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
38 import org.opendaylight.controller.config.threadpool.ThreadPool;
39 import org.opendaylight.mdsal.binding.api.DataBroker;
40 import org.opendaylight.mdsal.binding.api.DataObjectModification;
41 import org.opendaylight.mdsal.binding.api.DataTreeModification;
42 import org.opendaylight.mdsal.binding.api.RpcProviderService;
43 import org.opendaylight.mdsal.binding.api.WriteTransaction;
44 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
45 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
46 import org.opendaylight.netconf.client.NetconfClientDispatcher;
47 import org.opendaylight.netconf.client.NetconfClientSessionListener;
48 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
49 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
50 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
51 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
52 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
53 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.DefaultBaseNetconfSchemas;
54 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol.Name;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.ProtocolBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
74 import org.opendaylight.yangtools.yang.binding.DataObject;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
78 import org.opendaylight.yangtools.yang.common.Uint16;
79 import org.opendaylight.yangtools.yang.common.Uint32;
80 import org.opendaylight.yangtools.yang.parser.api.YangParserException;
81 import org.opendaylight.yangtools.yang.parser.impl.DefaultYangParserFactory;
83 @RunWith(MockitoJUnitRunner.StrictStubs.class)
84 public class NetconfTopologyImplTest {
86 private static final NodeId NODE_ID = new NodeId("testing-node");
87 private static final String TOPOLOGY_ID = "testing-topology";
90 private NetconfClientDispatcher mockedClientDispatcher;
93 private EventExecutor mockedEventExecutor;
96 private ScheduledThreadPool mockedKeepaliveExecutor;
99 private ThreadPool mockedProcessingExecutor;
102 private SchemaResourceManager mockedResourceManager;
105 private DataBroker dataBroker;
108 private DOMMountPointService mountPointService;
111 private AAAEncryptionService encryptionService;
114 private RpcProviderService rpcProviderService;
116 private TestingNetconfTopologyImpl topology;
117 private TestingNetconfTopologyImpl spyTopology;
120 public void setUp() {
121 when(mockedProcessingExecutor.getExecutor()).thenReturn(MoreExecutors.newDirectExecutorService());
123 topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher, mockedEventExecutor,
124 mockedKeepaliveExecutor, mockedProcessingExecutor, mockedResourceManager, dataBroker, mountPointService,
125 encryptionService, rpcProviderService);
127 spyTopology = spy(topology);
131 public void testInit() {
132 final WriteTransaction wtx = mock(WriteTransaction.class);
133 when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
134 doNothing().when(wtx)
135 .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
136 doReturn(emptyFluentFuture()).when(wtx).commit();
139 //verify initialization of topology
140 final InstanceIdentifier<NetworkTopology> networkTopologyId =
141 InstanceIdentifier.builder(NetworkTopology.class).build();
142 final Topology topo = new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build();
143 final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
144 verify(wtx).merge(LogicalDatastoreType.CONFIGURATION, networkTopologyId, networkTopology);
145 verify(wtx).merge(LogicalDatastoreType.OPERATIONAL, networkTopologyId, networkTopology);
146 verify(wtx).merge(LogicalDatastoreType.CONFIGURATION,
147 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))), topo);
148 verify(wtx).merge(LogicalDatastoreType.OPERATIONAL,
149 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))), topo);
153 public void testOnDataTreeChange() {
155 final DataObjectModification<Node> newNode = mock(DataObjectModification.class);
156 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
158 NodeKey key = new NodeKey(NODE_ID);
159 PathArgument pa = IdentifiableItem.of(Node.class, key);
160 when(newNode.getIdentifier()).thenReturn(pa);
162 final NodeBuilder nn = new NodeBuilder()
164 .addAugmentation(new NetconfNodeBuilder()
165 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
166 .setPort(new PortNumber(Uint16.valueOf(9999)))
167 .setReconnectOnChangedSchema(true)
168 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
169 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
170 .setKeepaliveDelay(Uint32.valueOf(1000))
172 .setCredentials(new LoginPasswordBuilder()
173 .setUsername("testuser")
174 .setPassword("testpassword")
178 when(newNode.getDataAfter()).thenReturn(nn.build());
181 final Collection<DataTreeModification<Node>> changes = new HashSet<>();
182 final DataTreeModification<Node> ch = mock(DataTreeModification.class);
183 when(ch.getRootNode()).thenReturn(newNode);
185 spyTopology.onDataTreeChanged(changes);
186 verify(spyTopology).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
188 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
189 spyTopology.onDataTreeChanged(changes);
190 verify(spyTopology).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
192 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
193 spyTopology.onDataTreeChanged(changes);
195 //one in previous creating and deleting node and one in updating
196 verify(spyTopology, times(2)).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
197 verify(spyTopology, times(2)).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
203 public void testGetClientConfig() {
204 final NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
206 final NetconfNode testingNode = new NetconfNodeBuilder()
207 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
208 .setPort(new PortNumber(Uint16.valueOf(9999)))
209 .setReconnectOnChangedSchema(true)
210 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
211 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
212 .setKeepaliveDelay(Uint32.valueOf(1000))
214 .setCredentials(new LoginPasswordBuilder()
215 .setUsername("testuser").setPassword("testpassword").build())
217 final NetconfReconnectingClientConfiguration configuration =
218 spyTopology.getClientConfig(sessionListener, testingNode);
219 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TCP, configuration.getProtocol());
220 assertNotNull(configuration.getAuthHandler());
221 assertNull(configuration.getSslHandlerFactory());
224 final NetconfNode testingNode2 = new NetconfNodeBuilder()
225 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
226 .setPort(new PortNumber(Uint16.valueOf(9999)))
227 .setReconnectOnChangedSchema(true)
228 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
229 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
230 .setKeepaliveDelay(Uint32.valueOf(1000))
232 .setCredentials(new LoginPasswordBuilder()
233 .setUsername("testuser").setPassword("testpassword").build())
235 final NetconfReconnectingClientConfiguration configuration2 =
236 spyTopology.getClientConfig(sessionListener, testingNode2);
237 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration2.getProtocol());
238 assertNotNull(configuration2.getAuthHandler());
239 assertNull(configuration2.getSslHandlerFactory());
242 final NetconfNode testingNode3 = new NetconfNodeBuilder()
243 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
244 .setPort(new PortNumber(Uint16.valueOf(9999)))
245 .setReconnectOnChangedSchema(true)
246 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
247 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
248 .setKeepaliveDelay(Uint32.valueOf(1000))
250 .setProtocol(new ProtocolBuilder().setName(Name.SSH).build())
251 .setCredentials(new LoginPasswordBuilder()
252 .setUsername("testuser").setPassword("testpassword").build())
254 final NetconfReconnectingClientConfiguration configuration3 =
255 spyTopology.getClientConfig(sessionListener, testingNode3);
256 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration3.getProtocol());
257 assertNotNull(configuration3.getAuthHandler());
258 assertNull(configuration3.getSslHandlerFactory());
261 final NetconfNode testingNode4 = new NetconfNodeBuilder()
262 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
263 .setPort(new PortNumber(Uint16.valueOf(9999)))
264 .setReconnectOnChangedSchema(true)
265 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
266 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
267 .setKeepaliveDelay(Uint32.valueOf(1000))
269 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build())
270 .setCredentials(new LoginPasswordBuilder()
271 .setUsername("testuser").setPassword("testpassword").build())
273 final NetconfReconnectingClientConfiguration configuration4 =
274 spyTopology.getClientConfig(sessionListener, testingNode4);
275 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, configuration4.getProtocol());
276 assertNull(configuration4.getAuthHandler());
277 assertNotNull(configuration4.getSslHandlerFactory());
280 public static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
281 private static final BaseNetconfSchemas BASE_SCHEMAS;
285 BASE_SCHEMAS = new DefaultBaseNetconfSchemas(new DefaultYangParserFactory());
286 } catch (YangParserException e) {
287 throw new ExceptionInInitializerError(e);
291 public TestingNetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
292 final EventExecutor eventExecutor,
293 final ScheduledThreadPool keepaliveExecutor,
294 final ThreadPool processingExecutor,
295 final SchemaResourceManager schemaRepositoryProvider,
296 final DataBroker dataBroker, final DOMMountPointService mountPointService,
297 final AAAEncryptionService encryptionService,
298 final RpcProviderService rpcProviderService) {
299 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor,
300 processingExecutor, schemaRepositoryProvider, dataBroker,
301 mountPointService, encryptionService, rpcProviderService, BASE_SCHEMAS);
305 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
306 return Futures.immediateFuture(new NetconfDeviceCapabilities());
310 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
311 return Futures.immediateFuture(null);
316 public void hideCredentialsTest() {
317 final String userName = "admin";
318 final String password = "pa$$word";
319 final Node node = new NodeBuilder()
320 .addAugmentation(new NetconfNodeBuilder()
321 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
322 .setPort(new PortNumber(Uint16.valueOf(9999)))
323 .setReconnectOnChangedSchema(true)
324 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
325 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
326 .setKeepaliveDelay(Uint32.valueOf(1000))
328 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build())
329 .setCredentials(new LoginPasswordBuilder()
330 .setUsername(userName)
331 .setPassword(password)
334 .setNodeId(NodeId.getDefaultInstance("junos"))
336 final String transformedNetconfNode = AbstractNetconfTopology.hideCredentials(node);
337 assertTrue(transformedNetconfNode.contains("credentials=***"));
338 assertFalse(transformedNetconfNode.contains(userName));
339 assertFalse(transformedNetconfNode.contains(password));