Remove use of Guava Charsets
[yangtools.git] / yang / yang-data-operations / src / test / java / org / opendaylight / yangtools / yang / data / operations / retest / YangDataOperationsTest.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.yangtools.yang.data.operations.retest;
9
10 import static org.junit.Assert.assertNull;
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.io.Files;
15
16 import java.io.File;
17 import java.io.FileNotFoundException;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.StringWriter;
21 import java.net.URISyntaxException;
22 import java.net.URL;
23 import java.nio.charset.StandardCharsets;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import javax.activation.UnsupportedDataTypeException;
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.ParserConfigurationException;
31 import javax.xml.transform.OutputKeys;
32 import javax.xml.transform.Transformer;
33 import javax.xml.transform.TransformerException;
34 import javax.xml.transform.TransformerFactory;
35 import javax.xml.transform.TransformerFactoryConfigurationError;
36 import javax.xml.transform.dom.DOMSource;
37 import javax.xml.transform.stream.StreamResult;
38
39 import org.junit.Assert;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.junit.runners.Parameterized;
43 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
44 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
45 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
46 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
47 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
48 import org.opendaylight.yangtools.yang.data.operations.DataOperations;
49 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.Module;
52 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
54 import org.w3c.dom.Document;
55 import org.w3c.dom.Element;
56 import org.xml.sax.SAXException;
57
58 @RunWith(Parameterized.class)
59 public class YangDataOperationsTest {
60
61     public static final String CURRENT_XML_NAME = "/current.xml";
62     public static final String MODIFICATION_XML_NAME = "/merge.xml";
63     private static final String XML_FOLDER_NAME = "/xmls";
64     public static final String RESULT_XML_NAME = "/result.xml";
65     private static final Object OPERATION_XML_NAME = "/defaultOperation.txt";
66
67     protected final ContainerSchemaNode containerNode;
68     protected final String testDirName;
69     protected final Optional<ContainerNode> currentConfig;
70     protected final Optional<ContainerNode> modification;
71     protected final ModifyAction modifyAction;
72     private final SchemaContext schema;
73
74     @Parameterized.Parameters()
75     public static Collection<Object[]> data() {
76         return Arrays.asList(new Object[][] {
77                 // Container
78                 { "/containerTest_createContainer" },
79                 { "/containerTest_deleteContainer" },
80                 { "/containerTest_innerContainerContainer" },
81                 { "/containerTest_innerLeavesBaseOperationsContainer" },
82                 { "/containerTest_noneContainer" },
83                 { "/containerTest_removeContainer"},
84                 { "/containerTest_replaceContainer"},
85                 { "/containerTest_choiceActualModificationSameCase"},
86                 { "/containerTest_choiceActualModificationDifferentCases"},
87                 { "/containerTest_choiceActualOneCaseModificationOtherCase"},
88                 //            LeafList
89                 { "/leafListTest" },
90                 // List
91                 { "/listTest" },
92                 // Additional
93                 {"/none_NoChange"},
94                 {"/listTest_alterInnerValue"}
95         });
96     }
97
98     public YangDataOperationsTest(final String testDir) throws Exception {
99         schema = parseTestSchema();
100         containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
101         this.testDirName = testDir;
102
103         currentConfig = loadXmlToCompositeNode(getXmlFolderName() + testDirName + CURRENT_XML_NAME);
104         modification = loadXmlToCompositeNode(getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
105         Preconditions.checkState(modification.isPresent(), "Modification xml has to be present under "
106                 + getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
107
108         modifyAction = loadModifyAction(getXmlFolderName() + testDirName + OPERATION_XML_NAME);
109     }
110
111     protected String getXmlFolderName() {
112         return XML_FOLDER_NAME;
113     }
114
115     // TODO unite testing resources e.g. schemas with yang-data-impl
116     // TODO create extract common testing infrastructure from this and yang-data-impl e.g. xml dom handling
117
118     @Test
119     public void testModification() throws Exception {
120
121         Optional<ContainerNode> result = DataOperations.modify(containerNode,
122                 currentConfig.orNull(), modification.orNull(), modifyAction);
123
124         String expectedResultXmlPath = getXmlFolderName() + testDirName + RESULT_XML_NAME;
125         Optional<ContainerNode> expectedResult = loadXmlToCompositeNode(expectedResultXmlPath);
126
127         if (result.isPresent()) {
128             verifyModificationResult(result, expectedResult);
129         } else {
130             assertNull("Result of modification is empty node, result xml should not be present "
131                     + expectedResultXmlPath, getClass().getResourceAsStream(expectedResultXmlPath));
132         }
133
134     }
135
136     private ModifyAction loadModifyAction(final String path) throws Exception {
137         URL resource = getClass().getResource(path);
138         if (resource == null) {
139             return ModifyAction.MERGE;
140         }
141
142         return ModifyAction.fromXmlValue(Files.toString(new File(resource.toURI()), StandardCharsets.UTF_8).trim());
143     }
144
145     private void verifyModificationResult(final Optional<ContainerNode> result, final Optional<ContainerNode> expectedResult)
146             throws UnsupportedDataTypeException {
147         Assert.assertEquals(
148                 String.format(
149                         "Test result %n %s %n Expected %n %s %n",
150                         toString(toDom(result.get())),
151                         toString(toDom(expectedResult.get()))), expectedResult.get(), result.get());
152     }
153
154     private Element toDom(final ContainerNode container) {
155         Iterable<Element> a =
156                 DomFromNormalizedNodeSerializerFactory.getInstance(newDocument(), DomUtils.defaultValueCodecProvider())
157                 .getContainerNodeSerializer().serialize(containerNode, container);
158         return a.iterator().next();
159     }
160
161     private Document newDocument() {
162         try {
163             return BUILDERFACTORY.newDocumentBuilder().newDocument();
164         } catch (ParserConfigurationException e) {
165             throw new RuntimeException("Failed to parse XML document", e);
166         }
167     }
168
169     private Optional<ContainerNode> loadXmlToCompositeNode(final String xmlPath) throws IOException, SAXException {
170         InputStream resourceAsStream = getClass().getResourceAsStream(xmlPath);
171         if (resourceAsStream == null) {
172             return Optional.absent();
173         }
174
175         Document currentConfigElement = readXmlToDocument(resourceAsStream);
176         Preconditions.checkNotNull(currentConfigElement);
177
178         return Optional.fromNullable(DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider(), schema).getContainerNodeParser().parse(
179                 Collections.singletonList(currentConfigElement.getDocumentElement()), containerNode));
180     }
181
182     SchemaContext parseTestSchema() throws URISyntaxException, FileNotFoundException, ReactorException {
183         File testYang = new File(getClass().getResource("/schemas/test.yang").toURI());
184         return RetestUtils.parseYangSources(testYang);
185     }
186
187     DataSchemaNode getSchemaNode(final SchemaContext context, final String moduleName, final String childNodeName) {
188         for (Module module : context.getModules()) {
189             if (module.getName().equals(moduleName)) {
190                 for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
191                     if (dataSchemaNode.getQName().getLocalName().equals(childNodeName)) {
192                         return dataSchemaNode;
193                     }
194                 }
195             }
196         }
197
198         throw new IllegalStateException("Unable to find child node " + childNodeName);
199     }
200
201     private static final DocumentBuilderFactory BUILDERFACTORY;
202
203     static {
204         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
205         factory.setNamespaceAware(true);
206         factory.setCoalescing(true);
207         factory.setIgnoringElementContentWhitespace(true);
208         factory.setIgnoringComments(true);
209         BUILDERFACTORY = factory;
210     }
211
212     private Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
213         DocumentBuilder dBuilder;
214         try {
215             dBuilder = BUILDERFACTORY.newDocumentBuilder();
216         } catch (ParserConfigurationException e) {
217             throw new RuntimeException("Failed to parse XML document", e);
218         }
219         Document doc = dBuilder.parse(xmlContent);
220
221         doc.getDocumentElement().normalize();
222         return doc;
223     }
224
225     public static String toString(final Element xml) {
226         try {
227             Transformer transformer = TransformerFactory.newInstance().newTransformer();
228             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
229
230             StreamResult result = new StreamResult(new StringWriter());
231             DOMSource source = new DOMSource(xml);
232             transformer.transform(source, result);
233
234             return result.getWriter().toString();
235         } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
236             throw new RuntimeException("Unable to serialize xml element " + xml, e);
237         }
238     }
239
240 }