2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.rfc8040.parser;
10 import static org.hamcrest.CoreMatchers.startsWith;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.jupiter.api.Assertions.assertEquals;
13 import static org.junit.jupiter.api.Assertions.assertFalse;
14 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
15 import static org.junit.jupiter.api.Assertions.assertNotNull;
16 import static org.junit.jupiter.api.Assertions.assertThrows;
18 import java.util.Optional;
19 import org.junit.jupiter.api.Test;
20 import org.opendaylight.yangtools.rfc8040.model.api.YangDataSchemaNode;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.common.Revision;
24 import org.opendaylight.yangtools.yang.common.XMLNamespace;
25 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.stmt.FeatureSet;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.InvalidSubstatementException;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.MissingSubstatementException;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
30 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
32 class YangDataExtensionTest extends AbstractYangDataTest {
33 private static final StatementStreamSource FOO_MODULE = sourceForResource(
34 "/yang-data-extension-test/foo.yang");
35 private static final StatementStreamSource FOO_INVALID_1_MODULE = sourceForResource(
36 "/yang-data-extension-test/foo-invalid-1.yang");
37 private static final StatementStreamSource FOO_INVALID_2_MODULE = sourceForResource(
38 "/yang-data-extension-test/foo-invalid-2.yang");
39 private static final StatementStreamSource FOO_INVALID_3_MODULE = sourceForResource(
40 "/yang-data-extension-test/foo-invalid-3.yang");
41 private static final StatementStreamSource BAR_MODULE = sourceForResource(
42 "/yang-data-extension-test/bar.yang");
43 private static final StatementStreamSource BAZ_MODULE = sourceForResource(
44 "/yang-data-extension-test/baz.yang");
45 private static final StatementStreamSource FOOBAR_MODULE = sourceForResource(
46 "/yang-data-extension-test/foobar.yang");
48 private static final Revision REVISION = Revision.of("2017-06-01");
49 private static final QNameModule FOO_QNAMEMODULE = QNameModule.of(XMLNamespace.of("foo"), REVISION);
52 void testYangData() throws Exception {
53 final var schemaContext = REACTOR.newBuild().addSources(FOO_MODULE, IETF_RESTCONF_MODULE).buildEffective();
54 assertNotNull(schemaContext);
56 final var extensions = schemaContext.getExtensions();
57 assertEquals(1, extensions.size());
59 final var unknownSchemaNodes = schemaContext.findModule(FOO_QNAMEMODULE).orElseThrow().getUnknownSchemaNodes();
60 assertEquals(2, unknownSchemaNodes.size());
61 final var it = unknownSchemaNodes.iterator();
62 assertEquals("my-yang-data-a", assertInstanceOf(YangDataSchemaNode.class, it.next()).getNodeParameter());
63 assertEquals("my-yang-data-b", assertInstanceOf(YangDataSchemaNode.class, it.next()).getNodeParameter());
64 assertFalse(it.hasNext());
68 void testConfigStatementBeingIgnoredInYangDataBody() throws Exception {
69 final var schemaContext = REACTOR.newBuild().addSources(BAZ_MODULE, IETF_RESTCONF_MODULE).buildEffective();
70 assertNotNull(schemaContext);
72 final var baz = schemaContext.findModule("baz", REVISION).orElseThrow();
73 final var unknownSchemaNodes = baz.getUnknownSchemaNodes();
74 assertEquals(1, unknownSchemaNodes.size());
76 final var myYangDataNode = assertInstanceOf(YangDataSchemaNode.class, unknownSchemaNodes.iterator().next());
78 final var yangDataChildren = myYangDataNode.getChildNodes();
79 assertEquals(1, yangDataChildren.size());
81 final var contInYangData = assertInstanceOf(ContainerSchemaNode.class, yangDataChildren.iterator().next());
82 assertEquals(Optional.empty(), contInYangData.effectiveConfig());
83 final var innerCont = assertInstanceOf(ContainerSchemaNode.class,
84 contInYangData.dataChildByName(QName.create(baz.getQNameModule(), "inner-cont")));
85 assertEquals(Optional.empty(), innerCont.effectiveConfig());
86 final var grpCont = assertInstanceOf(ContainerSchemaNode.class,
87 contInYangData.dataChildByName(QName.create(baz.getQNameModule(), "grp-cont")));
88 assertEquals(Optional.empty(), grpCont.effectiveConfig());
92 void testIfFeatureStatementBeingIgnoredInYangDataBody() throws Exception {
93 final var schemaContext = REACTOR.newBuild()
94 .setSupportedFeatures(FeatureSet.of())
95 .addSources(FOOBAR_MODULE, IETF_RESTCONF_MODULE)
97 assertNotNull(schemaContext);
99 final var foobar = schemaContext.findModule("foobar", REVISION).orElseThrow();
100 final var unknownSchemaNodes = foobar.getUnknownSchemaNodes();
101 assertEquals(1, unknownSchemaNodes.size());
103 final var myYangDataNode = assertInstanceOf(YangDataSchemaNode.class, unknownSchemaNodes.iterator().next());
105 final var yangDataChildren = myYangDataNode.getChildNodes();
106 assertEquals(1, yangDataChildren.size());
108 final var contInYangData = assertInstanceOf(ContainerSchemaNode.class, yangDataChildren.iterator().next());
109 assertInstanceOf(ContainerSchemaNode.class,
110 contInYangData.dataChildByName(QName.create(foobar.getQNameModule(), "inner-cont")));
111 assertInstanceOf(ContainerSchemaNode.class,
112 contInYangData.dataChildByName(QName.create(foobar.getQNameModule(), "grp-cont")));
116 void testYangDataBeingIgnored() throws Exception {
117 // yang-data statement is ignored if it does not appear as a top-level statement
118 // i.e., it will not appear in the final SchemaContext
119 final var schemaContext = REACTOR.newBuild().addSources(BAR_MODULE, IETF_RESTCONF_MODULE).buildEffective();
120 assertNotNull(schemaContext);
122 final var bar = schemaContext.findModule("bar", REVISION).orElseThrow();
123 final var cont = assertInstanceOf(ContainerSchemaNode.class,
124 bar.dataChildByName(QName.create(bar.getQNameModule(), "cont")));
126 final var extensions = schemaContext.getExtensions();
127 assertEquals(1, extensions.size());
129 final var unknownSchemaNodes = cont.getUnknownSchemaNodes();
130 assertEquals(0, unknownSchemaNodes.size());
134 void testYangDataWithMissingTopLevelContainer() {
135 final var build = REACTOR.newBuild().addSources(FOO_INVALID_1_MODULE, IETF_RESTCONF_MODULE);
136 final var ex = assertThrows(ReactorException.class, () -> build.buildEffective());
137 final var cause = assertInstanceOf(MissingSubstatementException.class, ex.getCause());
138 assertThat(cause.getMessage(), startsWith("yang-data requires at least one substatement [at "));
142 void testYangDataWithTwoTopLevelContainers() {
143 final var build = REACTOR.newBuild().addSources(FOO_INVALID_2_MODULE, IETF_RESTCONF_MODULE);
144 final var ex = assertThrows(ReactorException.class, () -> build.buildEffective());
145 final var cause = assertInstanceOf(InvalidSubstatementException.class, ex.getCause());
146 assertThat(cause.getMessage(),
147 startsWith("yang-data requires exactly one container data node definition, found ["));