c730f1392d2fd3921c803fa10f610cc41352eaed
[yangtools.git] / yang / rfc8040-parser-support / src / test / java / org / opendaylight / yangtools / rfc8040 / parser / YangDataExtensionTest.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.yangtools.rfc8040.parser;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import com.google.common.collect.ImmutableSet;
17 import java.io.IOException;
18 import java.net.URI;
19 import java.util.Collection;
20 import org.junit.AfterClass;
21 import org.junit.BeforeClass;
22 import org.junit.Test;
23 import org.opendaylight.yangtools.rfc8040.model.api.YangDataSchemaNode;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.common.QNameModule;
26 import org.opendaylight.yangtools.yang.common.Revision;
27 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
29 import org.opendaylight.yangtools.yang.model.api.Module;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
32 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
33 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
34 import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors;
35 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.InvalidSubstatementException;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.MissingSubstatementException;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
40 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
41 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
42
43 public class YangDataExtensionTest {
44
45     private static final StatementStreamSource FOO_MODULE = sourceForResource(
46             "/yang-data-extension-test/foo.yang");
47     private static final StatementStreamSource FOO_INVALID_1_MODULE = sourceForResource(
48             "/yang-data-extension-test/foo-invalid-1.yang");
49     private static final StatementStreamSource FOO_INVALID_2_MODULE = sourceForResource(
50             "/yang-data-extension-test/foo-invalid-2.yang");
51     private static final StatementStreamSource FOO_INVALID_3_MODULE = sourceForResource(
52             "/yang-data-extension-test/foo-invalid-3.yang");
53     private static final StatementStreamSource BAR_MODULE = sourceForResource(
54             "/yang-data-extension-test/bar.yang");
55     private static final StatementStreamSource BAZ_MODULE = sourceForResource(
56             "/yang-data-extension-test/baz.yang");
57     private static final StatementStreamSource FOOBAR_MODULE = sourceForResource(
58             "/yang-data-extension-test/foobar.yang");
59     private static final StatementStreamSource IETF_RESTCONF_MODULE = sourceForResource(
60             "/yang-data-extension-test/ietf-restconf.yang");
61
62     private static final Revision REVISION = Revision.of("2017-06-01");
63     private static final QNameModule FOO_QNAMEMODULE = QNameModule.create(URI.create("foo"), REVISION);
64     private static final QName MY_YANG_DATA_A = QName.create(FOO_QNAMEMODULE, "my-yang-data-a");
65     private static final QName MY_YANG_DATA_B = QName.create(FOO_QNAMEMODULE, "my-yang-data-b");
66
67     private static CrossSourceStatementReactor reactor;
68
69     @BeforeClass
70     public static void createReactor() {
71         reactor = RFC7950Reactors.vanillaReactorBuilder()
72                 .addStatementSupport(ModelProcessingPhase.FULL_DECLARATION, YangDataStatementSupport.getInstance())
73                 .build();
74     }
75
76     @AfterClass
77     public static void freeReactor() {
78         reactor = null;
79     }
80
81     @Test
82     public void testYangData() throws Exception {
83         final SchemaContext schemaContext = reactor.newBuild().addSources(FOO_MODULE, IETF_RESTCONF_MODULE)
84                 .buildEffective();
85         assertNotNull(schemaContext);
86
87         final Collection<? extends ExtensionDefinition> extensions = schemaContext.getExtensions();
88         assertEquals(1, extensions.size());
89
90         final Module foo = schemaContext.findModule(FOO_QNAMEMODULE).get();
91         final Collection<? extends UnknownSchemaNode> unknownSchemaNodes = foo.getUnknownSchemaNodes();
92         assertEquals(2, unknownSchemaNodes.size());
93
94         YangDataSchemaNode myYangDataANode = null;
95         YangDataSchemaNode myYangDataBNode = null;
96         for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
97             assertTrue(unknownSchemaNode instanceof YangDataSchemaNode);
98             final YangDataSchemaNode yangDataSchemaNode = (YangDataSchemaNode) unknownSchemaNode;
99             if (MY_YANG_DATA_A.equals(yangDataSchemaNode.getQName())) {
100                 myYangDataANode = yangDataSchemaNode;
101             } else if (MY_YANG_DATA_B.equals(yangDataSchemaNode.getQName())) {
102                 myYangDataBNode = yangDataSchemaNode;
103             }
104         }
105
106         assertNotNull(myYangDataANode);
107         assertNotNull(myYangDataBNode);
108
109         assertNotNull(myYangDataANode.getContainerSchemaNode());
110         assertNotNull(myYangDataBNode.getContainerSchemaNode());
111     }
112
113     @Test
114     public void testConfigStatementBeingIgnoredInYangDataBody() throws Exception {
115         final SchemaContext schemaContext = reactor.newBuild().addSources(BAZ_MODULE, IETF_RESTCONF_MODULE)
116                 .buildEffective();
117         assertNotNull(schemaContext);
118
119         final Module baz = schemaContext.findModule("baz", REVISION).get();
120         final Collection<? extends UnknownSchemaNode> unknownSchemaNodes = baz.getUnknownSchemaNodes();
121         assertEquals(1, unknownSchemaNodes.size());
122
123         final UnknownSchemaNode unknownSchemaNode = unknownSchemaNodes.iterator().next();
124         assertTrue(unknownSchemaNode instanceof YangDataSchemaNode);
125         final YangDataSchemaNode myYangDataNode = (YangDataSchemaNode) unknownSchemaNode;
126         assertNotNull(myYangDataNode);
127
128         final ContainerSchemaNode contInYangData = myYangDataNode.getContainerSchemaNode();
129         assertNotNull(contInYangData);
130         assertTrue(contInYangData.isConfiguration());
131         final ContainerSchemaNode innerCont = (ContainerSchemaNode) contInYangData.findDataChildByName(
132                 QName.create(baz.getQNameModule(), "inner-cont")).get();
133         assertNotNull(innerCont);
134         assertTrue(innerCont.isConfiguration());
135         final ContainerSchemaNode grpCont = (ContainerSchemaNode) contInYangData.findDataChildByName(
136                 QName.create(baz.getQNameModule(), "grp-cont")).get();
137         assertNotNull(grpCont);
138         assertTrue(grpCont.isConfiguration());
139     }
140
141     @Test
142     public void testIfFeatureStatementBeingIgnoredInYangDataBody() throws Exception {
143         final SchemaContext schemaContext = reactor.newBuild().setSupportedFeatures(ImmutableSet.of())
144                 .addSources(FOOBAR_MODULE, IETF_RESTCONF_MODULE).buildEffective();
145         assertNotNull(schemaContext);
146
147         final Module foobar = schemaContext.findModule("foobar", REVISION).get();
148         final Collection<? extends UnknownSchemaNode> unknownSchemaNodes = foobar.getUnknownSchemaNodes();
149         assertEquals(1, unknownSchemaNodes.size());
150
151         final UnknownSchemaNode unknownSchemaNode = unknownSchemaNodes.iterator().next();
152         assertTrue(unknownSchemaNode instanceof YangDataSchemaNode);
153         final YangDataSchemaNode myYangDataNode = (YangDataSchemaNode) unknownSchemaNode;
154         assertNotNull(myYangDataNode);
155
156         final ContainerSchemaNode contInYangData = myYangDataNode.getContainerSchemaNode();
157         assertNotNull(contInYangData);
158         final ContainerSchemaNode innerCont = (ContainerSchemaNode) contInYangData.findDataChildByName(
159                 QName.create(foobar.getQNameModule(), "inner-cont")).get();
160         assertNotNull(innerCont);
161         final ContainerSchemaNode grpCont = (ContainerSchemaNode) contInYangData.findDataChildByName(
162                 QName.create(foobar.getQNameModule(), "grp-cont")).get();
163         assertNotNull(grpCont);
164     }
165
166     @Test
167     public void testYangDataBeingIgnored() throws Exception {
168         // yang-data statement is ignored if it does not appear as a top-level statement
169         // i.e., it will not appear in the final SchemaContext
170         final SchemaContext schemaContext = reactor.newBuild().addSources(BAR_MODULE, IETF_RESTCONF_MODULE)
171                 .buildEffective();
172         assertNotNull(schemaContext);
173
174         final Module bar = schemaContext.findModule("bar", REVISION).get();
175         final ContainerSchemaNode cont = (ContainerSchemaNode) bar.findDataChildByName(
176                 QName.create(bar.getQNameModule(), "cont")).get();
177         assertNotNull(cont);
178
179         final Collection<? extends ExtensionDefinition> extensions = schemaContext.getExtensions();
180         assertEquals(1, extensions.size());
181
182         final Collection<? extends UnknownSchemaNode> unknownSchemaNodes = cont.getUnknownSchemaNodes();
183         assertEquals(0, unknownSchemaNodes.size());
184     }
185
186     @Test
187     public void testYangDataWithMissingTopLevelContainer() {
188         try {
189             reactor.newBuild().addSources(FOO_INVALID_1_MODULE, IETF_RESTCONF_MODULE).buildEffective();
190             fail("Exception should have been thrown because of missing top-level container in yang-data statement.");
191         } catch (final ReactorException ex) {
192             final Throwable cause = ex.getCause();
193             assertTrue(cause instanceof MissingSubstatementException);
194             assertTrue(cause.getMessage().startsWith("YANG_DATA is missing CONTAINER. Minimal count is 1."));
195         }
196     }
197
198     @Test
199     public void testYangDataWithTwoTopLevelContainers() {
200         try {
201             reactor.newBuild().addSources(FOO_INVALID_2_MODULE, IETF_RESTCONF_MODULE).buildEffective();
202             fail("Exception should have been thrown because of two top-level containers in yang-data statement.");
203         } catch (final ReactorException ex) {
204             final Throwable cause = ex.getCause();
205             assertTrue(cause instanceof InvalidSubstatementException);
206             assertTrue(cause.getMessage().startsWith("Maximal count of CONTAINER for YANG_DATA is 1, detected 2."));
207         }
208     }
209
210     @Test
211     public void testYangDataWithInvalidToplevelNode() {
212         try {
213             reactor.newBuild().addSources(FOO_INVALID_3_MODULE, IETF_RESTCONF_MODULE).buildEffective();
214             fail("Exception should have been thrown because of invalid top-level node in yang-data statement.");
215         } catch (final ReactorException ex) {
216             final Throwable cause = ex.getCause();
217             assertTrue(cause instanceof InvalidSubstatementException);
218             assertTrue(cause.getMessage().startsWith("LEAF is not valid for YANG_DATA."));
219         }
220     }
221
222     private static StatementStreamSource sourceForResource(final String resourceName) {
223         try {
224             return YangStatementStreamSource.create(YangTextSchemaSource.forResource(resourceName));
225         } catch (IOException | YangSyntaxErrorException e) {
226             throw new IllegalArgumentException("Failed to create source", e);
227         }
228     }
229 }