From 1cc90975f5c6d88981bda9e4adc58c319ab04549 Mon Sep 17 00:00:00 2001 From: Jakub Toth Date: Fri, 6 May 2016 11:42:27 +0200 Subject: [PATCH] Bug 5526 - Testing - RestconfModulesService Unit tests for RestconfModulesServiceImpl + repackaging of tests Change-Id: I0cb9c7b753d5c4c54d4d4d393d86787294a0903e Signed-off-by: Jakub Toth --- .../{rest => }/RestConnectorProviderTest.java | 4 +- .../SchemaContextHandlerTest.java | 3 +- .../{builder => }/IdentifierCodecTest.java | 4 +- .../impl/RestconfModulesServiceTest.java | 585 +++++++++++++++ .../impl/RestconfModulesServiceTestUtils.java | 417 +++++++++++ .../impl}/RestconfSchemaServiceTest.java | 2 +- .../impl}/RestconfStreamsServiceTest.java | 3 +- .../resources/modules/ietf-yang-types.yang | 4 +- .../module1.yang | 12 + .../module2.yang | 11 + .../module3.yang | 5 + .../mount-point-1.yang | 11 + .../modules/mount-points/mount-point-1.yang | 3 + .../ietf-inet-types.yang | 418 +++++++++++ .../ietf-yang-types.yang | 417 +++++++++++ .../mount-point-1.yang | 11 + ...module-with-illegal-container-modules.yang | 685 ++++++++++++++++++ ...tconf-module-with-illegal-list-module.yang | 684 +++++++++++++++++ ...module-with-missing-container-modules.yang | 639 ++++++++++++++++ ...tconf-module-with-missing-list-module.yang | 650 +++++++++++++++++ ...module-with-illegal-container-modules.yang | 685 ++++++++++++++++++ 21 files changed, 5243 insertions(+), 10 deletions(-) rename restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/{rest => }/RestConnectorProviderTest.java (98%) rename restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/{rest/impl/schema/context => handlers}/SchemaContextHandlerTest.java (98%) rename restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/{builder => }/IdentifierCodecTest.java (97%) create mode 100644 restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTest.java create mode 100644 restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTestUtils.java rename restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/{impl/services => services/impl}/RestconfSchemaServiceTest.java (99%) rename restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/{impl/services => services/impl}/RestconfStreamsServiceTest.java (99%) create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module1.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module2.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module3.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-illegal-container-modules.yang diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/RestConnectorProviderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/RestConnectorProviderTest.java similarity index 98% rename from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/RestConnectorProviderTest.java rename to restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/RestConnectorProviderTest.java index 623e2c8bd0..9b3b450b74 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/RestConnectorProviderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/RestConnectorProviderTest.java @@ -6,12 +6,13 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.restconf.rest; +package org.opendaylight.restconf; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -24,7 +25,6 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.restconf.RestConnectorProvider; import org.opendaylight.restconf.handlers.SchemaContextHandler; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/schema/context/SchemaContextHandlerTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/handlers/SchemaContextHandlerTest.java similarity index 98% rename from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/schema/context/SchemaContextHandlerTest.java rename to restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/handlers/SchemaContextHandlerTest.java index 6107d67d1e..23a60834d0 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/schema/context/SchemaContextHandlerTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/handlers/SchemaContextHandlerTest.java @@ -5,7 +5,8 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.restconf.rest.impl.schema.context; + +package org.opendaylight.restconf.handlers; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/builder/IdentifierCodecTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/IdentifierCodecTest.java similarity index 97% rename from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/builder/IdentifierCodecTest.java rename to restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/IdentifierCodecTest.java index a10eafef5e..8907e5fcc3 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/builder/IdentifierCodecTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/IdentifierCodecTest.java @@ -5,14 +5,14 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.restconf.parser.builder; + +package org.opendaylight.restconf.parser; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils; -import org.opendaylight.restconf.parser.IdentifierCodec; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTest.java new file mode 100644 index 0000000000..ff100dbdf4 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTest.java @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.restconf.rest.services.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.ALLOWED_KEYWORDS; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.MOUNT_POINT; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_EXISTING_MODULE; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_REGISTERED_MOUNT_POINT; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE_BEHIND_MOUNT_POINT; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.getExpectedModules; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.getExpectedModulesBehindMountPoint; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupCustomRestconfModule; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupCustomRestconfModuleMountPoint; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupMissingRestconfModule; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupMissingRestconfModuleMountPoint; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNormal; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNormalMountPoint; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNullMountPointService; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.verifyModule; +import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.verifyModules; + +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext; +import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.restconf.Draft11.RestconfModule; +import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler; +import org.opendaylight.restconf.handlers.SchemaContextHandler; +import org.opendaylight.restconf.rest.services.api.RestconfModulesService; +import org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TestModule; +import org.opendaylight.restconf.utils.RestconfConstants; +import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; + +/** + * Unit tests of the {@link RestconfModulesServiceImpl} + * + */ +public class RestconfModulesServiceTest { + @Rule public ExpectedException thrown = ExpectedException.none(); + + /** + * Test non-null init of {@link RestconfModulesServiceImpl}. + */ + @Test + public void restconfModulesServiceImplInitTest() { + assertNotNull("Modules service should be initialized and not null", + new RestconfModulesServiceImpl(mock(SchemaContextHandler.class), + mock(DOMMountPointServiceHandler.class))); + } + + /** + * Test getting all modules supported by the server. Retrieved modules are verified by the name, namespace and + * revision. + */ + @Test + public void getModulesTest() throws Exception { + // load schema context with testing modules and correct Restconf module + final RestconfModulesService modulesService = setupNormal(); + + // make test + final NormalizedNodeContext nodeContext = modulesService.getModules(null); + + // check if expected modules were loaded + assertNotNull("Node context cannot be null", nodeContext); + final Collection modules = (Collection) ((ContainerNode) nodeContext .getData()) + .getValue().iterator().next().getValue(); + final Set loadedModules = new HashSet<>(); + + for (final Object node : modules) { + final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet() + .iterator(); + final TestModule loadedModule = new TestModule(); + + while (mapEntries.hasNext()) { + final Entry e = ((SimpleImmutableEntry) mapEntries.next()); + final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName(); + + assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key)); + + switch (key) { + case RestconfMappingNodeConstants.NAME: + loadedModule.setName((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.NAMESPACE: + loadedModule.setNamespace((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.REVISION: + loadedModule.setRevision((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.FEATURE: + break; + } + } + + loadedModules.add(loadedModule); + } + + verifyModules(getExpectedModules(), loadedModules); + } + + /** + * Test getting all modules supported by the mount point. Retrieved modules are verified by the name, namespace and + * revision. + */ + @Test + public void getModulesMountPointTest() throws Exception { + // load testing modules and correct Restconf module behind mount point + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // make test + final NormalizedNodeContext nodeContext = modulesService.getModules(MOUNT_POINT, null); + + // check if expected modules were loaded, use module name as map key + assertNotNull("Node context cannot be null", nodeContext); + final Collection modules = (Collection) ((ContainerNode) nodeContext .getData()) + .getValue().iterator().next().getValue(); + final Set loadedModules = new HashSet<>(); + + for (final Object node : modules) { + final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet() + .iterator(); + final TestModule loadedModule = new TestModule(); + + while (mapEntries.hasNext()) { + final Entry e = ((SimpleImmutableEntry) mapEntries.next()); + final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName(); + + assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key)); + + switch (key) { + case RestconfMappingNodeConstants.NAME: + loadedModule.setName((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.NAMESPACE: + loadedModule.setNamespace((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.REVISION: + loadedModule.setRevision((String) ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.FEATURE: + break; + } + } + + loadedModules.add(loadedModule); + } + + verifyModules(getExpectedModulesBehindMountPoint(), loadedModules); + } + + /** + * Test getting the specific module supported by the server. Module name, revision, namespace and features are + * compared to have expected values. + */ + @Test + public void getModuleTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormal(); + + // get test module + final NormalizedNodeContext nodeContext = modulesService.getModule(TEST_MODULE, null); + + // verify loaded module + assertNotNull("Node context cannot be null", nodeContext); + final MapEntryNode node = ((MapNode) nodeContext.getData()).getValue().iterator().next(); + final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet().iterator(); + verifyModule("module1", "module:1", "2014-01-01", Collections.emptySet(), mapEntries); + } + + /** + * Test getting the specific module supported by the mount point. + */ + @Test + public void getModuleMountPointTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // get test module schemaContextBehindMountPoint mount point + final NormalizedNodeContext nodeContext = modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null); + + // verify loaded module + assertNotNull("Node context cannot be null", nodeContext); + final MapEntryNode node = ((MapNode) nodeContext.getData()).getValue().iterator().next(); + final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet().iterator(); + verifyModule("module1-behind-mount-point", "module:1:behind:mount:point", "2014-02-03", + Collections.emptySet(), mapEntries); + } + + /** + * Test getting all modules supported by the server if Restconf module is null. Test is expected to + * fail with NullPointerException. + */ + @Test + public void getModulesWithoutRestconfModuleNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupMissingRestconfModule(); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModules(null); + } + + /** + * Test getting all modules supported by the mount point if Restconf module is null. Test is expected + * to fail with NullPointerException. + */ + @Test + public void getModulesWithoutRestconfModuleMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupMissingRestconfModuleMountPoint(); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModules(MOUNT_POINT, null); + } + + /** + * Test getting all modules supported by the mount point with null value of + * identifier for mount point. Test is expected to fail with NullPointerException. + */ + @Test + public void getModulesWithNullIdentifierOfMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModules(null, null); + } + + /** + * Test getting all modules supported by the mount point if identifier does + * not contains {@link RestconfConstants#MOUNT}. Catching + * {@link RestconfDocumentedException} and testing error tyupe, error tag and error status code. + */ + @Test + public void getModulesWithoutMountConstantInMountPointIdentifierNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormalMountPoint(); + + try { + modulesService.getModules(MOUNT_POINT.replace("/" + RestconfConstants.MOUNT + "/", ""), null); + fail("Test should fail due to missing " + RestconfConstants.MOUNT + " constant in mount point identifier"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting all modules supported by the server when Restconf module does not contain node with name + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE}. Test is expected to fail with + * RestconfDocumentedException and error type, error tag and error status code are compared to + * expected values. + */ + @Test + public void getModulesRestconfModuleWithMissingContainerModulesNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModule( + "restconf-module-with-missing-container-modules"); + + // make test + try { + modulesService.getModules(null); + fail("Test should fail due to missing " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE + + " node in Restconf module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting all modules supported by the server when Restconf module contains node with name + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} but it is not of type {@link ContainerSchemaNode}. Test is + * expected to fail with IllegalStateException. + */ + @Test + public void getModulesRestconfModuleWithIllegalContainerModulesNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModule( + "restconf-module-with-illegal-container-modules"); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModules(null); + } + + /** + * Test getting all modules supported by the mount point when Restconf module does not contain node with name + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE}. Test is expected to fail with + * RestconfDocumentedException and error type, error tag and error status code are compared to + * expected values. + */ + @Test + public void getModulesRestconfModuleWithMissingContainerModulesMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint( + "restconf-module-with-missing-container-modules"); + + try { + modulesService.getModules(MOUNT_POINT, null); + fail("Test should fail due to missing " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE + + " node in Restconf module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting all modules supported by the mount point when Restconf module contains node with name + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} but it is not of type {@link ContainerSchemaNode}. Test + * is expected to fail with IllegalStateException. + */ + @Test + public void getModulesRestconfModuleWithIllegalContainerModulesMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint( + "restconf-module-with-illegal-container-modules"); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModules(MOUNT_POINT, null); + } + + /** + * Test of getting specific module supported by the server/mount point with null identifier. Test is + * expected to fail with NullPointerException. + */ + @Test + public void getModuleWithNullIdentifierNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = spy(new RestconfModulesServiceImpl( + mock(SchemaContextHandler.class), + mock(DOMMountPointServiceHandler.class))); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModule(null, null); + } + + /** + * Testing getting specific module supported by the server with module identifier which + * does not exist in SchemaContext. Catching {@link RestconfDocumentedException} + * and testing error type, error tag and error status code. + */ + @Test + public void getModuleNotExistModuleNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormal(); + + // make test + try { + modulesService.getModule(NOT_EXISTING_MODULE, null); + fail("Test should fail due to searching for not-existing module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.UNKNOWN_ELEMENT, e.getErrors().get(0).getErrorTag()); + assertEquals("Error code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Testing getting specific module supported by the mount point with module identifier which + * does not exist in SchemaContext. Catching {@link RestconfDocumentedException} + * and testing error type, error tag and error status code. + */ + @Test + public void getModuleNotExistModuleMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // make test + try { + modulesService.getModule(NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT, null); + fail("Test should fail due to searching for not-existing module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.UNKNOWN_ELEMENT, e.getErrors().get(0).getErrorTag()); + assertEquals("Error code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting specific module supported by the server when Restconf module is null. Test is expected to fail + * with NullPointerException. + */ + @Test + public void getModuleWithoutRestconfModuleNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupMissingRestconfModule(); + + this.thrown.expect(NullPointerException.class); + modulesService.getModule(TEST_MODULE, null); + } + + /** + * Test getting specific module supported by the mount point when Restconf module is null. Test is expected to fail + * with NullPointerException. + */ + @Test + public void getModuleWithoutRestconfModuleMountPointNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupMissingRestconfModuleMountPoint(); + + this.thrown.expect(NullPointerException.class); + modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null); + } + + /** + * Test getting specific module supported by the server when Restconf module does not contain node with + * name {@link RestconfModule#MODULE_LIST_SCHEMA_NODE}. Test is expected to fail with + * RestconfDocumentedException and error type, error tag and error status code are compared to + * expected values. + */ + @Test + public void getModuleRestconfModuleWithMissingListModuleNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = + setupCustomRestconfModule("restconf-module-with-missing-list-module"); + + // make test + try { + modulesService.getModule(TEST_MODULE, null); + fail("Test should fail due to missing " + RestconfModule.MODULE_LIST_SCHEMA_NODE + + " node in Restconf module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting specific module supported by the server when Restconf module contains node with name + * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} but it is not of type {@link ListSchemaNode}. Test is expected + * to fail with IllegalStateException. + */ + @Test + public void getModuleRestconfModuleWitIllegalListSchemaNodeNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModule( + "restconf-module-with-illegal-list-module"); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModule(TEST_MODULE, null); + } + + /** + * Test getting specific module supported by the mount point when Restconf module does not contain node with + * name {@link RestconfModule#MODULE_LIST_SCHEMA_NODE}. Test is expected to fail with + * RestconfDocumentedException and error type, error tag and error status code are compared to + * expected values. + */ + @Test + public void getModuleRestconfModuleWithMissingListModuleMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = + setupCustomRestconfModuleMountPoint("restconf-module-with-missing-list-module"); + + // make test + try { + modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null); + fail("Test should fail due to missing " + RestconfModule.MODULE_LIST_SCHEMA_NODE + + " node in Restconf module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Test getting specific module supported by the mount point when Restconf module contains node with name + * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} but it is not of type {@link ListSchemaNode}. Test is expected + * to fail with IllegalStateException. + */ + @Test + public void getModuleRestconfModuleWitIllegalListModuleMountPointNegativeTest() throws Exception { + // prepare condition + final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint( + "restconf-module-with-illegal-list-module"); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null); + } + + /** + * Negative test of specific module supported by the mount point when DOMMountPointServiceHandler + * contains null reference to DOMMountPointService. Test is expected to fail with + * NullPointerException. + */ + @Test + public void getModuleMissingMountPointServiceNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupNullMountPointService(); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null); + } + + /** + * Negative test of getting all modules supported by the mount point when DOMMountPointServiceHandler + * contains null reference to DOMMountPointService. Test is expected to fail with + * NullPointerException. + */ + @Test + public void getModulesMissingMountPointServiceNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupNullMountPointService(); + + // make test + this.thrown.expect(NullPointerException.class); + modulesService.getModules(MOUNT_POINT, null); + } + + /** + * Negative test of getting specific module supported by the mount point when specified mount point is not found + * (it is not registered in DOMMountPointService). Test is expected to fail with + * IllegalStateException. + */ + @Test + public void getModuleMountPointNotFoundNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModule(TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT, null); + } + + /** + * Negative test of getting all modules supported by the mount point when specified mount point is not found (it + * is not registered in DOMMountPointService). Test is expected to fail with + * IllegalStateException. + */ + @Test + public void getModulesMountPointNotFoundNegativeTest() throws Exception { + // prepare conditions + final RestconfModulesService modulesService = setupNormalMountPoint(); + + // make test + this.thrown.expect(IllegalStateException.class); + modulesService.getModules(NOT_REGISTERED_MOUNT_POINT, null); + } +} diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTestUtils.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTestUtils.java new file mode 100644 index 0000000000..3431090914 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTestUtils.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.restconf.rest.services.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableClassToInstanceMap; +import com.google.common.collect.Maps; +import java.io.File; +import java.net.URI; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; +import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl; +import org.opendaylight.controller.md.sal.dom.broker.spi.mount.SimpleDOMMountPoint; +import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils; +import org.opendaylight.restconf.Draft11; +import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler; +import org.opendaylight.restconf.handlers.SchemaContextHandler; +import org.opendaylight.restconf.utils.RestconfConstants; +import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; +import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream; + +class RestconfModulesServiceTestUtils { + static final String MOUNT_POINT = "/mount-point-1:cont/" + RestconfConstants.MOUNT + "/"; + static final String NOT_REGISTERED_MOUNT_POINT = "/mount-point-1:listA/" + RestconfConstants.MOUNT + "/"; + + static final String TEST_MODULE = "module1/2014-01-01"; + static final String NOT_EXISTING_MODULE = "not-existing/2016-01-01"; + + static final String TEST_MODULE_BEHIND_MOUNT_POINT = MOUNT_POINT + + "module1-behind-mount-point/2014-02-03"; + + static final String NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT = MOUNT_POINT + + NOT_EXISTING_MODULE; + + static final String TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT = NOT_REGISTERED_MOUNT_POINT + + "module1-behind-mount-point/2014-02-03"; + + // allowed leafs of list of modules + static final List ALLOWED_KEYWORDS = Arrays.asList( + RestconfMappingNodeConstants.NAME, RestconfMappingNodeConstants.REVISION, + RestconfMappingNodeConstants.NAMESPACE, RestconfMappingNodeConstants.FEATURE); + + static final String MODULES_PATH = "/modules"; + static final String MODULES_WITHOUT_RESTCONF_MODULE_PATH = "/modules/modules-without-restconf-module"; + static final String MOUNT_POINTS_PATH = "/modules/mount-points"; + static final String MODULES_BEHIND_MOUNT_POINT_PATH = "/modules/modules-behind-mount-point"; + + static final String CUSTOM_RESTCONF_MODULES_PATH = + "/modules/restconf-module-testing/"; + static final String CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH = + "/modules/restconf-module-testing-mount-point/"; + + private RestconfModulesServiceTestUtils() { throw new UnsupportedOperationException("Util class"); } + + /** + * Get all expected modules supported by the server + * @return Set of expected modules + * @throws Exception + */ + static final Set getExpectedModules() throws Exception { + return TestRestconfUtils.loadSchemaContext(MODULES_PATH).getModules(); + } + + /** + * Get all expected modules behind mount point + * @return Set of expected modules + * @throws Exception + */ + static final Set getExpectedModulesBehindMountPoint() throws Exception { + return TestRestconfUtils.loadSchemaContext(MODULES_BEHIND_MOUNT_POINT_PATH).getModules(); + } + + /** + * Verify if correct modules were loaded into Restconf module by comparison with expected modules. + * @param expectedModules Expected modules + * @param loadedModules Loaded modules into Restconf module + */ + static final void verifyModules(final Set expectedModules, final Set loadedModules) { + final Set expectedModulesTransformed = new HashSet<>(); + expectedModules.forEach((x) -> expectedModulesTransformed.add( + new TestModule(x.getName(), x.getNamespace(), x.getRevision()))); + assertEquals("Loaded modules are not as expected", expectedModulesTransformed, loadedModules); + } + + /** + * Verify id correct module was loaded into Restconf module by comparison of loaded and expected values of name, + * namespace, revision and features. + * @param expectedName Expected name + * @param expectedNamespace Expected namespace + * @param expectedRevision Expected revision + * @param expectedFeatures Expected features + * @param loadedModuleEntries Loaded values + */ + static final void verifyModule(final String expectedName, final String expectedNamespace, + final String expectedRevision, final Set expectedFeatures, + final Iterator loadedModuleEntries) { + while (loadedModuleEntries.hasNext()) { + final Entry e = ((AbstractMap.SimpleImmutableEntry) loadedModuleEntries.next()); + final String key = ((YangInstanceIdentifier.NodeIdentifier) e.getKey()).getNodeType().getLocalName(); + + assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key)); + + switch (key) { + case RestconfMappingNodeConstants.NAME: + assertEquals("Not correct module was found", + expectedName, ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.NAMESPACE: + assertEquals("Not correct module was found", + expectedNamespace, ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.REVISION: + assertEquals("Not correct module was found", + expectedRevision, ((LeafNode) e.getValue()).getValue()); + break; + case RestconfMappingNodeConstants.FEATURE: + assertEquals("Not correct module was found", + expectedFeatures, ((LeafSetNode) e.getValue()).getValue()); + break; + } + } + } + + /** + * Prepare RestconfModulesServiceImpl with SchemaContext containing correct Restconf + * module and testing modules supported by the server. + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupNormal() throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext(MODULES_PATH)); + return new RestconfModulesServiceImpl(schemaContextHandler, null); + } + + /** + * Prepare RestconfModulesServiceImpl with SchemaContext containing correct Restconf + * module and testing modules behind mount point. + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupNormalMountPoint() throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + + final Collection yangFiles = TestRestconfUtils.loadFiles(MODULES_PATH); + yangFiles.addAll(TestRestconfUtils.loadFiles(MOUNT_POINTS_PATH)); + when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.parseYangSources(yangFiles)); + + final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class); + when(mountPointServiceHandler.get()).thenReturn(getMountPointService()); + + return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler); + } + + /** + * Mock SchemaContext to load custom (modified) Restconf module. + * @param restconfModuleName Path of custom Restconf module + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupCustomRestconfModule(final String restconfModuleName) + throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + final SchemaContext schemaContext = mock(SchemaContext.class); + when(schemaContextHandler.get()).thenReturn(schemaContext); + + when(schemaContext.findModuleByNamespaceAndRevision(any(URI.class), any(Date.class))).thenAnswer(invocation -> { + final Object[] args = invocation.getArguments(); + if (args[0] == Draft11.RestconfModule.IETF_RESTCONF_QNAME.getNamespace() + && args[1] == Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()) { + return parseCustomRestconfSource(restconfModuleName).findModuleByName( + restconfModuleName, (Date) args[1]); + } else { + return TestRestconfUtils.loadSchemaContext(MODULES_PATH).findModuleByNamespaceAndRevision( + (URI) args[0], (Date) args[1]); + } + }); + + when(schemaContext.findModuleByName(any(String.class), any(Date.class))).thenAnswer(invocation -> { + final Object[] args = invocation.getArguments(); + return TestRestconfUtils.loadSchemaContext(MODULES_PATH).findModuleByName( + (String) args[0], (Date) args[1]); + }); + + return new RestconfModulesServiceImpl(schemaContextHandler, null); + } + + /** + * Mock SchemaContext to load custom (modified) Restconf module and prepare mount point. + * @param restconfModuleName + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupCustomRestconfModuleMountPoint( + final String restconfModuleName)throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + when(schemaContextHandler.get()).thenReturn( + parseCustomRestconfSourceMountPoint(restconfModuleName)); + + final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class); + final DOMMountPointService mountPointService = getMountPointService(); + when(mountPointServiceHandler.get()).thenReturn(mountPointService); + + return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler); + } + + /** + * Prepare RestconfModulesServiceImpl with SchemaContext without Restconf module. + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupMissingRestconfModule() throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext( + MODULES_WITHOUT_RESTCONF_MODULE_PATH)); + + return new RestconfModulesServiceImpl(schemaContextHandler, null); + } + + /** + * Prepare RestconfModulesServiceImpl with SchemaContext without Restconf module and + * mount point. + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupMissingRestconfModuleMountPoint() throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext( + MODULES_WITHOUT_RESTCONF_MODULE_PATH)); + + final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class); + when(mountPointServiceHandler.get()).thenReturn(getMountPointService()); + + return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler); + } + + /** + * Prepare RestconfModulesServiceImpl with SchemaContext with testing modules and mount + * points but DOMMountPointServiceHandler will contain null reference to + * DOMMountPointService. + * @return RestconfModulesServiceImpl + * @throws Exception + */ + static final RestconfModulesServiceImpl setupNullMountPointService() throws Exception { + final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class); + + final Collection yangFiles = TestRestconfUtils.loadFiles(MODULES_PATH); + yangFiles.addAll(TestRestconfUtils.loadFiles(MOUNT_POINTS_PATH)); + + when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.parseYangSources(yangFiles)); + + final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class); + when(mountPointServiceHandler.get()).thenReturn(null); + + return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler); + } + + /** + * Create DOMMountPointService with one registered SimpleDOMMountPoint. + * @return DOMMountPointService + * @throws Exception + */ + private static DOMMountPointService getMountPointService() throws Exception { + final DOMMountPointService mountPointService = new DOMMountPointServiceImpl(); + ((DOMMountPointServiceImpl) mountPointService).registerMountPoint( + SimpleDOMMountPoint.create( + YangInstanceIdentifier.builder().node( + QName.create("mount:point:1", "2016-01-01", "cont")).build(), + ImmutableClassToInstanceMap.copyOf(Maps.newHashMap()), + TestRestconfUtils.loadSchemaContext( + MODULES_BEHIND_MOUNT_POINT_PATH))); + + return mountPointService; + } + + /** + * Parse custom sources for creating SchemaContext containing Restconf module specified by + * restconfName its dependencies and one testing module. + * @param restconfName File name of custom Restconf module + * @return SchemaContext containing custom Restconf module + */ + private static SchemaContext parseCustomRestconfSource(final String restconfName) throws Exception { + final String restconf = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_PATH + restconfName + ".yang").getPath(); + final String yangTypes = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_PATH + "ietf-yang-types.yang").getPath(); + final String inetTypes = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_PATH + "ietf-inet-types.yang").getPath(); + final String testModule = TestRestconfUtils.class.getResource( + MODULES_PATH + "/module1.yang").getPath(); + + final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(restconf), restconf))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(yangTypes), yangTypes))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(inetTypes), inetTypes))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(testModule), testModule))); + + return reactor.buildEffective(); + } + + /** + * Parse custom sources for creating SchemaContext containing Restconf module specified by + * restconfName its dependencies and one mount point. + * @param restconfName File name of custom Restconf module + * @return SchemaContext containing custom Restconf module with one mount point + */ + private static SchemaContext parseCustomRestconfSourceMountPoint(String restconfName) throws Exception { + final String restconf = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + + restconfName + "/" + restconfName + ".yang").getPath(); + final String yangTypes = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "ietf-yang-types.yang").getPath(); + final String inetTypes = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "ietf-inet-types.yang").getPath(); + final String mountPoint = TestRestconfUtils.class.getResource( + CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "mount-point-1.yang").getPath(); + + final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(restconf), restconf))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(yangTypes), yangTypes))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(inetTypes), inetTypes))); + reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(mountPoint), mountPoint))); + + return reactor.buildEffective(); + } + + + /** + * Module representation containing name, namespace and revision for easier comparison of modules. + */ + static final class TestModule { + private String name; + private String namespace; + private String revision; + + TestModule() {} + + TestModule(String name, URI namespace, Date revision) { + this.name = name; + this.namespace = namespace.toString(); + this.revision = SimpleDateFormatUtil.getRevisionFormat().format(revision); + } + + String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + + String getNamespace() { + return namespace; + } + + void setNamespace(String namespace) { + this.namespace = namespace; + } + + String getRevision() { + return revision; + } + + void setRevision(String revision) { + this.revision = revision; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TestModule that = (TestModule) o; + + if (name != null ? !name.equals(that.name) : that.name != null) return false; + if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false; + return revision != null ? revision.equals(that.revision) : that.revision == null; + + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (namespace != null ? namespace.hashCode() : 0); + result = 31 * result + (revision != null ? revision.hashCode() : 0); + return result; + } + } +} diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfSchemaServiceTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfSchemaServiceTest.java similarity index 99% rename from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfSchemaServiceTest.java rename to restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfSchemaServiceTest.java index a33c5149e9..b65f28a5b3 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfSchemaServiceTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfSchemaServiceTest.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.restconf.rest.impl.services; +package org.opendaylight.restconf.rest.services.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfStreamsServiceTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfStreamsServiceTest.java similarity index 99% rename from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfStreamsServiceTest.java rename to restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfStreamsServiceTest.java index 85859000d8..acd5ae6dfb 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfStreamsServiceTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfStreamsServiceTest.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.restconf.rest.impl.services; +package org.opendaylight.restconf.rest.services.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -40,7 +40,6 @@ import org.opendaylight.netconf.sal.streams.listeners.Notificator; import org.opendaylight.restconf.Draft11; import org.opendaylight.restconf.handlers.SchemaContextHandler; import org.opendaylight.restconf.rest.services.api.RestconfStreamsService; -import org.opendaylight.restconf.rest.services.impl.RestconfStreamsServiceImpl; import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants; import org.opendaylight.restconf.utils.mapping.RestconfMappingStreamConstants; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; diff --git a/restconf/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang b/restconf/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang index 07e50b3913..c3f952cf25 100644 --- a/restconf/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang +++ b/restconf/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang @@ -260,7 +260,7 @@ reference "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; } - + typedef yang-identifier { type string { length "1..max"; @@ -280,7 +280,7 @@ reference "RFC 6020: YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF)"; - } + } /*** collection of date and time related types ***/ diff --git a/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module1.yang b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module1.yang new file mode 100644 index 0000000000..ab9d967e69 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module1.yang @@ -0,0 +1,12 @@ +module module1 { + namespace "module:1"; + prefix "mod1"; + revision "2014-01-01"; + + rpc dummy-rpc1-module1 { + } + + rpc dummy-rpc2-module1 { + } + +} \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module2.yang b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module2.yang new file mode 100644 index 0000000000..fa792d7bd3 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module2.yang @@ -0,0 +1,11 @@ +module module2 { + namespace "module:2"; + prefix "mod2"; + revision "2014-01-02"; + + rpc dummy-rpc1-module2 { + } + + rpc dummy-rpc2-module2 { + } +} \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module3.yang b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module3.yang new file mode 100644 index 0000000000..39bb690be0 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module3.yang @@ -0,0 +1,5 @@ +module module3 { + namespace "module:3"; + prefix "mod3"; + revision "2014-01-03"; +} \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang new file mode 100644 index 0000000000..4963c89cc0 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang @@ -0,0 +1,11 @@ +module mount-point-1 { + namespace "mount:point:1"; + prefix "point1"; + revision "2016-01-01"; + + container cont { + } + + list listA { + } +} \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/mount-points/mount-point-1.yang b/restconf/sal-rest-connector/src/test/resources/modules/mount-points/mount-point-1.yang index 86abc813fa..4963c89cc0 100644 --- a/restconf/sal-rest-connector/src/test/resources/modules/mount-points/mount-point-1.yang +++ b/restconf/sal-rest-connector/src/test/resources/modules/mount-points/mount-point-1.yang @@ -5,4 +5,7 @@ module mount-point-1 { container cont { } + + list listA { + } } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang new file mode 100644 index 0000000000..de20febbb7 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang @@ -0,0 +1,418 @@ + module ietf-inet-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types"; + prefix "inet"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types for Internet addresses and related things. + + Copyright (c) 2010 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, is permitted pursuant to, and subject to the license + terms contained in, the Simplified BSD License set forth in Section + 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6021; see + the RFC itself for full legal notices."; + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of protocol field related types ***/ + + typedef ip-version { + type enumeration { + enum unknown { + value "0"; + description + "An unknown or unspecified version of the Internet protocol."; + } + enum ipv4 { + value "1"; + description + "The IPv4 protocol as defined in RFC 791."; + } + enum ipv6 { + value "2"; + description + "The IPv6 protocol as defined in RFC 2460."; + } + } + description + "This value represents the version of the IP protocol. + + In the value set and its semantics, this type is equivalent + to the InetVersion textual convention of the SMIv2."; + reference + "RFC 791: Internet Protocol + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + typedef dscp { + type uint8 { + range "0..63"; + } + description + "The dscp type represents a Differentiated Services Code-Point + that may be used for marking packets in a traffic stream. + + In the value set and its semantics, this type is equivalent + to the Dscp textual convention of the SMIv2."; + reference + "RFC 3289: Management Information Base for the Differentiated + Services Architecture + RFC 2474: Definition of the Differentiated Services Field + (DS Field) in the IPv4 and IPv6 Headers + RFC 2780: IANA Allocation Guidelines For Values In + the Internet Protocol and Related Headers"; + } + + typedef ipv6-flow-label { + type uint32 { + range "0..1048575"; + } + description + "The flow-label type represents flow identifier or Flow Label + in an IPv6 packet header that may be used to discriminate + traffic flows. + + In the value set and its semantics, this type is equivalent + to the IPv6FlowLabel textual convention of the SMIv2."; + reference + "RFC 3595: Textual Conventions for IPv6 Flow Label + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification"; + } + + typedef port-number { + type uint16 { + range "0..65535"; + } + description + "The port-number type represents a 16-bit port number of an + Internet transport layer protocol such as UDP, TCP, DCCP, or + SCTP. Port numbers are assigned by IANA. A current list of + all assignments is available from . + + Note that the port number value zero is reserved by IANA. In + situations where the value zero does not make sense, it can + be excluded by subtyping the port-number type. + + In the value set and its semantics, this type is equivalent + to the InetPortNumber textual convention of the SMIv2."; + reference + "RFC 768: User Datagram Protocol + RFC 793: Transmission Control Protocol + RFC 4960: Stream Control Transmission Protocol + RFC 4340: Datagram Congestion Control Protocol (DCCP) + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of autonomous system related types ***/ + + typedef as-number { + type uint32; + description + "The as-number type represents autonomous system numbers + which identify an Autonomous System (AS). An AS is a set + of routers under a single technical administration, using + an interior gateway protocol and common metrics to route + packets within the AS, and using an exterior gateway + protocol to route packets to other ASs'. IANA maintains + the AS number space and has delegated large parts to the + regional registries. + + Autonomous system numbers were originally limited to 16 + bits. BGP extensions have enlarged the autonomous system + number space to 32 bits. This type therefore uses an uint32 + base type without a range restriction in order to support + a larger autonomous system number space. + + In the value set and its semantics, this type is equivalent + to the InetAutonomousSystemNumber textual convention of + the SMIv2."; + reference + "RFC 1930: Guidelines for creation, selection, and registration + of an Autonomous System (AS) + RFC 4271: A Border Gateway Protocol 4 (BGP-4) + RFC 4893: BGP Support for Four-octet AS Number Space + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of IP address and hostname related types ***/ + + typedef ip-address { + type union { + type inet:ipv4-address; + type inet:ipv6-address; + } + description + "The ip-address type represents an IP address and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-address { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '(%[\p{N}\p{L}]+)?'; + } + description + "The ipv4-address type represents an IPv4 address in + dotted-quad notation. The IPv4 address may include a zone + index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format for the zone index is the numerical + format"; + } + + typedef ipv6-address { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(%[\p{N}\p{L}]+)?'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(%.+)?'; + } + description + "The ipv6-address type represents an IPv6 address in full, + mixed, shortened, and shortened-mixed notation. The IPv6 + address may include a zone index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format of IPv6 addresses uses the compressed + format described in RFC 4291, Section 2.2, item 2 with the + following additional rules: the :: substitution must be + applied to the longest sequence of all-zero 16-bit chunks + in an IPv6 address. If there is a tie, the first sequence + of all-zero 16-bit chunks is replaced by ::. Single + all-zero 16-bit chunks are not compressed. The canonical + format uses lowercase characters and leading zeros are + not allowed. The canonical format for the zone index is + the numerical format as described in RFC 4007, Section + 11.2."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text Representation"; + } + + typedef ip-prefix { + type union { + type inet:ipv4-prefix; + type inet:ipv6-prefix; + } + description + "The ip-prefix type represents an IP prefix and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-prefix { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '/(([0-9])|([1-2][0-9])|(3[0-2]))'; + } + description + "The ipv4-prefix type represents an IPv4 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 32. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The canonical format of an IPv4 prefix has all bits of + the IPv4 address set to zero that are not part of the + IPv4 prefix."; + } + + typedef ipv6-prefix { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(/.+)'; + } + description + "The ipv6-prefix type represents an IPv6 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal 128. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The IPv6 address should have all bits that do not belong + to the prefix set to zero. + + The canonical format of an IPv6 prefix has all bits of + the IPv6 address set to zero that are not part of the + IPv6 prefix. Furthermore, IPv6 address is represented + in the compressed format described in RFC 4291, Section + 2.2, item 2 with the following additional rules: the :: + substitution must be applied to the longest sequence of + all-zero 16-bit chunks in an IPv6 address. If there is + a tie, the first sequence of all-zero 16-bit chunks is + replaced by ::. Single all-zero 16-bit chunks are not + compressed. The canonical format uses lowercase + characters and leading zeros are not allowed."; + reference + "RFC 4291: IP Version 6 Addressing Architecture"; + } + + /*** collection of domain name and URI types ***/ + + typedef domain-name { + type string { + pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' + + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' + + '|\.'; + length "1..253"; + } + description + "The domain-name type represents a DNS domain name. The + name SHOULD be fully qualified whenever possible. + + Internet domain names are only loosely specified. Section + 3.5 of RFC 1034 recommends a syntax (modified in Section + 2.1 of RFC 1123). The pattern above is intended to allow + for current practice in domain name use, and some possible + future expansion. It is designed to hold various types of + domain names, including names used for A or AAAA records + (host names) and other records, such as SRV records. Note + that Internet host names have a stricter syntax (described + in RFC 952) than the DNS recommendations in RFCs 1034 and + 1123, and that systems that want to store host names in + schema nodes using the domain-name type are recommended to + adhere to this stricter standard to ensure interoperability. + + The encoding of DNS names in the DNS protocol is limited + to 255 characters. Since the encoding consists of labels + prefixed by a length bytes and there is a trailing NULL + byte, only 253 characters can appear in the textual dotted + notation. + + The description clause of schema nodes using the domain-name + type MUST describe when and how these names are resolved to + IP addresses. Note that the resolution of a domain-name value + may require to query multiple DNS records (e.g., A for IPv4 + and AAAA for IPv6). The order of the resolution process and + which DNS record takes precedence can either be defined + explicitely or it may depend on the configuration of the + resolver. + + Domain-name values use the US-ASCII encoding. Their canonical + format uses lowercase US-ASCII characters. Internationalized + domain names MUST be encoded in punycode as described in RFC + 3492"; + reference + "RFC 952: DoD Internet Host Table Specification + RFC 1034: Domain Names - Concepts and Facilities + RFC 1123: Requirements for Internet Hosts -- Application + and Support + RFC 2782: A DNS RR for specifying the location of services + (DNS SRV) + RFC 3492: Punycode: A Bootstring encoding of Unicode for + Internationalized Domain Names in Applications + (IDNA) + RFC 5891: Internationalizing Domain Names in Applications + (IDNA): Protocol"; + } + + typedef host { + type union { + type inet:ip-address; + type inet:domain-name; + } + description + "The host type represents either an IP address or a DNS + domain name."; + } + + typedef uri { + type string; + description + "The uri type represents a Uniform Resource Identifier + (URI) as defined by STD 66. + + Objects using the uri type MUST be in US-ASCII encoding, + and MUST be normalized as described by RFC 3986 Sections + 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary + percent-encoding is removed, and all case-insensitive + characters are set to lowercase except for hexadecimal + digits, which are normalized to uppercase as described in + Section 6.2.2.1. + + The purpose of this normalization is to help provide + unique URIs. Note that this normalization is not + sufficient to provide uniqueness. Two URIs that are + textually distinct after this normalization may still be + equivalent. + + Objects using the uri type may restrict the schemes that + they permit. For example, 'data:' and 'urn:' schemes + might not be appropriate. + + A zero-length URI is not a valid URI. This can be used to + express 'URI absent' where required. + + In the value set and its semantics, this type is equivalent + to the Uri SMIv2 textual convention defined in RFC 5017."; + reference + "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3305: Report from the Joint W3C/IETF URI Planning Interest + Group: Uniform Resource Identifiers (URIs), URLs, + and Uniform Resource Names (URNs): Clarifications + and Recommendations + RFC 5017: MIB Textual Conventions for Uniform Resource + Identifiers (URIs)"; + } + + } diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang new file mode 100644 index 0000000000..c3f952cf25 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang @@ -0,0 +1,417 @@ + module ietf-yang-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types"; + prefix "yang"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types. + + Copyright (c) 2010 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, is permitted pursuant to, and subject to the license + terms contained in, the Simplified BSD License set forth in Section + 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6021; see + the RFC itself for full legal notices."; + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of counter and gauge types ***/ + + typedef counter32 { + type uint32; + description + "The counter32 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter32 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter32 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter32. + + In the value set and its semantics, this type is equivalent + to the Counter32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef zero-based-counter32 { + type yang:counter32; + default "0"; + description + "The zero-based-counter32 type represents a counter32 + that has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter32 textual convention of the SMIv2."; + reference + "RFC 4502: Remote Network Monitoring Management Information + Base Version 2"; + } + + typedef counter64 { + type uint64; + description + "The counter64 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter64 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter64 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter64. + + In the value set and its semantics, this type is equivalent + to the Counter64 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef zero-based-counter64 { + type yang:counter64; + default "0"; + description + "The zero-based-counter64 type represents a counter64 that + has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter64 textual convention of the SMIv2."; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + typedef gauge32 { + type uint32; + description + "The gauge32 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^32-1 (4294967295 decimal), and + the minimum value cannot be smaller than 0. The value of + a gauge32 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge32 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the Gauge32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef gauge64 { + type uint64; + description + "The gauge64 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^64-1 (18446744073709551615), and + the minimum value cannot be smaller than 0. The value of + a gauge64 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge64 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the CounterBasedGauge64 SMIv2 textual convention defined + in RFC 2856"; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + /*** collection of identifier related types ***/ + + typedef object-identifier { + type string { + pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))' + + '(\.(0|([1-9]\d*)))*'; + } + description + "The object-identifier type represents administratively + assigned names in a registration-hierarchical-name tree. + + Values of this type are denoted as a sequence of numerical + non-negative sub-identifier values. Each sub-identifier + value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers + are separated by single dots and without any intermediate + whitespace. + + The ASN.1 standard restricts the value space of the first + sub-identifier to 0, 1, or 2. Furthermore, the value space + of the second sub-identifier is restricted to the range + 0 to 39 if the first sub-identifier is 0 or 1. Finally, + the ASN.1 standard requires that an object identifier + has always at least two sub-identifier. The pattern + captures these restrictions. + + Although the number of sub-identifiers is not limited, + module designers should realize that there may be + implementations that stick with the SMIv2 limit of 128 + sub-identifiers. + + This type is a superset of the SMIv2 OBJECT IDENTIFIER type + since it is not restricted to 128 sub-identifiers. Hence, + this type SHOULD NOT be used to represent the SMIv2 OBJECT + IDENTIFIER type, the object-identifier-128 type SHOULD be + used instead."; + reference + "ISO9834-1: Information technology -- Open Systems + Interconnection -- Procedures for the operation of OSI + Registration Authorities: General procedures and top + arcs of the ASN.1 Object Identifier tree"; + } + + + + + typedef object-identifier-128 { + type object-identifier { + pattern '\d*(\.\d*){1,127}'; + } + description + "This type represents object-identifiers restricted to 128 + sub-identifiers. + + In the value set and its semantics, this type is equivalent + to the OBJECT IDENTIFIER type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef yang-identifier { + type string { + length "1..max"; + pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*'; + pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*'; + } + description + "A YANG identifier string as defined by the 'identifier' + rule in Section 12 of RFC 6020. An identifier must + start with an alphabetic character or an underscore + followed by an arbitrary sequence of alphabetic or + numeric characters, underscores, hyphens, or dots. + + A YANG identifier MUST NOT start with any possible + combination of the lowercase or uppercase character + sequence 'xml'."; + reference + "RFC 6020: YANG - A Data Modeling Language for the Network + Configuration Protocol (NETCONF)"; + } + + /*** collection of date and time related types ***/ + + typedef date-and-time { + type string { + pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?' + + '(Z|[\+\-]\d{2}:\d{2})'; + } + description + "The date-and-time type is a profile of the ISO 8601 + standard for representation of dates and times using the + Gregorian calendar. The profile is defined by the + date-time production in Section 5.6 of RFC 3339. + + The date-and-time type is compatible with the dateTime XML + schema type with the following notable exceptions: + + (a) The date-and-time type does not allow negative years. + + (b) The date-and-time time-offset -00:00 indicates an unknown + time zone (see RFC 3339) while -00:00 and +00:00 and Z all + represent the same time zone in dateTime. + + (c) The canonical format (see below) of data-and-time values + differs from the canonical format used by the dateTime XML + schema type, which requires all times to be in UTC using the + time-offset 'Z'. + + This type is not equivalent to the DateAndTime textual + convention of the SMIv2 since RFC 3339 uses a different + separator between full-date and full-time and provides + higher resolution of time-secfrac. + + The canonical format for date-and-time values with a known time + zone uses a numeric time zone offset that is calculated using + the device's configured known offset to UTC time. A change of + the device's offset to UTC time will cause date-and-time values + to change accordingly. Such changes might happen periodically + in case a server follows automatically daylight saving time + (DST) time zone offset changes. The canonical format for + date-and-time values with an unknown time zone (usually referring + to the notion of local time) uses the time-offset -00:00."; + reference + "RFC 3339: Date and Time on the Internet: Timestamps + RFC 2579: Textual Conventions for SMIv2 + XSD-TYPES: XML Schema Part 2: Datatypes Second Edition"; + } + + typedef timeticks { + type uint32; + description + "The timeticks type represents a non-negative integer that + represents the time, modulo 2^32 (4294967296 decimal), in + hundredths of a second between two epochs. When a schema + node is defined that uses this type, the description of + the schema node identifies both of the reference epochs. + + In the value set and its semantics, this type is equivalent + to the TimeTicks type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef timestamp { + type yang:timeticks; + description + "The timestamp type represents the value of an associated + timeticks schema node at which a specific occurrence happened. + The specific occurrence must be defined in the description + of any schema node defined using this type. When the specific + occurrence occurred prior to the last time the associated + timeticks attribute was zero, then the timestamp value is + zero. Note that this requires all timestamp values to be + reset to zero when the value of the associated timeticks + attribute reaches 497+ days and wraps around to zero. + + The associated timeticks schema node must be specified + in the description of any schema node using this type. + + In the value set and its semantics, this type is equivalent + to the TimeStamp textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of generic address types ***/ + + typedef phys-address { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + description + "Represents media- or physical-level addresses represented + as a sequence octets, each octet represented by two hexadecimal + numbers. Octets are separated by colons. The canonical + representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the PhysAddress textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + typedef mac-address { + type string { + pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'; + } + description + "The mac-address type represents an IEEE 802 MAC address. + The canonical representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the MacAddress textual convention of the SMIv2."; + reference + "IEEE 802: IEEE Standard for Local and Metropolitan Area + Networks: Overview and Architecture + RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of XML specific types ***/ + + typedef xpath1.0 { + type string; + description + "This type represents an XPATH 1.0 expression. + + When a schema node is defined that uses this type, the + description of the schema node MUST specify the XPath + context in which the XPath expression is evaluated."; + reference + "XPATH: XML Path Language (XPath) Version 1.0"; + } + + } diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang new file mode 100644 index 0000000000..4963c89cc0 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang @@ -0,0 +1,11 @@ +module mount-point-1 { + namespace "mount:point:1"; + prefix "point1"; + revision "2016-01-01"; + + container cont { + } + + list listA { + } +} \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang new file mode 100644 index 0000000000..116cdc161a --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang @@ -0,0 +1,685 @@ +module restconf-module-with-illegal-container-modules { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + /** changed from container modules to list modules for testing purposes **/ + list modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + list module { + key "name revision"; + description + "Each entry represents one module currently + supported by the server."; + + leaf name { + type yang:yang-identifier; + description "The YANG module name."; + } + leaf revision { + type union { + type revision-identifier; + type string { length 0; } + } + description + "The YANG module revision date. An empty string is + used if no revision statement is present in the + YANG module."; + } + leaf namespace { + type inet:uri; + mandatory true; + description + "The XML namespace identifier for this module."; + } + leaf-list feature { + type yang:yang-identifier; + description + "List of YANG feature names from this module that are + supported by the server."; + } + leaf-list deviation { + type yang:yang-identifier; + description + "List of YANG deviation module names used by this + server to modify the conformance of the module + associated with this entry."; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang new file mode 100644 index 0000000000..2d8fbb1936 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang @@ -0,0 +1,684 @@ +module restconf-module-with-illegal-list-module { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + container modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + /** changed from list module to container module for testing purposes **/ + container module { + description + "Each entry represents one module currently + supported by the server."; + + leaf name { + type yang:yang-identifier; + description "The YANG module name."; + } + leaf revision { + type union { + type revision-identifier; + type string { length 0; } + } + description + "The YANG module revision date. An empty string is + used if no revision statement is present in the + YANG module."; + } + leaf namespace { + type inet:uri; + mandatory true; + description + "The XML namespace identifier for this module."; + } + leaf-list feature { + type yang:yang-identifier; + description + "List of YANG feature names from this module that are + supported by the server."; + } + leaf-list deviation { + type yang:yang-identifier; + description + "List of YANG deviation module names used by this + server to modify the conformance of the module + associated with this entry."; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang new file mode 100644 index 0000000000..907533d2b2 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang @@ -0,0 +1,639 @@ +module restconf-module-with-missing-container-modules { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + // removed container modules for testing purposes + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang new file mode 100644 index 0000000000..6d2b4da499 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang @@ -0,0 +1,650 @@ +module restconf-module-with-missing-list-module { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + container modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + // removed list module for testing purposes + added list test-list + list test-list { + leaf test-leaf { + type string; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-illegal-container-modules.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-illegal-container-modules.yang new file mode 100644 index 0000000000..c21656f322 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-illegal-container-modules.yang @@ -0,0 +1,685 @@ +module restconf-module-with-illegal-container-modules { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-rmwicm"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + /** changed from container modules to list modules for testing purposes **/ + list modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + list module { + key "name revision"; + description + "Each entry represents one module currently + supported by the server."; + + leaf name { + type yang:yang-identifier; + description "The YANG module name."; + } + leaf revision { + type union { + type revision-identifier; + type string { length 0; } + } + description + "The YANG module revision date. An empty string is + used if no revision statement is present in the + YANG module."; + } + leaf namespace { + type inet:uri; + mandatory true; + description + "The XML namespace identifier for this module."; + } + leaf-list feature { + type yang:yang-identifier; + description + "List of YANG feature names from this module that are + supported by the server."; + } + leaf-list deviation { + type yang:yang-identifier; + description + "List of YANG deviation module names used by this + server to modify the conformance of the module + associated with this entry."; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file -- 2.36.6