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.schema.mapping.BaseNetconfSchemas;
52 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.DefaultBaseNetconfSchemas;
53 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol.Name;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.ProtocolBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
71 import org.opendaylight.yangtools.yang.binding.DataObject;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
75 import org.opendaylight.yangtools.yang.common.Decimal64;
76 import org.opendaylight.yangtools.yang.common.Empty;
77 import org.opendaylight.yangtools.yang.common.Uint16;
78 import org.opendaylight.yangtools.yang.common.Uint32;
79 import org.opendaylight.yangtools.yang.parser.api.YangParserException;
80 import org.opendaylight.yangtools.yang.parser.impl.DefaultYangParserFactory;
82 @RunWith(MockitoJUnitRunner.StrictStubs.class)
83 public class NetconfTopologyImplTest {
85 private static final NodeId NODE_ID = new NodeId("testing-node");
86 private static final String TOPOLOGY_ID = "testing-topology";
89 private NetconfClientDispatcher mockedClientDispatcher;
92 private EventExecutor mockedEventExecutor;
95 private ScheduledThreadPool mockedKeepaliveExecutor;
98 private ThreadPool mockedProcessingExecutor;
101 private SchemaResourceManager mockedResourceManager;
104 private DataBroker dataBroker;
107 private DOMMountPointService mountPointService;
110 private AAAEncryptionService encryptionService;
113 private RpcProviderService rpcProviderService;
115 private TestingNetconfTopologyImpl topology;
116 private TestingNetconfTopologyImpl spyTopology;
119 public void setUp() {
120 when(mockedProcessingExecutor.getExecutor()).thenReturn(MoreExecutors.newDirectExecutorService());
122 topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher, mockedEventExecutor,
123 mockedKeepaliveExecutor, mockedProcessingExecutor, mockedResourceManager, dataBroker, mountPointService,
124 encryptionService, rpcProviderService);
126 spyTopology = spy(topology);
130 public void testInit() {
131 final WriteTransaction wtx = mock(WriteTransaction.class);
132 when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
133 doNothing().when(wtx)
134 .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
135 doReturn(emptyFluentFuture()).when(wtx).commit();
138 //verify initialization of topology
139 final InstanceIdentifier<NetworkTopology> networkTopologyId =
140 InstanceIdentifier.builder(NetworkTopology.class).build();
141 final Topology topo = new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build();
142 verify(wtx).merge(LogicalDatastoreType.CONFIGURATION,
143 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))), topo);
144 verify(wtx).merge(LogicalDatastoreType.OPERATIONAL,
145 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))), topo);
149 public void testOnDataTreeChange() {
150 final DataObjectModification<Node> newNode = mock(DataObjectModification.class);
151 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
153 NodeKey key = new NodeKey(NODE_ID);
154 PathArgument pa = IdentifiableItem.of(Node.class, key);
155 when(newNode.getIdentifier()).thenReturn(pa);
157 final NodeBuilder nn = new NodeBuilder()
159 .addAugmentation(new NetconfNodeBuilder()
160 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
161 .setPort(new PortNumber(Uint16.valueOf(9999)))
162 .setReconnectOnChangedSchema(true)
163 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
164 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
165 .setKeepaliveDelay(Uint32.valueOf(1000))
167 .setCredentials(new LoginPasswordBuilder()
168 .setUsername("testuser")
169 .setPassword("testpassword")
173 when(newNode.getDataAfter()).thenReturn(nn.build());
175 final Collection<DataTreeModification<Node>> changes = new HashSet<>();
176 final DataTreeModification<Node> ch = mock(DataTreeModification.class);
177 when(ch.getRootNode()).thenReturn(newNode);
179 spyTopology.onDataTreeChanged(changes);
180 verify(spyTopology).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
182 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
183 spyTopology.onDataTreeChanged(changes);
184 verify(spyTopology).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
186 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
187 spyTopology.onDataTreeChanged(changes);
189 //one in previous creating and deleting node and one in updating
190 verify(spyTopology, times(2)).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
191 verify(spyTopology, times(2)).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
195 public void testGetClientConfig() {
196 final NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
197 final NetconfNodeBuilder nodeBuilder = new NetconfNodeBuilder()
198 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
199 .setPort(new PortNumber(Uint16.valueOf(9999)))
200 .setReconnectOnChangedSchema(true)
201 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
202 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
203 .setKeepaliveDelay(Uint32.valueOf(1000))
204 .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
205 .setMaxConnectionAttempts(Uint32.ZERO)
206 .setSleepFactor(Decimal64.valueOf("1.5"))
207 .setConnectionTimeoutMillis(Uint32.valueOf(20000));
209 final NetconfReconnectingClientConfiguration configuration =
210 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(true).build(), NODE_ID);
211 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TCP, configuration.getProtocol());
212 assertNotNull(configuration.getAuthHandler());
213 assertNull(configuration.getSslHandlerFactory());
215 final NetconfReconnectingClientConfiguration configuration2 =
216 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(false).build(), NODE_ID);
217 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration2.getProtocol());
218 assertNotNull(configuration2.getAuthHandler());
219 assertNull(configuration2.getSslHandlerFactory());
221 final NetconfReconnectingClientConfiguration configuration3 =
222 spyTopology.getClientConfig(sessionListener, nodeBuilder
223 .setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build(), NODE_ID);
224 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration3.getProtocol());
225 assertNotNull(configuration3.getAuthHandler());
226 assertNull(configuration3.getSslHandlerFactory());
228 final NetconfReconnectingClientConfiguration configuration4 =
229 spyTopology.getClientConfig(sessionListener, nodeBuilder
230 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build(), NODE_ID);
231 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, configuration4.getProtocol());
232 assertNull(configuration4.getAuthHandler());
233 assertNotNull(configuration4.getSslHandlerFactory());
236 public static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
237 private static final BaseNetconfSchemas BASE_SCHEMAS;
241 BASE_SCHEMAS = new DefaultBaseNetconfSchemas(new DefaultYangParserFactory());
242 } catch (YangParserException e) {
243 throw new ExceptionInInitializerError(e);
247 public TestingNetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
248 final EventExecutor eventExecutor,
249 final ScheduledThreadPool keepaliveExecutor,
250 final ThreadPool processingExecutor,
251 final SchemaResourceManager schemaRepositoryProvider,
252 final DataBroker dataBroker, final DOMMountPointService mountPointService,
253 final AAAEncryptionService encryptionService,
254 final RpcProviderService rpcProviderService) {
255 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor,
256 processingExecutor, schemaRepositoryProvider, dataBroker,
257 mountPointService, encryptionService, rpcProviderService, BASE_SCHEMAS);
261 public ListenableFuture<Empty> connectNode(final NodeId nodeId, final Node configNode) {
262 return Futures.immediateFuture(Empty.value());
266 public ListenableFuture<Empty> disconnectNode(final NodeId nodeId) {
267 return Futures.immediateFuture(Empty.value());
272 public void hideCredentialsTest() {
273 final String userName = "admin";
274 final String password = "pa$$word";
275 final Node node = new NodeBuilder()
276 .addAugmentation(new NetconfNodeBuilder()
277 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
278 .setPort(new PortNumber(Uint16.valueOf(9999)))
279 .setReconnectOnChangedSchema(true)
280 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
281 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
282 .setKeepaliveDelay(Uint32.valueOf(1000))
284 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build())
285 .setCredentials(new LoginPasswordBuilder()
286 .setUsername(userName)
287 .setPassword(password)
290 .setNodeId(NodeId.getDefaultInstance("junos"))
292 final String transformedNetconfNode = AbstractNetconfTopology.hideCredentials(node);
293 assertTrue(transformedNetconfNode.contains("credentials=***"));
294 assertFalse(transformedNetconfNode.contains(userName));
295 assertFalse(transformedNetconfNode.contains(password));