2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the terms of the Eclipse
5 * Public License v1.0 which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore.util;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Lists;
12 import com.google.common.collect.Maps;
13 import com.google.common.collect.Sets;
14 import org.custommonkey.xmlunit.Diff;
15 import org.custommonkey.xmlunit.XMLUnit;
16 import org.junit.Test;
17 import org.opendaylight.controller.cluster.datastore.common.SimpleNormalizedNodeMessage;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
25 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
26 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
27 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
28 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
29 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
32 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
33 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
34 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
35 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
37 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.Module;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.xml.sax.SAXException;
47 import javax.xml.parsers.DocumentBuilder;
48 import javax.xml.parsers.DocumentBuilderFactory;
49 import javax.xml.parsers.ParserConfigurationException;
50 import javax.xml.transform.OutputKeys;
51 import javax.xml.transform.Transformer;
52 import javax.xml.transform.TransformerException;
53 import javax.xml.transform.TransformerFactory;
54 import javax.xml.transform.TransformerFactoryConfigurationError;
55 import javax.xml.transform.dom.DOMSource;
56 import javax.xml.transform.stream.StreamResult;
57 import java.io.ByteArrayInputStream;
58 import java.io.IOException;
59 import java.io.InputStream;
60 import java.io.StringWriter;
62 import java.text.ParseException;
63 import java.text.SimpleDateFormat;
64 import java.util.ArrayList;
65 import java.util.Collections;
66 import java.util.Date;
67 import java.util.List;
73 * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to
74 * create the serialization of NormalizedNode using the ProtocolBuffer
81 public class NormalizedNodeXmlConverterTest {
82 private static final Logger logger = LoggerFactory
83 .getLogger(NormalizedNodeXmlConverterTest.class);
84 public static final String NAMESPACE =
85 "urn:opendaylight:params:xml:ns:yang:controller:test";
86 private static Date revision;
87 private ContainerNode expectedNode;
88 private ContainerSchemaNode containerNode;
89 private String xmlPath;
93 revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
94 } catch (ParseException e) {
95 throw new RuntimeException(e);
99 public static DataSchemaNode getSchemaNode(SchemaContext context,
100 String moduleName, String childNodeName) {
101 for (Module module : context.getModules()) {
102 if (module.getName().equals(moduleName)) {
103 DataSchemaNode found =
104 findChildNode(module.getChildNodes(), childNodeName);
105 Preconditions.checkState(found != null, "Unable to find %s",
110 throw new IllegalStateException("Unable to find child node "
114 static DataSchemaNode findChildNode(Set<DataSchemaNode> children, String name) {
115 List<DataNodeContainer> containers = Lists.newArrayList();
117 for (DataSchemaNode dataSchemaNode : children) {
118 if (dataSchemaNode.getQName().getLocalName().equals(name))
119 return dataSchemaNode;
120 if (dataSchemaNode instanceof DataNodeContainer) {
121 containers.add((DataNodeContainer) dataSchemaNode);
122 } else if (dataSchemaNode instanceof ChoiceNode) {
123 containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
127 for (DataNodeContainer container : containers) {
128 DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
129 if (retVal != null) {
137 private static InstanceIdentifier.NodeIdentifier getNodeIdentifier(
139 return new InstanceIdentifier.NodeIdentifier(new QName(
140 URI.create(NAMESPACE), revision, localName));
143 public static InstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(
144 String... childNames) {
145 Set<QName> qn = Sets.newHashSet();
147 for (String childName : childNames) {
148 qn.add(getNodeIdentifier(childName).getNodeType());
151 return new InstanceIdentifier.AugmentationIdentifier(qn);
155 private static ContainerNode augmentChoiceExpectedNode() {
157 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b =
158 Builders.containerBuilder();
159 b.withNodeIdentifier(getNodeIdentifier("container"));
163 .withNodeIdentifier(getNodeIdentifier("ch2"))
165 Builders.leafBuilder()
166 .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2")
171 .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
176 getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
177 .withValue("2").build()).build()).build());
181 .withNodeIdentifier(getNodeIdentifier("ch3"))
183 Builders.leafBuilder()
184 .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3")
188 .augmentationBuilder()
189 .withNodeIdentifier(getAugmentIdentifier("augLeaf"))
191 Builders.leafBuilder()
192 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
193 .withValue("augment").build()).build());
196 .augmentationBuilder()
197 .withNodeIdentifier(getAugmentIdentifier("ch"))
201 .withNodeIdentifier(getNodeIdentifier("ch"))
203 Builders.leafBuilder()
204 .withNodeIdentifier(getNodeIdentifier("c1Leaf"))
205 .withValue("1").build())
208 .augmentationBuilder()
210 getAugmentIdentifier("c1Leaf_AnotherAugment",
216 getNodeIdentifier("c1Leaf_AnotherAugment"))
217 .withValue("1").build())
222 getNodeIdentifier("deepChoice"))
227 getNodeIdentifier("deepLeafc1"))
228 .withValue("1").build()).build())
229 .build()).build()).build());
236 public void init(String yangPath, String xmlPath, ContainerNode expectedNode)
238 SchemaContext schema = parseTestSchema(yangPath);
239 this.xmlPath = xmlPath;
241 (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
242 this.expectedNode = expectedNode;
245 SchemaContext parseTestSchema(String yangPath) throws Exception {
247 YangParserImpl yangParserImpl = new YangParserImpl();
249 NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath);
250 ArrayList<InputStream> al = new ArrayList<InputStream>();
252 Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(al);
253 return yangParserImpl.resolveSchemaContext(modules);
259 public void testConversionWithAugmentChoice() throws Exception {
260 init("/augment_choice.yang", "/augment_choice.xml",
261 augmentChoiceExpectedNode());
262 Document doc = loadDocument(xmlPath);
264 ContainerNode built =
265 DomToNormalizedNodeParserFactory
266 .getInstance(DomUtils.defaultValueCodecProvider())
267 .getContainerNodeParser()
268 .parse(Collections.singletonList(doc.getDocumentElement()),
271 if (expectedNode != null)
272 junit.framework.Assert.assertEquals(expectedNode, built);
274 logger.info("{}", built);
276 Iterable<Element> els =
277 DomFromNormalizedNodeSerializerFactory
278 .getInstance(XmlDocumentUtils.getDocument(),
279 DomUtils.defaultValueCodecProvider())
280 .getContainerNodeSerializer().serialize(containerNode, built);
282 Element el = els.iterator().next();
284 XMLUnit.setIgnoreWhitespace(true);
285 XMLUnit.setIgnoreComments(true);
287 System.out.println(toString(doc.getDocumentElement()));
288 System.out.println(toString(el));
292 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
293 XMLUnit.buildTestDocument(toString(el))).similar();
296 private static ContainerNode listLeafListWithAttributes() {
297 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b =
298 Builders.containerBuilder();
299 b.withNodeIdentifier(getNodeIdentifier("container"));
301 CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder =
302 Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list"));
304 Map<QName, Object> predicates = Maps.newHashMap();
305 predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
307 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder =
308 Builders.mapEntryBuilder().withNodeIdentifier(
309 new InstanceIdentifier.NodeIdentifierWithPredicates(
310 getNodeIdentifier("list").getNodeType(), predicates));
311 NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> uint32InListBuilder =
312 Builders.leafBuilder().withNodeIdentifier(
313 getNodeIdentifier("uint32InList"));
315 list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
317 listBuilder.withChild(list1Builder.build());
318 b.withChild(listBuilder.build());
320 NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder =
321 Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
322 booleanBuilder.withValue(false);
323 b.withChild(booleanBuilder.build());
325 ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder =
326 Builders.leafSetBuilder().withNodeIdentifier(
327 getNodeIdentifier("leafList"));
329 NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder =
330 Builders.leafSetEntryBuilder().withNodeIdentifier(
331 new InstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList")
332 .getNodeType(), "a"));
334 leafList1Builder.withValue("a");
336 leafListBuilder.withChild(leafList1Builder.build());
337 b.withChild(leafListBuilder.build());
344 public void testConversionWithAttributes() throws Exception {
345 init("/test.yang", "/simple_xml_with_attributes.xml",
346 listLeafListWithAttributes());
347 Document doc = loadDocument(xmlPath);
349 ContainerNode built =
350 DomToNormalizedNodeParserFactory
351 .getInstance(DomUtils.defaultValueCodecProvider())
352 .getContainerNodeParser()
353 .parse(Collections.singletonList(doc.getDocumentElement()),
356 if (expectedNode != null)
357 junit.framework.Assert.assertEquals(expectedNode, built);
359 logger.info("{}", built);
361 Iterable<Element> els =
362 DomFromNormalizedNodeSerializerFactory
363 .getInstance(XmlDocumentUtils.getDocument(),
364 DomUtils.defaultValueCodecProvider())
365 .getContainerNodeSerializer().serialize(containerNode, built);
367 Element el = els.iterator().next();
369 XMLUnit.setIgnoreWhitespace(true);
370 XMLUnit.setIgnoreComments(true);
372 System.out.println(toString(doc.getDocumentElement()));
373 System.out.println(toString(el));
377 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
378 XMLUnit.buildTestDocument(toString(el))).similar();
382 private Document loadDocument(String xmlPath) throws Exception {
383 InputStream resourceAsStream =
384 NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath);
386 Document currentConfigElement = readXmlToDocument(resourceAsStream);
387 Preconditions.checkNotNull(currentConfigElement);
388 return currentConfigElement;
391 private static final DocumentBuilderFactory BUILDERFACTORY;
394 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
395 factory.setNamespaceAware(true);
396 factory.setCoalescing(true);
397 factory.setIgnoringElementContentWhitespace(true);
398 factory.setIgnoringComments(true);
399 BUILDERFACTORY = factory;
402 private Document readXmlToDocument(InputStream xmlContent)
403 throws IOException, SAXException {
404 DocumentBuilder dBuilder;
406 dBuilder = BUILDERFACTORY.newDocumentBuilder();
407 } catch (ParserConfigurationException e) {
408 throw new RuntimeException("Failed to parse XML document", e);
410 Document doc = dBuilder.parse(xmlContent);
412 doc.getDocumentElement().normalize();
416 public static String toString(Element xml) {
418 Transformer transformer =
419 TransformerFactory.newInstance().newTransformer();
420 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
422 StreamResult result = new StreamResult(new StringWriter());
423 DOMSource source = new DOMSource(xml);
424 transformer.transform(source, result);
426 return result.getWriter().toString();
427 } catch (IllegalArgumentException | TransformerFactoryConfigurationError
428 | TransformerException e) {
429 throw new RuntimeException("Unable to serialize xml element " + xml, e);
434 public void testConversionToNormalizedXml() throws Exception {
435 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
436 EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"),
437 augmentChoiceExpectedNode());
438 Document expectedDoc = loadDocument("/augment_choice.xml");
439 Document convertedDoc =
440 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
441 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
442 System.out.println(toString(convertedDoc.getDocumentElement()));
443 XMLUnit.setIgnoreWhitespace(true);
444 XMLUnit.setIgnoreComments(true);
446 new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
447 .getDocumentElement())),
448 XMLUnit.buildTestDocument(toString(convertedDoc
449 .getDocumentElement()))).similar();
450 System.out.println(toString(expectedDoc.getDocumentElement()));
456 public void testConversionFromXmlToNormalizedNode() throws Exception {
457 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
458 EncoderDecoderUtil.encode(parseTestSchema("/test.yang"),
459 listLeafListWithAttributes());
460 Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml");
461 Document convertedDoc =
462 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
463 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
464 System.out.println(toString(convertedDoc.getDocumentElement()));
465 XMLUnit.setIgnoreWhitespace(true);
466 XMLUnit.setIgnoreComments(true);
468 new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
469 .getDocumentElement())),
470 XMLUnit.buildTestDocument(toString(convertedDoc
471 .getDocumentElement()))).similar();
472 System.out.println(toString(expectedDoc.getDocumentElement()));
474 // now we will try to convert xml back to normalize node.
476 (ContainerNode) EncoderDecoderUtil.decode(
477 parseTestSchema("/test.yang"), nnXml);
478 junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn);
483 public void testInMemoryTestModelProtoBuffEncoding() throws Exception {
485 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
486 EncoderDecoderUtil.encode(parseTestSchema("/odl-datastore-test.yang"),
487 TestModel.createFamily());
489 Document convertedDoc =
490 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
491 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
492 System.out.println(toString(convertedDoc.getDocumentElement()));
494 // now we will try to convert xml back to normalize node.
496 (ContainerNode) EncoderDecoderUtil.decode(
497 parseTestSchema("/odl-datastore-test.yang"), nnXml);
498 junit.framework.Assert.assertEquals(TestModel.createFamily(), cn);