From 5eb49d18c3f1745fd92260050af5fff37484e2e6 Mon Sep 17 00:00:00 2001 From: Ivan Hrasko Date: Mon, 9 May 2016 15:48:38 +0200 Subject: [PATCH] Bug 5526 - Testing - Utils - Schema util Unit tests for RestconfSchemaUtil Change-Id: I375f9fe9c3845c63cee261ed37fbf3cd253e27e1 Signed-off-by: Ivan Hrasko --- .../context/RestconfSchemaUtilTest.java | 394 +++++++++++ ...f-module-with-empty-grouping-restconf.yang | 519 ++++++++++++++ ...module-with-missing-container-modules.yang | 639 +++++++++++++++++ ...module-with-missing-grouping-restconf.yang | 518 ++++++++++++++ ...tconf-module-with-missing-list-module.yang | 650 ++++++++++++++++++ ...tconf-module-with-missing-list-stream.yang | 7 +- 6 files changed, 2726 insertions(+), 1 deletion(-) create mode 100644 restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/utils/schema/context/RestconfSchemaUtilTest.java create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-empty-grouping-restconf.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-container-modules.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-grouping-restconf.yang create mode 100644 restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-module.yang diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/utils/schema/context/RestconfSchemaUtilTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/utils/schema/context/RestconfSchemaUtilTest.java new file mode 100644 index 0000000000..7fd781ad01 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/utils/schema/context/RestconfSchemaUtilTest.java @@ -0,0 +1,394 @@ +/* + * 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.utils.schema.context; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.opendaylight.restconf.Draft11.MonitoringModule; +import static org.opendaylight.restconf.Draft11.RestconfModule; + +import com.google.common.collect.Sets; +import java.util.NoSuchElementException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils; +import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.netconf.sal.restconf.impl.RestconfError; +import org.opendaylight.restconf.Draft11; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; + +/** + * Unit tests for {@link RestconfSchemaUtil} + */ +public class RestconfSchemaUtilTest { + // schema with testing modules + private SchemaContext schemaContext; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setup() throws Exception { + schemaContext = TestRestconfUtils.loadSchemaContext("/modules/restconf-module-testing"); + } + + /** + * Positive test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} when this node can be found. + */ + @Test + public void getRestconfSchemaNodeListModuleTest() { + final DataSchemaNode dataSchemaNode = RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("ietf-restconf"), + RestconfModule.MODULE_LIST_SCHEMA_NODE); + + assertNotNull("Existing schema node "+ RestconfModule.MODULE_LIST_SCHEMA_NODE + " should be found", + dataSchemaNode); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getLocalName(), RestconfModule.MODULE_LIST_SCHEMA_NODE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getNamespace().toString(), RestconfModule.NAMESPACE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getFormattedRevision(), RestconfModule.REVISION); + } + + /** + * Positive test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link MonitoringModule#STREAM_LIST_SCHEMA_NODE} when this node can be found. + */ + @Test + public void getRestconfSchemaNodeListStreamTest() { + final DataSchemaNode dataSchemaNode = RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("ietf-restconf"), + MonitoringModule.STREAM_LIST_SCHEMA_NODE); + + assertNotNull("Existing schema node " + MonitoringModule.STREAM_LIST_SCHEMA_NODE + " should be found", + dataSchemaNode); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getLocalName(), MonitoringModule.STREAM_LIST_SCHEMA_NODE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getNamespace().toString(), RestconfModule.NAMESPACE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getFormattedRevision(), RestconfModule.REVISION); + } + + /** + * Positive test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} when this node can be found. + */ + @Test + public void getRestconfSchemaNodeContainerModulesTest() { + final DataSchemaNode dataSchemaNode = RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("ietf-restconf"), + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + + assertNotNull("Existing schema node " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE + "should be found", + dataSchemaNode); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getLocalName(), RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getNamespace().toString(), RestconfModule.NAMESPACE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getFormattedRevision(), RestconfModule.REVISION); + } + + /** + * Positive test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link MonitoringModule#STREAMS_CONTAINER_SCHEMA_NODE} when this node can be found. + */ + @Test + public void getRestconfSchemaNodeContainerStreamsTest() { + final DataSchemaNode dataSchemaNode = RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("ietf-restconf"), + MonitoringModule.STREAMS_CONTAINER_SCHEMA_NODE); + + assertNotNull("Existing schema node " + MonitoringModule.STREAMS_CONTAINER_SCHEMA_NODE + " should be found", + dataSchemaNode); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getLocalName(), MonitoringModule.STREAMS_CONTAINER_SCHEMA_NODE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getNamespace().toString(), RestconfModule.NAMESPACE); + assertEquals("Incorrect schema node was returned", + dataSchemaNode.getQName().getFormattedRevision(), RestconfModule.REVISION); + } + + /** + * Negative test for getting DataSchemaNode from Restconf module when Restconf module is + * null. Test is expected to fail catching NullPointerException. + */ + @Test + public void getRestconfSchemaNodeNullRestconfModuleNegativeTest() { + thrown.expect(NullPointerException.class); + RestconfSchemaUtil.getRestconfSchemaNode(null, RestconfModule.RESTCONF_CONTAINER_SCHEMA_NODE); + } + + /** + * Negative test for getting DataSchemaNode from Restconf module when name of the schema node name is + * null. Test is expected to fail with NullPointerException. + */ + @Test + public void getRestconfSchemaNodeNullSchemaNodeNameNegativeTest() { + thrown.expect(NullPointerException.class); + RestconfSchemaUtil.getRestconfSchemaNode(getTestingRestconfModule("ietf-restconf"), null); + } + + /** + * Negative test for getting DataSchemaNode from Restconf module when name of the schema node name + * references to not existing node. Test is expected to fail catching code>RestconfDocumentedException and + * checking expected error type, error tag and error status code. + */ + @Test + public void getRestconfSchemaNodeNotExistingSchemaNodeNameNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode(getTestingRestconfModule("ietf-restconf"), "not-existing-node"); + fail("Test should fail due to not-existing node name"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} when this node cannot be found. + * RestconfDocumentedException is expected and error type, error tag and error status code are + * compared to expected values. + */ + @Test + public void getRestconfSchemaNodeContainerModulesNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode(getTestingRestconfModule( + "restconf-module-with-missing-container-modules"), RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + fail("Test should fail due to missing " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE + " node"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} when this node cannot be found. + * RestconfDocumentedException is expected and error type, error tag and error status code are + * compared to expected values. + */ + @Test + public void getRestconfSchemaNodeListModuleNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("restconf-module-with-missing-list-module"), + RestconfModule.MODULE_LIST_SCHEMA_NODE); + fail("Test should fail due to missing " + RestconfModule.MODULE_LIST_SCHEMA_NODE + " node"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link MonitoringModule#STREAMS_CONTAINER_SCHEMA_NODE} when this node cannot + * be found. RestconfDocumentedException is expected and error type, error tag and error status code + * are compared to expected values. + */ + @Test + public void getRestconfSchemaNodeContainerStreamsNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("restconf-module-with-missing-container-streams"), + MonitoringModule.STREAMS_CONTAINER_SCHEMA_NODE); + fail("Test should fail due to missing " + MonitoringModule.STREAMS_CONTAINER_SCHEMA_NODE + " node"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module for schema node name equals to + * {@link MonitoringModule#STREAM_LIST_SCHEMA_NODE} when this node cannot be found. + * RestconfDocumentedException is expected and error type, error tag and error status code + * are compared to expected values. + */ + @Test + public void getRestconfSchemaNodeListStreamNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("restconf-module-with-missing-list-stream"), + MonitoringModule.STREAM_LIST_SCHEMA_NODE); + fail("Test should fail due to missing " + MonitoringModule.STREAM_LIST_SCHEMA_NODE + " node"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module when Restconf module does not + * contains restconf grouping. Test is expected to fail with RestconfDocumentedException and error + * type, error tag and error status code are compared to expected values. + */ + @Test + public void getRestconfSchemaNodeMissingRestconfGroupingNegativeTest() { + try { + RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("restconf-module-with-missing-grouping-restconf"), + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + fail("Test should fail due to missing restconf grouping in Restconf module"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test for getting DataSchemaNode from Restconf module when Restconf module contains + * restconf grouping which does not contain any child nodes. Test is expected to fail with + * NoSuchElementException. + */ + @Test + public void getRestconfSchemaNodeEmptyRestconfGroupingNegativeTest() { + thrown.expect(NoSuchElementException.class); + RestconfSchemaUtil.getRestconfSchemaNode( + getTestingRestconfModule("restconf-module-with-empty-grouping-restconf"), + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + } + + /** + * Positive test trying to find DataSchemaNode of {@link RestconfModule#RESTCONF_GROUPING_SCHEMA_NODE} + * in Restconf module groupings collection. + */ + @Test + public void findSchemaNodeInCollectionTest() { + final SchemaNode schemaNode = RestconfSchemaUtil.findSchemaNodeInCollection( + getTestingRestconfModule("ietf-restconf").getGroupings(), + RestconfModule.RESTCONF_GROUPING_SCHEMA_NODE); + + assertNotNull("Restconf grouping schema node should be found", schemaNode); + assertEquals("Incorrect grouping was returned", + schemaNode.getQName().getLocalName(), RestconfModule.RESTCONF_GROUPING_SCHEMA_NODE); + assertEquals("Incorrect grouping was returned", + schemaNode.getQName().getNamespace().toString(), RestconfModule.NAMESPACE); + assertEquals("Incorrect grouping was returned", + schemaNode.getQName().getFormattedRevision(), RestconfModule.REVISION); + } + + /** + * Negative test trying to find DataSchemaNode of not existing groupings schema node name in Restconf + * module grouping collection. Test is expected to fail catching RestconfDocumentedException and + * checking for correct error type, error tag and error status code. + */ + @Test + public void findSchemaNodeInCollectionNegativeTest() { + try { + RestconfSchemaUtil.findSchemaNodeInCollection( + getTestingRestconfModule("ietf-restconf").getGroupings(), "not-existing-grouping"); + fail("Test should fail due to missing not-existing grouping in Restconf grouping collection"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test trying to find DataSchemaNode of existing schema node name in null + * collection. Test is expected to fail with NullPointerException. + */ + @Test + public void findSchemaNodeInCollectionNullCollectionNegativeTest() { + thrown.expect(NullPointerException.class); + RestconfSchemaUtil.findSchemaNodeInCollection(null, RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + } + + /** + * Negative test trying to find DataSchemaNode for schema node name in empty collection. Test is + * expected to fail with RestconfDocumentedException. Error type, error tag and error status code + * are compared to expected values. + */ + @Test + public void findSchemaNodeInCollectionEmptyCollectionNegativeTest() { + try { + RestconfSchemaUtil.findSchemaNodeInCollection( + Sets.newHashSet(), RestconfModule.MODULES_CONTAINER_SCHEMA_NODE); + fail("Test should fail due to empty schema nodes collection"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * Negative test trying to find DataSchemaNode of null schema node name in Restconf module + * groupings collection. Test is expected to fail with RestconfDocumentedException. Error type, error + * tag and error status code are compared to expected values. + */ + @Test + public void findSchemaNodeInCollectionNullSchemaNodeName() { + try { + RestconfSchemaUtil.findSchemaNodeInCollection( + getTestingRestconfModule("ietf-restconf").getGroupings(), null); + fail("Test should fail due to null schema node name"); + } catch (final RestconfDocumentedException e) { + assertEquals("Error type is not correct", + RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType()); + assertEquals("Error tag is not correct", + RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag()); + assertEquals("Error status code is not correct", + 404, e.getErrors().get(0).getErrorTag().getStatusCode()); + } + } + + /** + * There are multiple testing Restconf modules for different test cases. It is possible to distinguish them by + * name or by namespace. This method is looking for Restconf test module by its name. + * @param s Testing Restconf module name + * @return Restconf module + */ + private Module getTestingRestconfModule(final String s) { + return schemaContext.findModuleByName(s, Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()); + } +} diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-empty-grouping-restconf.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-empty-grouping-restconf.yang new file mode 100644 index 0000000000..6e8377d9e0 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-empty-grouping-restconf.yang @@ -0,0 +1,519 @@ +module restconf-module-with-empty-grouping-restconf { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-rmwegr"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + /** This grouping is empty for testing purposes **/ + grouping restconf {} + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-container-modules.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-container-modules.yang new file mode 100644 index 0000000000..c117ffbcc5 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-container-modules.yang @@ -0,0 +1,639 @@ +module restconf-module-with-missing-container-modules { + namespace "urn:ietf:params:xml:ns:yang:ietf-restcon-rmwmcmf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + // removed container modules for testing purposes + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-grouping-restconf.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-grouping-restconf.yang new file mode 100644 index 0000000000..0e8009aa85 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-grouping-restconf.yang @@ -0,0 +1,518 @@ +module restconf-module-with-missing-grouping-restconf { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-rmwmgr"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + /** grouping restconf removed for testing purposes **/ + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-module.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-module.yang new file mode 100644 index 0000000000..34b4d48453 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-module.yang @@ -0,0 +1,650 @@ +module restconf-module-with-missing-list-module { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-rmwmlm"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + container modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + // removed list module for testing purposes + added list test-list + list test-list { + leaf test-leaf { + type string; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-stream.yang b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-stream.yang index fcc7e308a1..ba8c9aa1d7 100644 --- a/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-stream.yang +++ b/restconf/sal-rest-connector/src/test/resources/modules/restconf-module-testing/restconf-module-with-missing-list-stream.yang @@ -586,7 +586,12 @@ module restconf-module-with-missing-list-stream { reference "RFC 5277, Section 3.4, element."; - /** deleted list stream for testing purposes **/ + /** deleted list stream for testing purposes + added list test-list **/ + list test-list { + leaf test-leaf { + type string; + } + } } leaf version { -- 2.36.6