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.protobuff.messages.common.SimpleNormalizedNodeMessage;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
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.Collection;
66 import java.util.Collections;
67 import java.util.Date;
68 import java.util.List;
74 * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to
75 * create the serialization of NormalizedNode using the ProtocolBuffer
82 public class NormalizedNodeXmlConverterTest {
83 private static final Logger logger = LoggerFactory
84 .getLogger(NormalizedNodeXmlConverterTest.class);
85 public static final String NAMESPACE =
86 "urn:opendaylight:params:xml:ns:yang:controller:test";
87 private static Date revision;
88 private ContainerNode expectedNode;
89 private ContainerSchemaNode containerNode;
90 private String xmlPath;
94 revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
95 } catch (ParseException e) {
96 throw new RuntimeException(e);
100 public static DataSchemaNode getSchemaNode(final SchemaContext context,
101 final String moduleName, final String childNodeName) {
102 for (Module module : context.getModules()) {
103 if (module.getName().equals(moduleName)) {
104 DataSchemaNode found =
105 findChildNode(module.getChildNodes(), childNodeName);
106 Preconditions.checkState(found != null, "Unable to find %s",
111 throw new IllegalStateException("Unable to find child node "
115 static DataSchemaNode findChildNode(final Collection<DataSchemaNode> children, final String name) {
116 List<DataNodeContainer> containers = Lists.newArrayList();
118 for (DataSchemaNode dataSchemaNode : children) {
119 if (dataSchemaNode.getQName().getLocalName().equals(name)) {
120 return dataSchemaNode;
122 if (dataSchemaNode instanceof DataNodeContainer) {
123 containers.add((DataNodeContainer) dataSchemaNode);
124 } else if (dataSchemaNode instanceof ChoiceNode) {
125 containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
129 for (DataNodeContainer container : containers) {
130 DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
131 if (retVal != null) {
139 public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(
140 final String localName) {
141 return new YangInstanceIdentifier.NodeIdentifier(QName.create(
142 URI.create(NAMESPACE), revision, localName));
145 public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(
146 final String... childNames) {
147 Set<QName> qn = Sets.newHashSet();
149 for (String childName : childNames) {
150 qn.add(getNodeIdentifier(childName).getNodeType());
153 return new YangInstanceIdentifier.AugmentationIdentifier(qn);
157 public static ContainerNode augmentChoiceExpectedNode() {
159 DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b =
160 Builders.containerBuilder();
161 b.withNodeIdentifier(getNodeIdentifier("container"));
165 .withNodeIdentifier(getNodeIdentifier("ch2"))
167 Builders.leafBuilder()
168 .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2")
173 .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
178 getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
179 .withValue("2").build()).build()).build());
183 .withNodeIdentifier(getNodeIdentifier("ch3"))
185 Builders.leafBuilder()
186 .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3")
190 .augmentationBuilder()
191 .withNodeIdentifier(getAugmentIdentifier("augLeaf"))
193 Builders.leafBuilder()
194 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
195 .withValue("augment").build()).build());
198 .augmentationBuilder()
199 .withNodeIdentifier(getAugmentIdentifier("ch"))
203 .withNodeIdentifier(getNodeIdentifier("ch"))
205 Builders.leafBuilder()
206 .withNodeIdentifier(getNodeIdentifier("c1Leaf"))
207 .withValue("1").build())
210 .augmentationBuilder()
212 getAugmentIdentifier("c1Leaf_AnotherAugment",
218 getNodeIdentifier("c1Leaf_AnotherAugment"))
219 .withValue("1").build())
224 getNodeIdentifier("deepChoice"))
229 getNodeIdentifier("deepLeafc1"))
230 .withValue("1").build()).build())
231 .build()).build()).build());
238 public void init(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
240 SchemaContext schema = parseTestSchema(yangPath);
241 this.xmlPath = xmlPath;
243 (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
244 this.expectedNode = expectedNode;
247 SchemaContext parseTestSchema(final String yangPath) throws Exception {
249 YangParserImpl yangParserImpl = new YangParserImpl();
251 NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath);
252 ArrayList<InputStream> al = new ArrayList<InputStream>();
254 Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(al);
255 return yangParserImpl.resolveSchemaContext(modules);
261 public void testConversionWithAugmentChoice() throws Exception {
262 init("/augment_choice.yang", "/augment_choice.xml",
263 augmentChoiceExpectedNode());
264 Document doc = loadDocument(xmlPath);
266 ContainerNode built =
267 DomToNormalizedNodeParserFactory
268 .getInstance(DomUtils.defaultValueCodecProvider())
269 .getContainerNodeParser()
270 .parse(Collections.singletonList(doc.getDocumentElement()),
273 if (expectedNode != null) {
274 junit.framework.Assert.assertEquals(expectedNode, built);
277 logger.info("{}", built);
279 Iterable<Element> els =
280 DomFromNormalizedNodeSerializerFactory
281 .getInstance(XmlDocumentUtils.getDocument(),
282 DomUtils.defaultValueCodecProvider())
283 .getContainerNodeSerializer().serialize(containerNode, built);
285 Element el = els.iterator().next();
287 XMLUnit.setIgnoreWhitespace(true);
288 XMLUnit.setIgnoreComments(true);
290 System.out.println(toString(doc.getDocumentElement()));
291 System.out.println(toString(el));
294 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
295 XMLUnit.buildTestDocument(toString(el))).similar();
298 private static ContainerNode listLeafListWithAttributes() {
299 DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b =
300 Builders.containerBuilder();
301 b.withNodeIdentifier(getNodeIdentifier("container"));
303 CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder =
304 Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list"));
306 Map<QName, Object> predicates = Maps.newHashMap();
307 predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
309 DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder =
310 Builders.mapEntryBuilder().withNodeIdentifier(
311 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
312 getNodeIdentifier("list").getNodeType(), predicates));
313 NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> uint32InListBuilder =
314 Builders.leafBuilder().withNodeIdentifier(
315 getNodeIdentifier("uint32InList"));
317 list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
319 listBuilder.withChild(list1Builder.build());
320 b.withChild(listBuilder.build());
322 NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder =
323 Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
324 booleanBuilder.withValue(false);
325 b.withChild(booleanBuilder.build());
327 ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder =
328 Builders.leafSetBuilder().withNodeIdentifier(
329 getNodeIdentifier("leafList"));
331 NormalizedNodeBuilder<YangInstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder =
332 Builders.leafSetEntryBuilder().withNodeIdentifier(
333 new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList")
334 .getNodeType(), "a"));
336 leafList1Builder.withValue("a");
338 leafListBuilder.withChild(leafList1Builder.build());
339 b.withChild(leafListBuilder.build());
346 public void testConversionWithAttributes() throws Exception {
347 init("/test.yang", "/simple_xml_with_attributes.xml",
348 listLeafListWithAttributes());
349 Document doc = loadDocument(xmlPath);
351 ContainerNode built =
352 DomToNormalizedNodeParserFactory
353 .getInstance(DomUtils.defaultValueCodecProvider())
354 .getContainerNodeParser()
355 .parse(Collections.singletonList(doc.getDocumentElement()),
358 if (expectedNode != null) {
359 junit.framework.Assert.assertEquals(expectedNode, built);
362 logger.info("{}", built);
364 Iterable<Element> els =
365 DomFromNormalizedNodeSerializerFactory
366 .getInstance(XmlDocumentUtils.getDocument(),
367 DomUtils.defaultValueCodecProvider())
368 .getContainerNodeSerializer().serialize(containerNode, built);
370 Element el = els.iterator().next();
372 XMLUnit.setIgnoreWhitespace(true);
373 XMLUnit.setIgnoreComments(true);
375 System.out.println(toString(doc.getDocumentElement()));
376 System.out.println(toString(el));
379 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
380 XMLUnit.buildTestDocument(toString(el))).similar();
384 private Document loadDocument(final String xmlPath) throws Exception {
385 InputStream resourceAsStream =
386 NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath);
388 Document currentConfigElement = readXmlToDocument(resourceAsStream);
389 Preconditions.checkNotNull(currentConfigElement);
390 return currentConfigElement;
393 private static final DocumentBuilderFactory BUILDERFACTORY;
396 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
397 factory.setNamespaceAware(true);
398 factory.setCoalescing(true);
399 factory.setIgnoringElementContentWhitespace(true);
400 factory.setIgnoringComments(true);
401 BUILDERFACTORY = factory;
404 private Document readXmlToDocument(final InputStream xmlContent)
405 throws IOException, SAXException {
406 DocumentBuilder dBuilder;
408 dBuilder = BUILDERFACTORY.newDocumentBuilder();
409 } catch (ParserConfigurationException e) {
410 throw new RuntimeException("Failed to parse XML document", e);
412 Document doc = dBuilder.parse(xmlContent);
414 doc.getDocumentElement().normalize();
418 public static String toString(final Element xml) {
420 Transformer transformer =
421 TransformerFactory.newInstance().newTransformer();
422 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
424 StreamResult result = new StreamResult(new StringWriter());
425 DOMSource source = new DOMSource(xml);
426 transformer.transform(source, result);
428 return result.getWriter().toString();
429 } catch (IllegalArgumentException | TransformerFactoryConfigurationError
430 | TransformerException e) {
431 throw new RuntimeException("Unable to serialize xml element " + xml, e);
436 public void testConversionToNormalizedXml() throws Exception {
437 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
438 EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"),
439 augmentChoiceExpectedNode());
440 Document expectedDoc = loadDocument("/augment_choice.xml");
441 Document convertedDoc =
442 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
443 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
444 System.out.println(toString(convertedDoc.getDocumentElement()));
445 XMLUnit.setIgnoreWhitespace(true);
446 XMLUnit.setIgnoreComments(true);
447 new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
448 .getDocumentElement())),
449 XMLUnit.buildTestDocument(toString(convertedDoc
450 .getDocumentElement()))).similar();
451 System.out.println(toString(expectedDoc.getDocumentElement()));
457 public void testConversionFromXmlToNormalizedNode() throws Exception {
458 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
459 EncoderDecoderUtil.encode(parseTestSchema("/test.yang"),
460 listLeafListWithAttributes());
461 Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml");
462 Document convertedDoc =
463 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
464 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
465 System.out.println(toString(convertedDoc.getDocumentElement()));
466 XMLUnit.setIgnoreWhitespace(true);
467 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);