Bug 5526 - Testing - RestconfModulesService 01/38501/33
authorJakub Toth <jatoth@cisco.com>
Fri, 6 May 2016 09:42:27 +0000 (11:42 +0200)
committerIvan Hrasko <ihrasko@cisco.com>
Thu, 30 Jun 2016 06:38:00 +0000 (08:38 +0200)
Unit tests for RestconfModulesServiceImpl + repackaging of tests

Change-Id: I0cb9c7b753d5c4c54d4d4d393d86787294a0903e
Signed-off-by: Jakub Toth <jatoth@cisco.com>
21 files changed:
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/RestConnectorProviderTest.java [moved from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/RestConnectorProviderTest.java with 98% similarity]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/handlers/SchemaContextHandlerTest.java [moved from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/schema/context/SchemaContextHandlerTest.java with 98% similarity]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/IdentifierCodecTest.java [moved from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/parser/builder/IdentifierCodecTest.java with 97% similarity]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTest.java [new file with mode: 0644]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfModulesServiceTestUtils.java [new file with mode: 0644]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfSchemaServiceTest.java [moved from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfSchemaServiceTest.java with 99% similarity]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/services/impl/RestconfStreamsServiceTest.java [moved from restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/rest/impl/services/RestconfStreamsServiceTest.java with 99% similarity]
restconf/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang
restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module1.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module2.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/module3.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/mount-points/mount-point-1.yang
restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang [new file with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang [new file with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-illegal-container-modules.yang [new file with mode: 0644]

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 623e2c8bd05e60cc74c61fef32befc99ed64659f..9b3b450b747cb3308a82d1e503e57c205f0ced75 100644 (file)
@@ -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;
@@ -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;
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 a10eafef5e6f2d0a0b8b089b2304620823db083c..8907e5fcc35c655b25110be57945c15506ef4ec0 100644 (file)
@@ -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 (file)
index 0000000..ff100db
--- /dev/null
@@ -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<TestModule> 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<TestModule> 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 <code>null</code>. Test is expected to
+     * fail with <code>NullPointerException</code>.
+     */
+    @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 <code>null</code>. Test is expected
+     * to fail with <code>NullPointerException</code>.
+     */
+    @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 <code>null</code> value of
+     * identifier for mount point. Test is expected to fail with <code>NullPointerException</code>.
+     */
+    @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
+     * <code>RestconfDocumentedException</code> 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 <code>IllegalStateException</code>.
+     */
+    @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
+     * <code>RestconfDocumentedException</code> 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 <code>IllegalStateException</code>.
+     */
+    @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 <code>null</code> identifier. Test is
+     * expected to fail with <code>NullPointerException</code>.
+     */
+    @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 <code>SchemaContext</code>. 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 <code>SchemaContext</code>. 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 <code>NullPointerException</code>.
+     */
+    @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 <code>NullPointerException</code>.
+     */
+    @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
+     * <code>RestconfDocumentedException</code> 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 <code>IllegalStateException</code>.
+     */
+    @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
+     * <code>RestconfDocumentedException</code> 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 <code>IllegalStateException</code>.
+     */
+    @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 <code>DOMMountPointServiceHandler</code>
+     * contains <code>null</code> reference to  <code>DOMMountPointService</code>. Test is expected to fail with
+     * <code>NullPointerException</code>.
+     */
+    @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 <code>DOMMountPointServiceHandler</code>
+     * contains <code>null</code> reference to  <code>DOMMountPointService</code>. Test is expected to fail with
+     * <code>NullPointerException</code>.
+     */
+    @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 <code>DOMMountPointService</code>). Test is expected to fail with
+     * <code>IllegalStateException</code>.
+     */
+    @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 <code>DOMMountPointService</code>). Test is expected to fail with
+     * <code>IllegalStateException</code>.
+     */
+    @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 (file)
index 0000000..3431090
--- /dev/null
@@ -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<String> 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 <code>Set</code> of expected modules
+     * @throws Exception
+     */
+    static final Set<Module> getExpectedModules() throws Exception {
+        return TestRestconfUtils.loadSchemaContext(MODULES_PATH).getModules();
+    }
+
+    /**
+     * Get all expected modules behind mount point
+     * @return <code>Set</code> of expected modules
+     * @throws Exception
+     */
+    static final Set<Module> 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<Module> expectedModules, final Set<TestModule> loadedModules) {
+        final Set<TestModule> 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<Object> 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 <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> containing correct Restconf
+     * module and testing modules supported by the server.
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @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 <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> containing correct Restconf
+     * module and testing modules behind mount point.
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @throws Exception
+     */
+    static final RestconfModulesServiceImpl setupNormalMountPoint() throws Exception {
+        final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+
+        final Collection<File> 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 <code>SchemaContext</code> to load custom (modified) Restconf module.
+     * @param restconfModuleName Path of custom Restconf module
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @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 <code>SchemaContext</code> to load custom (modified) Restconf module and prepare mount point.
+     * @param restconfModuleName
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @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 <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> without Restconf module.
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @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 <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> without Restconf module and
+     * mount point.
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @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 <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> with testing modules and mount
+     * points but <code>DOMMountPointServiceHandler</code> will contain <code>null</code> reference to
+     * <code>DOMMountPointService</code>.
+     * @return <code>RestconfModulesServiceImpl</code>
+     * @throws Exception
+     */
+    static final RestconfModulesServiceImpl setupNullMountPointService() throws Exception {
+        final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+
+        final Collection<File> 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 <code>DOMMountPointService</code> with one registered <code>SimpleDOMMountPoint</code>.
+     * @return <code>DOMMountPointService</code>
+     * @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 <code>SchemaContext</code> containing Restconf module specified by
+     * <code>restconfName</code> its dependencies and one testing module.
+     * @param restconfName File name of custom Restconf module
+     * @return <code>SchemaContext</code> 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 <code>SchemaContext</code> containing Restconf module specified by
+     * <code>restconfName</code> its dependencies and one mount point.
+     * @param restconfName File name of custom Restconf module
+     * @return <code>SchemaContext</code> 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;
+        }
+    }
+}
@@ -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;
@@ -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;
index 07e50b3913683cf84b4944d53602d4d92cfb8a2d..c3f952cf256e4515f42aff2f4f6c057bad47fc15 100644 (file)
      reference
       "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
    }
-   
+
     typedef yang-identifier {
        type string {
          length "1..max";
        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 (file)
index 0000000..ab9d967
--- /dev/null
@@ -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 (file)
index 0000000..fa792d7
--- /dev/null
@@ -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 (file)
index 0000000..39bb690
--- /dev/null
@@ -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 (file)
index 0000000..4963c89
--- /dev/null
@@ -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
index 86abc813fa625b454b3e4b75457739ebd2b5bd86..4963c89cc0ef8f847e3bb3c9eac5c834eef6293c 100644 (file)
@@ -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 (file)
index 0000000..de20feb
--- /dev/null
@@ -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:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   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 <http://www.iana.org/>.
+
+       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 (file)
index 0000000..c3f952c
--- /dev/null
@@ -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:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   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 (file)
index 0000000..4963c89
--- /dev/null
@@ -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 (file)
index 0000000..116cdc1
--- /dev/null
@@ -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
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     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, <streams> 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, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> 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, <replayLogCreationTime>
+                  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, <eventTime> 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 (file)
index 0000000..2d8fbb1
--- /dev/null
@@ -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
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     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, <streams> 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, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> 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, <replayLogCreationTime>
+                  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, <eventTime> 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 (file)
index 0000000..907533d
--- /dev/null
@@ -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
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     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, <streams> 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, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> 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, <replayLogCreationTime>
+                  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, <eventTime> 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 (file)
index 0000000..6d2b4da
--- /dev/null
@@ -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
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     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, <streams> 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, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> 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, <replayLogCreationTime>
+                  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, <eventTime> 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 (file)
index 0000000..c21656f
--- /dev/null
@@ -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
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     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, <streams> 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, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> 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, <replayLogCreationTime>
+                  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, <eventTime> 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