Remove RuntimeGeneratedMappingService from config-manager
[controller.git] / opendaylight / netconf / config-netconf-connector / src / test / java / org / opendaylight / controller / netconf / confignetconfconnector / NetconfMappingTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.netconf.confignetconfconnector;
10
11 import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertThat;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.Matchers.any;
17 import static org.mockito.Matchers.anyString;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.verifyNoMoreInteractions;
23 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
24 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
25 import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
26
27 import com.google.common.base.Optional;
28 import com.google.common.base.Preconditions;
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.Lists;
31 import com.google.common.collect.Maps;
32 import com.google.common.collect.Sets;
33 import java.io.FileNotFoundException;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.math.BigInteger;
37 import java.net.URISyntaxException;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Map.Entry;
46 import java.util.Set;
47 import javax.management.InstanceAlreadyExistsException;
48 import javax.management.InstanceNotFoundException;
49 import javax.management.ObjectName;
50 import javax.xml.parsers.ParserConfigurationException;
51 import org.custommonkey.xmlunit.AbstractNodeTester;
52 import org.custommonkey.xmlunit.NodeTest;
53 import org.custommonkey.xmlunit.NodeTestException;
54 import org.custommonkey.xmlunit.NodeTester;
55 import org.custommonkey.xmlunit.XMLAssert;
56 import org.custommonkey.xmlunit.XMLUnit;
57 import org.hamcrest.CoreMatchers;
58 import org.junit.Before;
59 import org.junit.Ignore;
60 import org.junit.Test;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 import org.opendaylight.controller.config.api.ConflictingVersionException;
64 import org.opendaylight.controller.config.api.ValidationException;
65 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
66 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
67 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
68 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
69 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
70 import org.opendaylight.controller.config.yang.test.impl.ComplexDtoBInner;
71 import org.opendaylight.controller.config.yang.test.impl.ComplexList;
72 import org.opendaylight.controller.config.yang.test.impl.Deep;
73 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
74 import org.opendaylight.controller.config.yang.test.impl.DtoAInner;
75 import org.opendaylight.controller.config.yang.test.impl.DtoAInnerInner;
76 import org.opendaylight.controller.config.yang.test.impl.DtoC;
77 import org.opendaylight.controller.config.yang.test.impl.DtoD;
78 import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
79 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
80 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
81 import org.opendaylight.controller.config.yang.test.impl.Peers;
82 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
83 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
84 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
85 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
86 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
87 import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
88 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
89 import org.opendaylight.controller.netconf.confignetconfconnector.operations.UnLock;
90 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
91 import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
92 import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
93 import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
94 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
95 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
96 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
97 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
98 import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
99 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
100 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
101 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
102 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
103 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
104 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
105 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
108 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
109 import org.opendaylight.yangtools.yang.model.api.Module;
110 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
111 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
112 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
113 import org.osgi.framework.Filter;
114 import org.osgi.framework.ServiceListener;
115 import org.osgi.framework.ServiceReference;
116 import org.slf4j.Logger;
117 import org.slf4j.LoggerFactory;
118 import org.w3c.dom.Document;
119 import org.w3c.dom.Element;
120 import org.w3c.dom.Node;
121 import org.w3c.dom.NodeList;
122 import org.w3c.dom.Text;
123 import org.w3c.dom.traversal.DocumentTraversal;
124 import org.xml.sax.SAXException;
125
126
127 public class NetconfMappingTest extends AbstractConfigTest {
128     private static final Logger LOG = LoggerFactory.getLogger(NetconfMappingTest.class);
129
130     private static final String INSTANCE_NAME = "instance-from-code";
131     private static final String NETCONF_SESSION_ID = "foo";
132     private static final String TEST_NAMESPACE= "urn:opendaylight:params:xml:ns:yang:controller:test:impl";
133     private NetconfTestImplModuleFactory factory;
134     private DepTestImplModuleFactory factory2;
135     private IdentityTestModuleFactory factory3;
136     private TestImplModuleFactory factory4;
137
138     @Mock
139     YangStoreContext yangStoreSnapshot;
140     @Mock
141     NetconfOperationRouter netconfOperationRouter;
142     @Mock
143     AggregatedNetconfOperationServiceFactory netconfOperationServiceSnapshot;
144     @Mock
145     private AutoCloseable sessionCloseable;
146
147     private TransactionProvider transactionProvider;
148
149     @Before
150     public void setUp() throws Exception {
151         MockitoAnnotations.initMocks(this);
152
153
154         final Filter filter = mock(Filter.class);
155         doReturn(filter).when(mockedContext).createFilter(anyString());
156         doNothing().when(mockedContext).addServiceListener(any(ServiceListener.class), anyString());
157         doReturn(new ServiceReference<?>[]{}).when(mockedContext).getServiceReferences(anyString(), anyString());
158
159         doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
160         doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
161
162         this.factory = new NetconfTestImplModuleFactory();
163         this.factory2 = new DepTestImplModuleFactory();
164         this.factory3 = new IdentityTestModuleFactory();
165         factory4 = new TestImplModuleFactory();
166         doNothing().when(sessionCloseable).close();
167
168         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, this.factory, this.factory2,
169                 this.factory3, factory4));
170
171         transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
172     }
173
174     private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException {
175         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
176
177         final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
178         final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class);
179         setModule(mxBean, transaction, instanceName + "_dep");
180
181         int i = 1;
182         for (Class<? extends AbstractServiceInterface> sInterface : factory.getImplementedServiceIntefaces()) {
183             ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
184             transaction.saveServiceReference(
185                     transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++,
186                     on);
187
188         }
189         transaction.commit();
190         return on;
191     }
192
193     @Test
194     public void testIdentityRefs() throws Exception {
195         edit("netconfMessages/editConfig_identities.xml");
196
197         commit();
198         getConfigRunning();
199     }
200
201     @Override
202     protected BindingRuntimeContext getBindingRuntimeContext() {
203         final BindingRuntimeContext ret = super.getBindingRuntimeContext();
204         doReturn(TestIdentity1.class).when(ret).getIdentityClass(TestIdentity1.QNAME);
205         doReturn(TestIdentity2.class).when(ret).getIdentityClass(TestIdentity2.QNAME);
206         return ret;
207     }
208
209     @Test
210     public void testServicePersistance() throws Exception {
211         createModule(INSTANCE_NAME);
212
213         edit("netconfMessages/editConfig.xml");
214         Document config = getConfigCandidate();
215         assertCorrectServiceNames(config, Sets.newHashSet("user_to_instance_from_code", "ref_dep_user",
216                 "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
217                 "ref_from_code_to_instance-from-code_1"));
218
219
220         edit("netconfMessages/editConfig_addServiceName.xml");
221         config = getConfigCandidate();
222         assertCorrectServiceNames(config, Sets.newHashSet("user_to_instance_from_code", "ref_dep_user",
223                 "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
224                 "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"));
225
226         edit("netconfMessages/editConfig_addServiceNameOnTest.xml");
227         config = getConfigCandidate();
228         assertCorrectServiceNames(config, Sets.newHashSet("user_to_instance_from_code", "ref_dep_user",
229                 "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
230                 "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"));
231
232         commit();
233         config = getConfigRunning();
234         assertCorrectRefNamesForDependencies(config);
235         assertCorrectServiceNames(config, Sets.newHashSet("user_to_instance_from_code", "ref_dep_user",
236                 "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
237                 "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"));
238
239         edit("netconfMessages/editConfig_replace_default.xml");
240         config = getConfigCandidate();
241         assertCorrectServiceNames(config, Collections.<String>emptySet());
242
243         edit("netconfMessages/editConfig_remove.xml");
244         config = getConfigCandidate();
245         assertCorrectServiceNames(config, Collections.<String>emptySet());
246
247         commit();
248         config = getConfigCandidate();
249         assertCorrectServiceNames(config, Collections.<String>emptySet());
250
251     }
252
253     @Test
254     public void testUnLock() throws Exception {
255         assertTrue(NetconfMessageUtil.isOKMessage(lockCandidate()));
256         assertTrue(NetconfMessageUtil.isOKMessage(unlockCandidate()));
257     }
258
259     private void assertCorrectRefNamesForDependencies(Document config) throws NodeTestException {
260         NodeList modulesList = config.getElementsByTagName("modules");
261         assertEquals(1, modulesList.getLength());
262
263         NodeTest nt = new NodeTest((DocumentTraversal) config, modulesList.item(0));
264         NodeTester tester = new AbstractNodeTester() {
265             private int defaultRefNameCount = 0;
266             private int userRefNameCount = 0;
267
268             @Override
269             public void testText(Text text) throws NodeTestException {
270                 if(text.getData().equals("ref_dep2")) {
271                     defaultRefNameCount++;
272                 } else if(text.getData().equals("ref_dep_user_two")) {
273                     userRefNameCount++;
274                 }
275             }
276
277             @Override
278             public void noMoreNodes(NodeTest forTest) throws NodeTestException {
279                 assertEquals(0, defaultRefNameCount);
280                 assertEquals(2, userRefNameCount);
281             }
282         };
283         nt.performTest(tester, Node.TEXT_NODE);
284     }
285
286     private void assertCorrectServiceNames(Document configCandidate, Set<String> refNames) throws NodeTestException {
287         final Set<String> refNames2 = new HashSet<>(refNames);
288         NodeList servicesNodes = configCandidate.getElementsByTagName("services");
289         assertEquals(1, servicesNodes.getLength());
290
291         NodeTest nt = new NodeTest((DocumentTraversal) configCandidate, servicesNodes.item(0));
292         NodeTester tester = new AbstractNodeTester() {
293
294             @Override
295             public void testElement(Element element) throws NodeTestException {
296                 if(element.getNodeName() != null) {
297                     if(element.getNodeName().equals("name")) {
298                         String elmText = element.getTextContent();
299                         if(refNames2.contains(elmText)) {
300                             refNames2.remove(elmText);
301                         } else {
302                             throw new NodeTestException("Unexpected services defined: " + elmText);
303                         }
304                     }
305                 }
306             }
307
308             @Override
309             public void noMoreNodes(NodeTest forTest) throws NodeTestException {
310                 assertEquals(Collections.<String>emptySet(), refNames2);
311                 assertTrue(refNames2.toString(), refNames2.isEmpty());
312             }
313         };
314         nt.performTest(tester, Node.ELEMENT_NODE);
315     }
316
317     @Test
318     public void testConfigNetconfUnionTypes() throws Exception {
319
320         createModule(INSTANCE_NAME);
321
322         edit("netconfMessages/editConfig.xml");
323         commit();
324         Document response = getConfigRunning();
325         Element ipElement = readXmlToElement("<ip xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">0:0:0:0:0:0:0:1</ip>");
326         assertContainsElement(response, readXmlToElement("<ip xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">0:0:0:0:0:0:0:1</ip>"));
327
328         assertContainsElement(response, readXmlToElement("<union-test-attr xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">456</union-test-attr>"));
329
330
331         edit("netconfMessages/editConfig_setUnions.xml");
332         commit();
333         response = getConfigRunning();
334         assertContainsElement(response, readXmlToElement("<ip xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">127.1.2.3</ip>"));
335         assertContainsElement(response, readXmlToElement("<union-test-attr xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">randomStringForUnion</union-test-attr>"));
336
337     }
338
339     @Test
340     public void testConfigNetconf() throws Exception {
341
342         createModule(INSTANCE_NAME);
343
344         edit("netconfMessages/editConfig.xml");
345         Document configCandidate = getConfigCandidate();
346         checkBinaryLeafEdited(configCandidate);
347
348
349         // default-operation:none, should not affect binary leaf
350         edit("netconfMessages/editConfig_none.xml");
351         checkBinaryLeafEdited(getConfigCandidate());
352
353         // check after edit
354         commit();
355         Document response = getConfigRunning();
356
357         checkBinaryLeafEdited(response);
358         checkTypeConfigAttribute(response);
359         checkTypedefs(response);
360         checkTestingDeps(response);
361         checkEnum(response);
362         checkBigDecimal(response);
363
364         edit("netconfMessages/editConfig_remove.xml");
365
366         commit();
367         assertXMLEqual(getConfigCandidate(), getConfigRunning());
368
369         final Document expectedResult = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml");
370         XMLUnit.setIgnoreWhitespace(true);
371         assertXMLEqual(expectedResult, getConfigRunning());
372         assertXMLEqual(expectedResult, getConfigCandidate());
373
374         edit("netconfMessages/editConfig_none.xml");
375         closeSession();
376         verify(sessionCloseable).close();
377         verifyNoMoreInteractions(netconfOperationRouter);
378         verifyNoMoreInteractions(netconfOperationServiceSnapshot);
379     }
380
381     private void checkBigDecimal(Document response) throws NodeTestException, SAXException, IOException {
382         assertContainsElement(response, readXmlToElement("<sleep-factor xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.58</sleep-factor>"));
383         // Default
384         assertContainsElement(response, readXmlToElement("<sleep-factor xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.00</sleep-factor>"));
385
386     }
387
388     private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
389             IOException {
390         DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID, sessionCloseable);
391         executeOp(closeOp, "netconfMessages/closeSession.xml");
392     }
393
394     private void edit(String resource) throws ParserConfigurationException, SAXException, IOException,
395             NetconfDocumentedException {
396         EditConfig editOp = new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
397                 NETCONF_SESSION_ID);
398         executeOp(editOp, resource);
399     }
400
401     private void commit() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
402         Commit commitOp = new Commit(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
403         executeOp(commitOp, "netconfMessages/commit.xml");
404     }
405
406     private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
407         Lock commitOp = new Lock(NETCONF_SESSION_ID);
408         return executeOp(commitOp, "netconfMessages/lock.xml");
409     }
410
411     private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
412         UnLock commitOp = new UnLock(NETCONF_SESSION_ID);
413         return executeOp(commitOp, "netconfMessages/unlock.xml");
414     }
415
416     private Document getConfigCandidate() throws ParserConfigurationException, SAXException, IOException,
417             NetconfDocumentedException {
418         GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
419                 configRegistryClient, NETCONF_SESSION_ID);
420         return executeOp(getConfigOp, "netconfMessages/getConfig_candidate.xml");
421     }
422
423     private Document getConfigRunning() throws ParserConfigurationException, SAXException, IOException,
424             NetconfDocumentedException {
425         GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
426                 configRegistryClient, NETCONF_SESSION_ID);
427         return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
428     }
429
430     @Ignore("second edit message corrupted")
431     @Test(expected = NetconfDocumentedException.class)
432     public void testConfigNetconfReplaceDefaultEx() throws Exception {
433
434         createModule(INSTANCE_NAME);
435
436         edit("netconfMessages/editConfig.xml");
437         edit("netconfMessages/editConfig_replace_default_ex.xml");
438     }
439
440     @Test
441     public void testConfigNetconfReplaceDefault() throws Exception {
442
443         createModule(INSTANCE_NAME);
444
445         edit("netconfMessages/editConfig.xml");
446         commit();
447         Document response = getConfigRunning();
448         final int allInstances = response.getElementsByTagName("module").getLength();
449
450         edit("netconfMessages/editConfig_replace_default.xml");
451
452         commit();
453         response = getConfigRunning();
454
455         final int afterReplace = response.getElementsByTagName("module").getLength();
456         assertEquals(4, allInstances);
457         assertEquals(2, afterReplace);
458     }
459
460     @Test
461     public void testSameAttrDifferentNamespaces() throws Exception {
462         try {
463             edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
464             fail();
465         } catch (NetconfDocumentedException e) {
466             String message = e.getMessage();
467             assertContainsString(message, "Element simpleInt present multiple times with different namespaces");
468             assertContainsString(message, TEST_NAMESPACE);
469             assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
470         }
471     }
472
473     @Test
474     public void testDifferentNamespaceInTO() throws Exception {
475         try {
476             edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
477             fail();
478         } catch (NetconfDocumentedException e) {
479             String message = e.getMessage();
480             assertContainsString(message, "Unrecognised elements");
481             assertContainsString(message, "simple-int2");
482             assertContainsString(message, "dto_d");
483         }
484     }
485
486     @Test
487     public void testSameAttrDifferentNamespacesList() throws Exception {
488         try {
489             edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
490             fail();
491         } catch (NetconfDocumentedException e) {
492             String message = e.getMessage();
493             assertContainsString(message, "Element allow-user present multiple times with different namespaces");
494             assertContainsString(message, TEST_NAMESPACE);
495             assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
496         }
497     }
498
499     @Test
500     public void testTypeNameConfigAttributeMatching() throws Exception {
501         edit("netconfMessages/editConfig.xml");
502         commit();
503         edit("netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml");
504         commit();
505
506         Document response = getConfigRunning();
507         checkTypeConfigAttribute(response);
508     }
509
510     // TODO add <modules operation="replace"> functionality
511     @Test(expected = NetconfDocumentedException.class)
512     public void testConfigNetconfReplaceModuleEx() throws Exception {
513
514         createModule(INSTANCE_NAME);
515
516         edit("netconfMessages/editConfig.xml");
517         edit("netconfMessages/editConfig_replace_module_ex.xml");
518     }
519
520     @Test
521     public void testUnrecognisedConfigElements() throws Exception {
522
523         String format = "netconfMessages/unrecognised/editConfig_unrecognised%d.xml";
524         final int TESTS_COUNT = 8;
525
526         for (int i = 0; i < TESTS_COUNT; i++) {
527             String file = String.format(format, i + 1);
528             LOG.info("Reading {}", file);
529             try {
530                 edit(file);
531             } catch (NetconfDocumentedException e) {
532                 assertContainsString(e.getMessage(), "Unrecognised elements");
533                 assertContainsString(e.getMessage(), "unknownAttribute");
534                 continue;
535             }
536             fail("Unrecognised test should throw exception " + file);
537         }
538     }
539
540     @Test
541     @Ignore
542     // FIXME
543     public void testConfigNetconfReplaceModule() throws Exception {
544
545         createModule(INSTANCE_NAME);
546
547         edit("netconfMessages/editConfig.xml");
548         commit();
549         Document response = getConfigRunning();
550         final int allInstances = response.getElementsByTagName("instance").getLength();
551
552         edit("netconfMessages/editConfig_replace_module.xml");
553
554         commit();
555         response = getConfigRunning();
556         final int afterReplace = response.getElementsByTagName("instance").getLength();
557
558         assertEquals(4 + 4 /* Instances from services */, allInstances);
559         assertEquals(3 + 3, afterReplace);
560     }
561
562     @Test(expected = NetconfDocumentedException.class)
563     public void testEx() throws Exception {
564
565         commit();
566     }
567
568     @Test
569     public void testEx2() throws Exception {
570         assertContainsElement(discard(), readXmlToElement("<ok xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
571     }
572
573     private Document discard() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
574         DiscardChanges discardOp = new DiscardChanges(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
575         return executeOp(discardOp, "netconfMessages/discardChanges.xml");
576     }
577
578     private void checkBinaryLeafEdited(final Document response) throws NodeTestException, SAXException, IOException {
579         assertContainsElement(response, readXmlToElement("<binaryLeaf xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">YmluYXJ5</binaryLeaf>"));
580         assertContainsElement(response, readXmlToElement("<binaryLeaf xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ZGVmYXVsdEJpbg==</binaryLeaf>"));
581     }
582
583     private void checkTypedefs(final Document response) throws NodeTestException, SAXException, IOException {
584
585         assertContainsElement(response, readXmlToElement("<extended xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">10</extended>"));
586         // Default
587         assertContainsElement(response, readXmlToElement("<extended xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">1</extended>"));
588
589         assertContainsElement(response, readXmlToElement("<extended-twice xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">20</extended-twice>"));
590         // Default
591         assertContainsElement(response, readXmlToElement("<extended-twice xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2</extended-twice>"));
592
593         assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">TWO</extended-enum>"));
594         // Default
595         assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ONE</extended-enum>"));
596     }
597
598     private void assertContainsString(String string, String substring) {
599         assertThat(string, CoreMatchers.containsString(substring));
600     }
601
602     private void checkEnum(final Document response) throws Exception {
603
604         String expectedEnumContent = "TWO";
605
606         XMLAssert.assertXpathEvaluatesTo(expectedEnumContent,
607                 getXpathForNetconfImplSubnode(INSTANCE_NAME,"extended-enum"),
608                 response);
609     }
610
611     private void checkTestingDeps(Document response) {
612         int testingDepsSize = response.getElementsByTagName("testing-deps").getLength();
613         assertEquals(2, testingDepsSize);
614     }
615
616     private String getXpathForNetconfImplSubnode(String instanceName, String subnode) {
617         return "/urn:ietf:params:xml:ns:netconf:base:1.0:rpc-reply" +
618                 "/urn:ietf:params:xml:ns:netconf:base:1.0:data" +
619                 "/urn:opendaylight:params:xml:ns:yang:controller:config:modules" +
620                 "/module[name='"+instanceName+"']" +
621                 "/urn:opendaylight:params:xml:ns:yang:controller:test:impl:impl-netconf" +
622                 "/urn:opendaylight:params:xml:ns:yang:controller:test:impl:"+subnode;
623     }
624
625     private void checkTypeConfigAttribute(Document response) throws Exception {
626
627         Map<String,String> namesToTypeValues = ImmutableMap.of("instance-from-code", "configAttributeType",
628                 "test2", "default-string");
629         for (Entry<String, String> nameToExpectedValue : namesToTypeValues.entrySet()) {
630             XMLAssert.assertXpathEvaluatesTo(nameToExpectedValue.getValue(),
631                     getXpathForNetconfImplSubnode(nameToExpectedValue.getKey(),"type"),
632                     response);
633         }
634     }
635
636     private Map<String, Map<String, ModuleMXBeanEntry>> getMbes() throws Exception {
637         final List<InputStream> yangDependencies = getYangs();
638
639         final Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries = Maps.newHashMap();
640
641         YangParserImpl yangParser = new YangParserImpl();
642         final SchemaContext schemaContext = yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(yangDependencies).values()));
643         YangStoreService yangStoreService = new YangStoreService(new SchemaContextProvider() {
644             @Override
645             public SchemaContext getSchemaContext() {
646                 return schemaContext ;
647             }
648         }, mockedContext);
649         mBeanEntries.putAll(yangStoreService.getModuleMXBeanEntryMap());
650
651         return mBeanEntries;
652     }
653
654     private Set<org.opendaylight.yangtools.yang.model.api.Module> getModules() throws Exception {
655         SchemaContext resolveSchemaContext = getSchemaContext();
656         return resolveSchemaContext.getModules();
657     }
658
659     private SchemaContext getSchemaContext() throws Exception {
660         final List<InputStream> yangDependencies = getYangs();
661         YangParserImpl parser = new YangParserImpl();
662
663         Set<Module> allYangModules = parser.parseYangModelsFromStreams(yangDependencies);
664
665         return parser.resolveSchemaContext(Sets
666                 .newHashSet(allYangModules));
667     }
668
669     @Test
670     public void testConfigNetconfRuntime() throws Exception {
671
672         createModule(INSTANCE_NAME);
673
674         edit("netconfMessages/editConfig.xml");
675         checkBinaryLeafEdited(getConfigCandidate());
676
677         // check after edit
678         commit();
679         Document response = get();
680
681         assertEquals(2/*With runtime beans*/ + 2 /*Without runtime beans*/, getElementsSize(response, "module"));
682         // data from state
683         assertEquals(2, getElementsSize(response, "asdf"));
684         // data from running config
685         assertEquals(2, getElementsSize(response, "simple-short"));
686
687         assertEquals(8, getElementsSize(response, "inner-running-data"));
688         assertEquals(8, getElementsSize(response, "deep2"));
689         assertEquals(8 * 4, getElementsSize(response, "inner-inner-running-data"));
690         assertEquals(8 * 4, getElementsSize(response, "deep3"));
691         assertEquals(8 * 4 * 2, getElementsSize(response, "list-of-strings"));
692         assertEquals(8, getElementsSize(response, "inner-running-data-additional", "urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
693         assertEquals(8, getElementsSize(response, "deep4"));
694         // TODO assert keys
695
696         RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
697
698         response = executeOp(netconf, "netconfMessages/rpc.xml");
699         assertContainsElementWithText(response, "testarg1");
700
701         response = executeOp(netconf, "netconfMessages/rpcInner.xml");
702         Document expectedReplyOk = XmlFileLoader.xmlFileToDocument("netconfMessages/rpc-reply_ok.xml");
703         XMLUnit.setIgnoreWhitespace(true);
704         XMLAssert.assertXMLEqual(expectedReplyOk, response);
705
706         response = executeOp(netconf, "netconfMessages/rpcInnerInner.xml");
707         assertContainsElementWithText(response, "true");
708
709         response = executeOp(netconf, "netconfMessages/rpcInnerInner_complex_output.xml");
710         assertContainsElementWithText(response, "1");
711         assertContainsElementWithText(response, "2");
712     }
713
714     private Document get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
715         Get getOp = new Get(transactionProvider, yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
716         return executeOp(getOp, "netconfMessages/get.xml");
717     }
718
719     private int getElementsSize(Document response, String elementName) {
720         return response.getElementsByTagName(elementName).getLength();
721     }
722
723     private int getElementsSize(Document response, String elementName, String namespace) {
724         return response.getElementsByTagNameNS(namespace, elementName).getLength();
725     }
726
727     private Document executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException,
728             SAXException, IOException, NetconfDocumentedException {
729
730         final Document request = XmlFileLoader.xmlFileToDocument(filename);
731
732         LOG.debug("Executing netconf operation\n{}", XmlUtil.toString(request));
733         HandlingPriority priority = op.canHandle(request);
734
735         Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE);
736
737         final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
738         LOG.debug("Got response\n{}", XmlUtil.toString(response));
739         return response;
740     }
741
742     private List<InputStream> getYangs() throws FileNotFoundException {
743         List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
744                 "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
745                 "/META-INF/yang/test-groups.yang", "/META-INF/yang/ietf-inet-types.yang");
746         final Collection<InputStream> yangDependencies = new ArrayList<>();
747         for (String path : paths) {
748             final InputStream is = Preconditions
749                     .checkNotNull(getClass().getResourceAsStream(path), path + " not found");
750             yangDependencies.add(is);
751         }
752         return Lists.newArrayList(yangDependencies);
753     }
754
755     private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName)
756             throws InstanceAlreadyExistsException, InstanceNotFoundException {
757         mxBean.setSimpleInt((long) 44);
758         mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 });
759         final DtoD dtob = getDtoD();
760         mxBean.setDtoD(dtob);
761         //
762         final DtoC dtoa = getDtoC();
763         mxBean.setDtoC(dtoa);
764         mxBean.setSimpleBoolean(false);
765         //
766         final Peers p1 = new Peers();
767         p1.setCoreSize(44L);
768         p1.setPort("port1");
769         p1.setSimpleInt3(456);
770         final Peers p2 = new Peers();
771         p2.setCoreSize(44L);
772         p2.setPort("port23");
773         p2.setSimpleInt3(456);
774         mxBean.setPeers(Lists.<Peers> newArrayList(p1, p2));
775         // //
776         mxBean.setSimpleLong(454545L);
777         mxBean.setSimpleLong2(44L);
778         mxBean.setSimpleBigInteger(BigInteger.valueOf(999L));
779         mxBean.setSimpleByte(new Byte((byte) 4));
780         mxBean.setSimpleShort(new Short((short) 4));
781         mxBean.setSimpleTest(545);
782
783         mxBean.setComplexList(Lists.<ComplexList> newArrayList());
784         mxBean.setSimpleList(Lists.<Integer> newArrayList());
785
786         final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName);
787         int i = 1;
788         for (Class<? extends AbstractServiceInterface> sInterface : factory2.getImplementedServiceIntefaces()) {
789             ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
790             transaction.saveServiceReference(
791                     transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++,
792                     testingDepOn);
793
794         }
795         mxBean.setTestingDep(testingDepOn);
796     }
797
798     private static DtoD getDtoD() {
799         final DtoD dtob = new DtoD();
800         dtob.setSimpleInt1((long) 444);
801         dtob.setSimpleInt2((long) 4444);
802         dtob.setSimpleInt3(454);
803         final ComplexDtoBInner dtobInner = new ComplexDtoBInner();
804         final Deep deep = new Deep();
805         deep.setSimpleInt3(4);
806         dtobInner.setDeep(deep);
807         dtobInner.setSimpleInt3(44);
808         dtobInner.setSimpleList(Lists.newArrayList(4));
809         dtob.setComplexDtoBInner(Lists.newArrayList(dtobInner));
810         dtob.setSimpleList(Lists.newArrayList(4));
811         return dtob;
812     }
813
814     private static DtoC getDtoC() {
815         final DtoC dtoa = new DtoC();
816         // dtoa.setSimpleArg((long) 55);
817         final DtoAInner dtoAInner = new DtoAInner();
818         final DtoAInnerInner dtoAInnerInner = new DtoAInnerInner();
819         dtoAInnerInner.setSimpleArg(456L);
820         dtoAInner.setDtoAInnerInner(dtoAInnerInner);
821         dtoAInner.setSimpleArg(44L);
822         dtoa.setDtoAInner(dtoAInner);
823         return dtoa;
824     }
825
826 }