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.NetconfNodeBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol.Name;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.ProtocolBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
73 import org.opendaylight.yangtools.yang.binding.DataObject;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
77 import org.opendaylight.yangtools.yang.common.Decimal64;
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() {
154 final DataObjectModification<Node> newNode = mock(DataObjectModification.class);
155 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
157 NodeKey key = new NodeKey(NODE_ID);
158 PathArgument pa = IdentifiableItem.of(Node.class, key);
159 when(newNode.getIdentifier()).thenReturn(pa);
161 final NodeBuilder nn = new NodeBuilder()
163 .addAugmentation(new NetconfNodeBuilder()
164 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
165 .setPort(new PortNumber(Uint16.valueOf(9999)))
166 .setReconnectOnChangedSchema(true)
167 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
168 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
169 .setKeepaliveDelay(Uint32.valueOf(1000))
171 .setCredentials(new LoginPasswordBuilder()
172 .setUsername("testuser")
173 .setPassword("testpassword")
177 when(newNode.getDataAfter()).thenReturn(nn.build());
179 final Collection<DataTreeModification<Node>> changes = new HashSet<>();
180 final DataTreeModification<Node> ch = mock(DataTreeModification.class);
181 when(ch.getRootNode()).thenReturn(newNode);
183 spyTopology.onDataTreeChanged(changes);
184 verify(spyTopology).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
186 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
187 spyTopology.onDataTreeChanged(changes);
188 verify(spyTopology).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
190 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
191 spyTopology.onDataTreeChanged(changes);
193 //one in previous creating and deleting node and one in updating
194 verify(spyTopology, times(2)).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
195 verify(spyTopology, times(2)).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
199 public void testGetClientConfig() {
200 final NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
201 final NetconfNodeBuilder nodeBuilder = new NetconfNodeBuilder()
202 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
203 .setPort(new PortNumber(Uint16.valueOf(9999)))
204 .setReconnectOnChangedSchema(true)
205 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
206 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
207 .setKeepaliveDelay(Uint32.valueOf(1000))
208 .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
209 .setMaxConnectionAttempts(Uint32.ZERO)
210 .setSleepFactor(Decimal64.valueOf("1.5"))
211 .setConnectionTimeoutMillis(Uint32.valueOf(20000));
213 final NetconfReconnectingClientConfiguration configuration =
214 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(true).build());
215 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TCP, configuration.getProtocol());
216 assertNotNull(configuration.getAuthHandler());
217 assertNull(configuration.getSslHandlerFactory());
219 final NetconfReconnectingClientConfiguration configuration2 =
220 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(false).build());
221 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration2.getProtocol());
222 assertNotNull(configuration2.getAuthHandler());
223 assertNull(configuration2.getSslHandlerFactory());
225 final NetconfReconnectingClientConfiguration configuration3 =
226 spyTopology.getClientConfig(sessionListener, nodeBuilder
227 .setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build());
228 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration3.getProtocol());
229 assertNotNull(configuration3.getAuthHandler());
230 assertNull(configuration3.getSslHandlerFactory());
232 final NetconfReconnectingClientConfiguration configuration4 =
233 spyTopology.getClientConfig(sessionListener, nodeBuilder
234 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build());
235 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, configuration4.getProtocol());
236 assertNull(configuration4.getAuthHandler());
237 assertNotNull(configuration4.getSslHandlerFactory());
240 public static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
241 private static final BaseNetconfSchemas BASE_SCHEMAS;
245 BASE_SCHEMAS = new DefaultBaseNetconfSchemas(new DefaultYangParserFactory());
246 } catch (YangParserException e) {
247 throw new ExceptionInInitializerError(e);
251 public TestingNetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
252 final EventExecutor eventExecutor,
253 final ScheduledThreadPool keepaliveExecutor,
254 final ThreadPool processingExecutor,
255 final SchemaResourceManager schemaRepositoryProvider,
256 final DataBroker dataBroker, final DOMMountPointService mountPointService,
257 final AAAEncryptionService encryptionService,
258 final RpcProviderService rpcProviderService) {
259 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor,
260 processingExecutor, schemaRepositoryProvider, dataBroker,
261 mountPointService, encryptionService, rpcProviderService, BASE_SCHEMAS);
265 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
266 return Futures.immediateFuture(new NetconfDeviceCapabilities());
270 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
271 return Futures.immediateFuture(null);
276 public void hideCredentialsTest() {
277 final String userName = "admin";
278 final String password = "pa$$word";
279 final Node node = new NodeBuilder()
280 .addAugmentation(new NetconfNodeBuilder()
281 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
282 .setPort(new PortNumber(Uint16.valueOf(9999)))
283 .setReconnectOnChangedSchema(true)
284 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
285 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
286 .setKeepaliveDelay(Uint32.valueOf(1000))
288 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build())
289 .setCredentials(new LoginPasswordBuilder()
290 .setUsername(userName)
291 .setPassword(password)
294 .setNodeId(NodeId.getDefaultInstance("junos"))
296 final String transformedNetconfNode = AbstractNetconfTopology.hideCredentials(node);
297 assertTrue(transformedNetconfNode.contains("credentials=***"));
298 assertFalse(transformedNetconfNode.contains(userName));
299 assertFalse(transformedNetconfNode.contains(password));