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.Mockito.doReturn;
16 import static org.mockito.Mockito.mock;
17 import static org.mockito.Mockito.spy;
18 import static org.mockito.Mockito.times;
19 import static org.mockito.Mockito.verify;
20 import static org.mockito.Mockito.when;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import com.google.common.util.concurrent.MoreExecutors;
25 import io.netty.util.concurrent.EventExecutor;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.mockito.Mock;
32 import org.mockito.junit.MockitoJUnitRunner;
33 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
34 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
35 import org.opendaylight.controller.config.threadpool.ThreadPool;
36 import org.opendaylight.mdsal.binding.api.DataBroker;
37 import org.opendaylight.mdsal.binding.api.DataObjectModification;
38 import org.opendaylight.mdsal.binding.api.DataTreeModification;
39 import org.opendaylight.mdsal.binding.api.RpcProviderService;
40 import org.opendaylight.mdsal.binding.api.WriteTransaction;
41 import org.opendaylight.mdsal.common.api.CommitInfo;
42 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
43 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
44 import org.opendaylight.netconf.client.NetconfClientDispatcher;
45 import org.opendaylight.netconf.client.NetconfClientSessionListener;
46 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
47 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
48 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
49 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
50 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.DefaultBaseNetconfSchemas;
51 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.parameters.Protocol.Name;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.parameters.ProtocolBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.credentials.credentials.LoginPasswordBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNodeBuilder;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
72 import org.opendaylight.yangtools.yang.common.Decimal64;
73 import org.opendaylight.yangtools.yang.common.Empty;
74 import org.opendaylight.yangtools.yang.common.Uint16;
75 import org.opendaylight.yangtools.yang.common.Uint32;
76 import org.opendaylight.yangtools.yang.parser.api.YangParserException;
77 import org.opendaylight.yangtools.yang.parser.impl.DefaultYangParserFactory;
79 @RunWith(MockitoJUnitRunner.StrictStubs.class)
80 public class NetconfTopologyImplTest {
81 private static final NodeId NODE_ID = new NodeId("testing-node");
82 private static final String TOPOLOGY_ID = "testing-topology";
85 private NetconfClientDispatcher mockedClientDispatcher;
87 private EventExecutor mockedEventExecutor;
89 private ScheduledThreadPool mockedKeepaliveExecutor;
91 private ThreadPool mockedProcessingExecutor;
93 private SchemaResourceManager mockedResourceManager;
95 private DataBroker dataBroker;
97 private DOMMountPointService mountPointService;
99 private AAAEncryptionService encryptionService;
101 private RpcProviderService rpcProviderService;
103 private WriteTransaction wtx;
105 private TestingNetconfTopologyImpl topology;
106 private TestingNetconfTopologyImpl spyTopology;
109 public void setUp() {
110 doReturn(MoreExecutors.newDirectExecutorService()).when(mockedProcessingExecutor).getExecutor();
111 doReturn(wtx).when(dataBroker).newWriteOnlyTransaction();
112 doReturn(CommitInfo.emptyFluentFuture()).when(wtx).commit();
114 topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher, mockedEventExecutor,
115 mockedKeepaliveExecutor, mockedProcessingExecutor, mockedResourceManager, dataBroker, mountPointService,
116 encryptionService, rpcProviderService);
118 spyTopology = spy(topology);
122 public void testInit() {
125 //verify initialization of topology
126 verify(wtx).merge(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(NetworkTopology.class)
127 .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))).build(),
128 new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build());
132 public void testOnDataTreeChange() {
133 final DataObjectModification<Node> newNode = mock(DataObjectModification.class);
134 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
136 NodeKey key = new NodeKey(NODE_ID);
137 PathArgument pa = IdentifiableItem.of(Node.class, key);
138 when(newNode.getIdentifier()).thenReturn(pa);
140 final NodeBuilder nn = new NodeBuilder()
142 .addAugmentation(new NetconfNodeBuilder()
143 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
144 .setPort(new PortNumber(Uint16.valueOf(9999)))
145 .setReconnectOnChangedSchema(true)
146 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
147 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
148 .setKeepaliveDelay(Uint32.valueOf(1000))
150 .setCredentials(new LoginPasswordBuilder()
151 .setUsername("testuser")
152 .setPassword("testpassword")
156 when(newNode.getDataAfter()).thenReturn(nn.build());
158 final Collection<DataTreeModification<Node>> changes = new HashSet<>();
159 final DataTreeModification<Node> ch = mock(DataTreeModification.class);
160 when(ch.getRootNode()).thenReturn(newNode);
162 spyTopology.onDataTreeChanged(changes);
163 verify(spyTopology).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
165 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
166 spyTopology.onDataTreeChanged(changes);
167 verify(spyTopology).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
169 when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
170 spyTopology.onDataTreeChanged(changes);
172 //one in previous creating and deleting node and one in updating
173 verify(spyTopology, times(2)).disconnectNode(NetconfTopologyImpl.getNodeId(pa));
174 verify(spyTopology, times(2)).connectNode(NetconfTopologyImpl.getNodeId(pa), nn.build());
178 public void testGetClientConfig() {
179 final NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
180 final NetconfNodeBuilder nodeBuilder = new NetconfNodeBuilder()
181 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
182 .setPort(new PortNumber(Uint16.valueOf(9999)))
183 .setReconnectOnChangedSchema(true)
184 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
185 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
186 .setKeepaliveDelay(Uint32.valueOf(1000))
187 .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
188 .setMaxConnectionAttempts(Uint32.ZERO)
189 .setSleepFactor(Decimal64.valueOf("1.5"))
190 .setConnectionTimeoutMillis(Uint32.valueOf(20000));
192 final NetconfReconnectingClientConfiguration configuration =
193 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(true).build(), NODE_ID);
194 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TCP, configuration.getProtocol());
195 assertNotNull(configuration.getAuthHandler());
196 assertNull(configuration.getSslHandlerFactory());
198 final NetconfReconnectingClientConfiguration configuration2 =
199 spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(false).build(), NODE_ID);
200 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration2.getProtocol());
201 assertNotNull(configuration2.getAuthHandler());
202 assertNull(configuration2.getSslHandlerFactory());
204 final NetconfReconnectingClientConfiguration configuration3 =
205 spyTopology.getClientConfig(sessionListener, nodeBuilder
206 .setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build(), NODE_ID);
207 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration3.getProtocol());
208 assertNotNull(configuration3.getAuthHandler());
209 assertNull(configuration3.getSslHandlerFactory());
211 final NetconfReconnectingClientConfiguration configuration4 =
212 spyTopology.getClientConfig(sessionListener, nodeBuilder
213 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build(), NODE_ID);
214 assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, configuration4.getProtocol());
215 assertNull(configuration4.getAuthHandler());
216 assertNotNull(configuration4.getSslHandlerFactory());
219 public static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
220 private static final BaseNetconfSchemas BASE_SCHEMAS;
224 BASE_SCHEMAS = new DefaultBaseNetconfSchemas(new DefaultYangParserFactory());
225 } catch (YangParserException e) {
226 throw new ExceptionInInitializerError(e);
230 public TestingNetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
231 final EventExecutor eventExecutor,
232 final ScheduledThreadPool keepaliveExecutor,
233 final ThreadPool processingExecutor,
234 final SchemaResourceManager schemaRepositoryProvider,
235 final DataBroker dataBroker, final DOMMountPointService mountPointService,
236 final AAAEncryptionService encryptionService,
237 final RpcProviderService rpcProviderService) {
238 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor,
239 processingExecutor, schemaRepositoryProvider, dataBroker,
240 mountPointService, encryptionService, rpcProviderService, BASE_SCHEMAS);
244 public ListenableFuture<Empty> connectNode(final NodeId nodeId, final Node configNode) {
245 return Futures.immediateFuture(Empty.value());
249 public ListenableFuture<Empty> disconnectNode(final NodeId nodeId) {
250 return Futures.immediateFuture(Empty.value());
255 public void hideCredentialsTest() {
256 final String userName = "admin";
257 final String password = "pa$$word";
258 final Node node = new NodeBuilder()
259 .addAugmentation(new NetconfNodeBuilder()
260 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
261 .setPort(new PortNumber(Uint16.valueOf(9999)))
262 .setReconnectOnChangedSchema(true)
263 .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
264 .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
265 .setKeepaliveDelay(Uint32.valueOf(1000))
267 .setProtocol(new ProtocolBuilder().setName(Name.TLS).build())
268 .setCredentials(new LoginPasswordBuilder()
269 .setUsername(userName)
270 .setPassword(password)
273 .setNodeId(NodeId.getDefaultInstance("junos"))
275 final String transformedNetconfNode = AbstractNetconfTopology.hideCredentials(node);
276 assertTrue(transformedNetconfNode.contains("credentials=***"));
277 assertFalse(transformedNetconfNode.contains(userName));
278 assertFalse(transformedNetconfNode.contains(password));