2 * Copyright (c) 2013 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
9 package org.opendaylight.controller.netconf.it;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertThat;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Matchers.anyString;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.mock;
19 import com.google.common.base.Function;
20 import com.google.common.base.Throwables;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Sets;
23 import io.netty.channel.ChannelFuture;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.lang.management.ManagementFactory;
27 import java.net.InetSocketAddress;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.List;
35 import java.util.concurrent.ExecutionException;
36 import java.util.concurrent.TimeoutException;
37 import javax.management.ObjectName;
38 import javax.xml.parsers.ParserConfigurationException;
39 import org.junit.After;
40 import org.junit.Before;
41 import org.junit.Ignore;
42 import org.junit.Test;
43 import org.junit.matchers.JUnitMatchers;
44 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
45 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
46 import org.opendaylight.controller.config.spi.ModuleFactory;
47 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
48 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
49 import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
50 import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
51 import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
52 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
53 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
54 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
55 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
56 import org.opendaylight.controller.netconf.api.NetconfMessage;
57 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
58 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
59 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
60 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
61 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
62 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
63 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
64 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
65 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
66 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
67 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
68 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
69 import org.opendaylight.controller.netconf.util.xml.XmlElement;
70 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
73 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
74 import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
75 import org.w3c.dom.Document;
76 import org.w3c.dom.Element;
77 import org.w3c.dom.NamedNodeMap;
78 import org.w3c.dom.Node;
79 import org.xml.sax.SAXException;
81 public class NetconfITTest extends AbstractNetconfConfigTest {
83 // TODO refactor, pull common code up to AbstractNetconfITTest
85 private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
88 private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
89 private DefaultCommitNotificationProducer commitNotificationProducer;
90 private NetconfServerDispatcher dispatch;
92 private NetconfClientDispatcherImpl clientDispatcher;
94 static ModuleFactory[] FACTORIES = {new TestImplModuleFactory(), new DepTestImplModuleFactory(),
95 new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory(),
96 new MultipleDependenciesModuleFactory()};
99 public void setUp() throws Exception {
100 initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
106 NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
107 factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
109 commitNotificationProducer = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
111 dispatch = createDispatcher(factoriesListener);
112 ChannelFuture s = dispatch.createServer(tcpAddress);
115 clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
118 private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
119 return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNotificationProducer);
122 static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
123 NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
124 NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
125 doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
126 doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
127 return new NetconfMonitoringServiceImpl(netconfOperationProvider);
131 public void tearDown() throws Exception {
132 commitNotificationProducer.close();
133 clientDispatcher.close();
136 private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
137 this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
138 this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
139 this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
140 this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
143 private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
144 final Collection<InputStream> yangDependencies = getBasicYangs();
145 return new HardcodedYangStoreService(yangDependencies);
148 static Collection<InputStream> getBasicYangs() throws IOException {
150 List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
151 "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
152 "/META-INF/yang/ietf-inet-types.yang");
153 final Collection<InputStream> yangDependencies = new ArrayList<>();
154 List<String> failedToFind = new ArrayList<>();
155 for (String path : paths) {
156 InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
157 if (resourceAsStream == null) {
158 failedToFind.add(path);
160 yangDependencies.add(resourceAsStream);
163 assertEquals("Some yang files were not found", Collections.<String>emptyList(), failedToFind);
164 return yangDependencies;
169 public void testNetconfClientDemonstration() throws Exception {
170 try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
172 Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
173 long sessionId = netconfClient.getSessionId();
175 // NetconfMessage can be created :
176 // new NetconfMessage(XmlUtil.readXmlToDocument("<xml/>"));
178 NetconfMessage response = netconfClient.sendMessage(getConfig);
179 response.getDocument();
184 public void testTwoSessions() throws Exception {
185 try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
186 try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
187 assertNotNull(netconfClient2.getCapabilities());
194 public void waitingTest() throws Exception {
195 final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
196 transaction.createModule(DepTestImplModuleFactory.NAME, "eb");
197 transaction.commit();
198 Thread.currentThread().suspend();
202 public void rpcReplyContainsAllAttributesTest() throws Exception {
203 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
204 final String rpc = "<rpc message-id=\"5\" a=\"a\" b=\"44\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
205 + "<get/>" + "</rpc>";
206 final Document doc = XmlUtil.readXmlToDocument(rpc);
207 final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
208 assertNotNull(message);
209 final NamedNodeMap expectedAttributes = doc.getDocumentElement().getAttributes();
210 final NamedNodeMap returnedAttributes = message.getDocument().getDocumentElement().getAttributes();
212 assertSameAttributes(expectedAttributes, returnedAttributes);
216 private void assertSameAttributes(final NamedNodeMap expectedAttributes, final NamedNodeMap returnedAttributes) {
217 assertNotNull("Expecting 4 attributes", returnedAttributes);
218 assertEquals(expectedAttributes.getLength(), returnedAttributes.getLength());
220 for (int i = 0; i < expectedAttributes.getLength(); i++) {
221 final Node expAttr = expectedAttributes.item(i);
222 final Node attr = returnedAttributes.item(i);
223 assertEquals(expAttr.getNodeName(), attr.getNodeName());
224 assertEquals(expAttr.getNamespaceURI(), attr.getNamespaceURI());
225 assertEquals(expAttr.getTextContent(), attr.getTextContent());
230 public void rpcReplyErrorContainsAllAttributesTest() throws Exception {
231 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
232 final String rpc = "<rpc message-id=\"1\" a=\"adada\" b=\"4\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
233 + "<commit/>" + "</rpc>";
234 final Document doc = XmlUtil.readXmlToDocument(rpc);
235 final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
236 final NamedNodeMap expectedAttributes = doc.getDocumentElement().getAttributes();
237 final NamedNodeMap returnedAttributes = message.getDocument().getDocumentElement().getAttributes();
239 assertSameAttributes(expectedAttributes, returnedAttributes);
244 public void rpcOutputContainsCorrectNamespace() throws Exception {
245 final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
246 ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, "instanceD");
247 ObjectName impl = transaction.createModule(NetconfTestImplModuleFactory.NAME, "instance");
248 NetconfTestImplModuleMXBean proxy = configRegistryClient
249 .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
250 proxy.setTestingDep(dep);
251 proxy.setSimpleShort((short) 0);
253 transaction.commit();
255 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
256 final String expectedNamespace = "urn:opendaylight:params:xml:ns:yang:controller:test:impl";
258 final String rpc = "<rpc message-id=\"5\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
262 + "<context-instance>/modules/module[type='impl-netconf'][name='instance']</context-instance>"
263 + "<arg1>argument1</arg1>" + "</no-arg>" + "</rpc>";
264 final Document doc = XmlUtil.readXmlToDocument(rpc);
265 final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
267 final Element rpcReply = message.getDocument().getDocumentElement();
268 final XmlElement resultElement = XmlElement.fromDomElement(rpcReply).getOnlyChildElement();
269 assertEquals("result", resultElement.getName());
271 final String namespace = resultElement.getNamespaceAttribute();
272 assertEquals(expectedNamespace, namespace);
277 public void testCloseSession() throws Exception {
278 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
281 Document rpcReply = netconfClient.sendMessage(this.editConfig)
283 assertIsOK(rpcReply);
285 rpcReply = netconfClient.sendMessage(this.closeSession)
288 assertIsOK(rpcReply);
293 public void testEditConfig() throws Exception {
294 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
295 // send edit_config.xml
296 final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
297 assertIsOK(rpcReply);
302 public void testValidate() throws Exception {
303 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
305 Document rpcReply = netconfClient.sendMessage(getConfigCandidate).getDocument();
306 assertEquals("data", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
309 rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/validate.xml"))
311 assertIsOK(rpcReply);
315 private void assertIsOK(final Document rpcReply) throws NetconfDocumentedException {
316 assertEquals("rpc-reply", rpcReply.getDocumentElement().getLocalName());
317 assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
320 private Document assertGetConfigWorks(final TestingNetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException, NetconfDocumentedException {
321 return assertGetConfigWorks(netconfClient, this.getConfig);
324 private Document assertGetConfigWorks(final TestingNetconfClient netconfClient, final NetconfMessage getConfigMessage)
325 throws InterruptedException, ExecutionException, TimeoutException, NetconfDocumentedException {
326 final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
327 assertNotNull(rpcReply);
328 assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName());
329 return rpcReply.getDocument();
333 public void testGetConfig() throws Exception {
334 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
335 assertGetConfigWorks(netconfClient);
340 public void createYangTestBasedOnYuma() throws Exception {
341 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
342 Document rpcReply = netconfClient.sendMessage(
343 XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_yang-test.xml"))
345 assertEquals("rpc-reply", rpcReply.getDocumentElement().getTagName());
346 assertIsOK(rpcReply);
347 assertGetConfigWorks(netconfClient, this.getConfigCandidate);
348 rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
350 assertIsOK(rpcReply);
352 final ObjectName on = new ObjectName(
353 "org.opendaylight.controller:instanceName=impl-dep-instance,type=Module,moduleFactoryName=impl-dep");
354 Set<ObjectName> cfgBeans = configRegistryClient.lookupConfigBeans();
355 assertEquals(cfgBeans, Sets.newHashSet(on));
359 private TestingNetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
360 final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), clientDispatcher, getClientConfiguration(address, 5000));
361 assertEquals(expected, Long.toString(netconfClient.getSessionId()));
362 return netconfClient;
366 public void testIdRef() throws Exception {
367 NetconfMessage editId = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
368 NetconfMessage commit = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml");
370 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
371 assertIsOK(netconfClient.sendMessage(editId).getDocument());
372 assertIsOK(netconfClient.sendMessage(commit).getDocument());
374 NetconfMessage response = netconfClient.sendMessage(getConfig);
376 assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>"));
377 assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>"));
378 assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>"));
379 assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>"));
381 } catch (Exception e) {
382 fail(Throwables.getStackTraceAsString(e));
387 protected CodecRegistry getCodecRegistry() {
388 final IdentityCodec<?> codec = mock(IdentityCodec.class);
389 doReturn(TestIdentity1.class).when(codec).deserialize(TestIdentity1.QNAME);
390 doReturn(TestIdentity2.class).when(codec).deserialize(TestIdentity2.QNAME);
392 final CodecRegistry ret = super.getCodecRegistry();
393 doReturn(codec).when(ret).getIdentityCodec();
399 public void testMultipleDependencies() throws Exception {
400 // push first xml, should add parent and d1,d2 dependencies
401 try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
402 Document rpcReply = netconfClient.sendMessage(
403 XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps1.xml"))
405 assertIsOK(rpcReply);
406 commit(netconfClient);
408 // verify that parent.getTestingDeps == d1,d2
409 MultipleDependenciesModuleMXBean parentProxy = configRegistryClient.newMXBeanProxy(
410 configRegistryClient.lookupConfigBean(MultipleDependenciesModuleFactory.NAME, "parent"),
411 MultipleDependenciesModuleMXBean.class);
413 List<ObjectName> testingDeps = parentProxy.getTestingDeps();
414 assertEquals(2, testingDeps.size());
415 Set<String> actualRefs = getServiceReferences(testingDeps);
416 assertEquals(Sets.newHashSet("ref_d1", "ref_d2"), actualRefs);
419 // push second xml, should add d3 to parent's dependencies
420 mergeD3(parentProxy);
421 // push second xml again, to test that d3 is not added again
422 mergeD3(parentProxy);
425 public void mergeD3(MultipleDependenciesModuleMXBean parentProxy) throws Exception {
426 try (TestingNetconfClient netconfClient = new TestingNetconfClient(
427 "test " + tcpAddress.toString(), clientDispatcher, getClientConfiguration(tcpAddress, 5000))) {
429 Document rpcReply = netconfClient.sendMessage(
430 XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps2.xml"))
432 assertIsOK(rpcReply);
433 commit(netconfClient);
436 List<ObjectName> testingDeps = parentProxy.getTestingDeps();
437 assertEquals(3, testingDeps.size());
438 Set<String> actualRefs = getServiceReferences(testingDeps);
439 assertEquals(Sets.newHashSet("ref_d1", "ref_d2", "ref_d3"), actualRefs);
443 public Set<String> getServiceReferences(List<ObjectName> testingDeps) {
444 return new HashSet<>(Lists.transform(testingDeps, new Function<ObjectName, String>() {
446 public String apply(ObjectName input) {
447 return ObjectNameUtil.getReferenceName(input);
452 public void commit(TestingNetconfClient netconfClient) throws Exception {
454 rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
456 assertIsOK(rpcReply);