Merge "Fix upload size to be greater than 1MB"
authorBruno Sakoto <bruno.sakoto@bell.ca>
Wed, 7 Apr 2021 13:37:12 +0000 (13:37 +0000)
committerGerrit Code Review <gerrit@onap.org>
Wed, 7 Apr 2021 13:37:12 +0000 (13:37 +0000)
22 files changed:
cps-application/src/main/java/org/onap/cps/config/WebSecurityConfig.java
cps-rest/docs/api/swagger/cpsAdmin.yml
cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java
cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/query/CpsPathQuery.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
cps-ri/src/test/resources/data/anchor.sql
cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
cps-service/src/test/groovy/org/onap/cps/model/DataNodeBuilderSpec.groovy
cps-service/src/test/resources/ietf/data/ietf-network-topology-sample-rfc8345.json [new file with mode: 0644]
cps-service/src/test/resources/ietf/ietf-inet-types@2013-07-15.yang [moved from cps-service/src/test/resources/e2e/basic/ietf-inet-types.yang with 99% similarity, mode: 0644]
cps-service/src/test/resources/ietf/ietf-network-state@2018-02-26.yang [new file with mode: 0644]
cps-service/src/test/resources/ietf/ietf-network-topology-state@2018-02-26.yang [new file with mode: 0644]
cps-service/src/test/resources/ietf/ietf-network-topology@2018-02-26.yang [new file with mode: 0644]
cps-service/src/test/resources/ietf/ietf-network@2018-02-26.yang [new file with mode: 0644]
cps-service/src/test/resources/ietf/ietf-yang-types@2013-07-15.yang [moved from cps-service/src/test/resources/e2e/basic/ietf-yang-types.yang with 99% similarity, mode: 0644]

index fbf1be9..93a3a6e 100644 (file)
@@ -55,7 +55,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         @Autowired @Value("${security.auth.password}") final String password
     ) {
         super();
-        this.permitUris = permitUris.isEmpty() ? new String[] {"/v3/api-docs"} : permitUris.split("\\s*,\\s*");
+        this.permitUris = permitUris.isEmpty() ? new String[] {"/v3/api-docs"} : permitUris.split("\\s{0,9},\\s{0,9}");
         this.username = username;
         this.password = password;
     }
index 5040e2c..cf26299 100755 (executable)
@@ -173,7 +173,7 @@ anchorByDataspaceAndAnchorName:
         $ref: 'components.yml#/components/responses/NotFound'
 
   delete:
-    description: Delete an anchor given an anchor name and a dataspace - DRAFT
+    description: Delete an anchor given an anchor name and a dataspace
     tags:
       - cps-admin
     summary: Delete an anchor
@@ -182,8 +182,6 @@ anchorByDataspaceAndAnchorName:
       - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
       - $ref: 'components.yml#/components/parameters/anchorNameInPath'
     responses:
-      '200':
-        $ref: 'components.yml#/components/responses/Ok'
       '204':
         $ref: 'components.yml#/components/responses/NoContent'
       '400':
index d74e9b1..ead365a 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -56,6 +57,11 @@ public class AdminRestController implements CpsAdminApi {
         return new ResponseEntity<>(dataspaceName, HttpStatus.CREATED);
     }
 
+    @Override
+    public ResponseEntity<Object> deleteDataspace(final String dataspaceName) {
+        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
     @Override
     public ResponseEntity<String> createSchemaSet(final MultipartFile multipartFile,
         final String schemaSetName, final String dataspaceName) {
@@ -91,13 +97,9 @@ public class AdminRestController implements CpsAdminApi {
     }
 
     @Override
-    public ResponseEntity<Object> deleteAnchor(final String dataspaceName, final String anchorName) {
-        return null;
-    }
-
-    @Override
-    public ResponseEntity<Object> deleteDataspace(final String dataspaceName) {
-        return null;
+    public ResponseEntity<Void> deleteAnchor(final String dataspaceName, final String anchorName) {
+        cpsAdminService.deleteAnchor(dataspaceName, anchorName);
+        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
     }
 
     @Override
index ab4cf7c..1ccd3ba 100755 (executable)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020 Pantheon.tech
+ *  Copyright (C) 2020-2021 Pantheon.tech
  *  Modifications Copyright (C) 2020, 2021 Bell Canada. All rights reserved.
  *  Copyright (C) 2021 Nordix Foundation
  *  ================================================================================
@@ -308,6 +308,18 @@ class AdminRestControllerSpec extends Specification {
             responseContent.contains(schemaSetName)
     }
 
+    def 'Delete anchor.'() {
+        given: 'an endpoint'
+            def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName"
+        when: 'delete method is invoked on anchor endpoint'
+            def response = mvc.perform(delete(anchorEndpoint)).andReturn().response
+        then: 'associated service method is invoked with expected parameters'
+            1 * mockCpsAdminService.deleteAnchor(dataspaceName, anchorName)
+        and: 'response code indicates success'
+            response.status == HttpStatus.NO_CONTENT.value()
+    }
+
+
     def createMultipartFile(filename, content) {
         return new MockMultipartFile("file", filename, "text/plain", content.getBytes())
     }
index 1b8f196..edc56e4 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation. All rights reserved.
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.cps.spi.impl;
 
+import com.google.common.collect.ImmutableSet;
 import java.util.Collection;
 import java.util.stream.Collectors;
+import javax.transaction.Transactional;
 import org.onap.cps.spi.CpsAdminPersistenceService;
 import org.onap.cps.spi.entities.AnchorEntity;
 import org.onap.cps.spi.entities.DataspaceEntity;
@@ -31,6 +34,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.model.Anchor;
 import org.onap.cps.spi.repository.AnchorRepository;
 import org.onap.cps.spi.repository.DataspaceRepository;
+import org.onap.cps.spi.repository.FragmentRepository;
 import org.onap.cps.spi.repository.SchemaSetRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataIntegrityViolationException;
@@ -48,6 +52,9 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
     @Autowired
     private SchemaSetRepository schemaSetRepository;
 
+    @Autowired
+    private FragmentRepository fragmentRepository;
+
     @Override
     public void createDataspace(final String dataspaceName) {
         try {
@@ -83,10 +90,20 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
 
     @Override
     public Anchor getAnchor(final String dataspaceName, final String anchorName) {
+        return toAnchor(getAnchorEntity(dataspaceName, anchorName));
+    }
+
+    @Transactional
+    @Override
+    public void deleteAnchor(final String dataspaceName, final String anchorName) {
+        final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+        fragmentRepository.deleteByAnchorIn(ImmutableSet.of(anchorEntity));
+        anchorRepository.delete(anchorEntity);
+    }
+
+    private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
-        final AnchorEntity anchorEntity =
-            anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
-        return toAnchor(anchorEntity);
+        return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
     }
 
     private static Anchor toAnchor(final AnchorEntity anchorEntity) {
index 7b9bfba..97a304d 100644 (file)
@@ -39,7 +39,8 @@ public class CpsPathQuery {
 
     private static final String NON_CAPTURING_GROUP_1_TO_99_YANG_CONTAINERS = "((?:\\/[^\\/]+){1,99})";
 
-    private static final String YANG_LEAF_VALUE_EQUALS_CONDITION = "\\[\\s*@(\\S+?)\\s*=\\s*(.*?)\\s*\\]";
+    private static final String YANG_LEAF_VALUE_EQUALS_CONDITION =
+        "\\[\\s{0,9}@(\\S+?)\\s{0,9}=\\s{0,9}(.*?)\\s{0,9}\\]";
 
     private static final Pattern QUERY_CPS_PATH_WITH_SINGLE_LEAF_PATTERN =
         Pattern.compile(NON_CAPTURING_GROUP_1_TO_99_YANG_CONTAINERS + YANG_LEAF_VALUE_EQUALS_CONDITION);
index 7ab099d..0d75d3f 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Nordix Foundation
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,6 +37,8 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
 
     static final String SET_DATA = '/data/anchor.sql'
     static final String EMPTY_DATASPACE_NAME = 'DATASPACE-002'
+    static final Integer DELETED_ANCHOR_ID = 3001
+    static final Long DELETED_FRAGMENT_ID = 4001
 
     @Sql(CLEAR_DATA)
     def 'Create and retrieve a new dataspace.'() {
@@ -77,10 +80,10 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
         then: 'an #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                    | dataspaceName  | schemaSetName     | anchorName     || expectedException
-            'dataspace does not exist'  | 'unknown'      | 'not-relevant'    | 'not-relevant' || DataspaceNotFoundException
-            'schema set does not exist' | DATASPACE_NAME | 'unknown'         | 'not-relevant' || SchemaSetNotFoundException
-            'anchor already exists'     | DATASPACE_NAME |  SCHEMA_SET_NAME1 | ANCHOR_NAME1   || AlreadyDefinedException
+            scenario                    | dataspaceName  | schemaSetName    | anchorName     || expectedException
+            'dataspace does not exist'  | 'unknown'      | 'not-relevant'   | 'not-relevant' || DataspaceNotFoundException
+            'schema set does not exist' | DATASPACE_NAME | 'unknown'        | 'not-relevant' || SchemaSetNotFoundException
+            'anchor already exists'     | DATASPACE_NAME | SCHEMA_SET_NAME1 | ANCHOR_NAME1   || AlreadyDefinedException
     }
 
     @Unroll
@@ -91,9 +94,9 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
         then: 'an #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                    | dataspaceName  | anchorName     || expectedException
-            'dataspace does not exist'  | 'unknown'      | 'not-relevant' || DataspaceNotFoundException
-            'anchor does not exists'    | DATASPACE_NAME | 'unknown'      || AnchorNotFoundException
+            scenario                   | dataspaceName  | anchorName     || expectedException
+            'dataspace does not exist' | 'unknown'      | 'not-relevant' || DataspaceNotFoundException
+            'anchor does not exists'   | DATASPACE_NAME | 'unknown'      || AnchorNotFoundException
     }
 
     @Unroll
@@ -118,4 +121,26 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
         then: 'an DataspaceNotFoundException is thrown'
             thrown(DataspaceNotFoundException)
     }
+
+    @Sql([CLEAR_DATA, SET_DATA])
+    def 'Delete anchor'() {
+        when: 'delete anchor action is invoked'
+            objectUnderTest.deleteAnchor(DATASPACE_NAME, ANCHOR_NAME1)
+        then: 'anchor and associated data fragment are deleted'
+            assert anchorRepository.findById(DELETED_ANCHOR_ID).isEmpty()
+            assert fragmentRepository.findById(DELETED_FRAGMENT_ID).isEmpty()
+    }
+
+    @Unroll
+    @Sql([CLEAR_DATA, SET_DATA])
+    def 'delete anchor error scenario: #scenario'(){
+        when: 'delete anchor attempt is performed'
+            objectUnderTest.deleteAnchor(dataspaceName, anchorName)
+        then: 'an #expectedException is thrown'
+            thrown(expectedException)
+        where: 'the following data is used'
+            scenario                   | dataspaceName  | anchorName     || expectedException
+            'dataspace does not exist' | 'unknown'      | 'not-relevant' || DataspaceNotFoundException
+            'anchor does not exists'   | DATASPACE_NAME | 'unknown'      || AnchorNotFoundException
+    }
 }
index 1d9b4b1..a7d3e67 100644 (file)
@@ -6,4 +6,7 @@ INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
 
 INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
     (3001, 'ANCHOR-001', 1001, 2001),
-    (3002, 'ANCHOR-002', 1001, 2002);
\ No newline at end of file
+    (3002, 'ANCHOR-002', 1001, 2002);
+
+INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
+    (4001, 1001, 3001, null, '/xpath', '{}');
\ No newline at end of file
index 0379ac2..1e4c9c7 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -62,9 +63,17 @@ public interface CpsAdminService {
      * Get an anchor in the given dataspace using the anchor name.
      *
      * @param dataspaceName dataspace name
-     * @param anchorName anchor name
+     * @param anchorName    anchor name
      * @return an anchor
      */
     @NonNull
     Anchor getAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+
+    /**
+     * Delete anchor by name in given dataspace.
+     *
+     * @param dataspaceName dataspace name
+     * @param anchorName    anchor name
+     */
+    void deleteAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
 }
index 09550f1..2518573 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -52,4 +53,9 @@ public class CpsAdminServiceImpl implements CpsAdminService {
     public Anchor getAnchor(final String dataspaceName, final String anchorName) {
         return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName);
     }
+
+    @Override
+    public void deleteAnchor(final String dataspaceName, final String anchorName) {
+        cpsAdminPersistenceService.deleteAnchor(dataspaceName, anchorName);
+    }
 }
\ No newline at end of file
index f47af5f..35e07f8 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation. All rights reserved.
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -67,4 +68,12 @@ public interface CpsAdminPersistenceService {
      */
     @NonNull
     Anchor getAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+
+    /**
+     * Delete anchor by name in given dataspace.
+     *
+     * @param dataspaceName dataspace name
+     * @param anchorName anchor name
+     */
+    void deleteAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
 }
\ No newline at end of file
index ea0626c..cf79ad7 100644 (file)
@@ -30,6 +30,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.utils.YangUtils;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
@@ -150,8 +151,10 @@ public class DataNodeBuilder {
     }
 
     private static void addYangContainer(final DataNode currentDataNode, final DataContainerNode<?> dataContainerNode) {
-        final DataNode dataContainerDataNode = createAndAddChildDataNode(currentDataNode,
-            YangUtils.buildXpath(dataContainerNode.getIdentifier()));
+        final DataNode dataContainerDataNode =
+            (dataContainerNode.getIdentifier() instanceof YangInstanceIdentifier.AugmentationIdentifier)
+                ? currentDataNode
+                : createAndAddChildDataNode(currentDataNode, YangUtils.buildXpath(dataContainerNode.getIdentifier()));
         final Collection<DataContainerChild<?, ?>> normalizedChildNodes = dataContainerNode.getValue();
         for (final NormalizedNode<?, ?> normalizedNode : normalizedChildNodes) {
             addDataNodeFromNormalizedNode(dataContainerDataNode, normalizedNode);
index 6631a20..b1fc4dc 100755 (executable)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation
  *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -61,4 +62,11 @@ class CpsAdminServiceImplSpec extends Specification {
         expect: 'the anchor provided by persistence service is returned as result'
             objectUnderTest.getAnchor('someDataspace','someAnchor') == anchor
     }
+
+    def 'Delete anchor.'() {
+        when: 'delete anchor is invoked'
+            objectUnderTest.deleteAnchor('someDataspace','someAnchor')
+        then: 'associated persistence service method is invoked with same parameters'
+             1 * mockCpsAdminPersistenceService.deleteAnchor('someDataspace','someAnchor')
+    }
 }
index a24bd0a..a09166d 100755 (executable)
@@ -52,7 +52,11 @@ class E2ENetworkSliceSpec extends Specification {
 \r
     def 'E2E model can be parsed by CPS.'() {\r
         given: 'Valid yang resource as name-to-content map'\r
-            def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('e2e/basic/ietf-inet-types.yang','e2e/basic/ietf-yang-types.yang','e2e/basic/ran-network2020-08-06.yang')\r
+            def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap(\r
+                    'ietf/ietf-inet-types@2013-07-15.yang',\r
+                    'ietf/ietf-yang-types@2013-07-15.yang',\r
+                    'e2e/basic/ran-network2020-08-06.yang'\r
+            )\r
         when: 'Create schema set method is invoked'\r
             cpsModuleServiceImpl.createSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap)\r
         then: 'Parameters are validated and processing is delegated to persistence service'\r
@@ -144,8 +148,8 @@ class E2ENetworkSliceSpec extends Specification {
     def 'E2E RAN Schema Model.'(){\r
         given: 'yang resources'\r
             def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap(\r
-                    'e2e/basic/ietf-inet-types.yang',\r
-                    'e2e/basic/ietf-yang-types.yang',\r
+                    'ietf/ietf-inet-types@2013-07-15.yang',\r
+                    'ietf/ietf-yang-types@2013-07-15.yang',\r
                     'e2e/basic/cps-ran-schema-model@2021-01-28.yang'\r
             )\r
         and : 'json data'\r
index dca648b..901e0b6 100644 (file)
@@ -35,6 +35,15 @@ class DataNodeBuilderSpec extends Specification {
             '/test-tree/branch[@name=\'Right\']/nest': [name: 'Big', birds: ['Owl', 'Raven', 'Crow']]
     ]
 
+    String[] networkTopologyModelRfc8345 = [
+            'ietf/ietf-yang-types@2013-07-15.yang',
+            'ietf/ietf-network-topology-state@2018-02-26.yang',
+            'ietf/ietf-network-topology@2018-02-26.yang',
+            'ietf/ietf-network-state@2018-02-26.yang',
+            'ietf/ietf-network@2018-02-26.yang',
+            'ietf/ietf-inet-types@2013-07-15.yang'
+    ]
+
     def 'Converting NormalizedNode (tree) to a DataNode (tree).'() {
         given: 'the schema context for expected model'
             def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang')
@@ -74,6 +83,55 @@ class DataNodeBuilderSpec extends Specification {
             mappedResult.keySet()
                     .containsAll(['/test-tree/branch[@name=\'Branch\']', '/test-tree/branch[@name=\'Branch\']/nest'])
     }
+    def 'Converting NormalizedNode (tree) to a DataNode (tree) -- augmentation case.'() {
+        given: 'a schema context for expected model'
+            def yangResourceNameToContent = TestUtils.getYangResourcesAsMap(networkTopologyModelRfc8345)
+            def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
+        and: 'the json data parsed into normalized node object'
+            def jsonData = TestUtils.getResourceFileContent('ietf/data/ietf-network-topology-sample-rfc8345.json')
+            def normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext)
+        when: 'the normalized node is converted to a data node '
+            def result = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode).build()
+            def mappedResult = TestUtils.getFlattenMapByXpath(result)
+        then: 'all expected data nodes are populated'
+            mappedResult.size() == 32
+            println(mappedResult.keySet().sort())
+        and: 'xpaths for augmentation nodes (link and termination-point nodes) were built correctly'
+            mappedResult.keySet().containsAll([
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D1,1-2-1,D2,2-1-1']",
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D1,1-3-1,D3,3-1-1']",
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D2,2-1-1,D1,1-2-1']",
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D2,2-3-1,D3,3-2-1']",
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D3,3-1-1,D1,1-3-1']",
+                    "/networks/network[@network-id='otn-hc']/link[@link-id='D3,3-2-1,D2,2-3-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D1']/termination-point[@tp-id='1-0-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D1']/termination-point[@tp-id='1-2-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D1']/termination-point[@tp-id='1-3-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D2']/termination-point[@tp-id='2-0-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D2']/termination-point[@tp-id='2-1-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D2']/termination-point[@tp-id='2-3-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D3']/termination-point[@tp-id='3-1-1']",
+                    "/networks/network[@network-id='otn-hc']/node[@node-id='D3']/termination-point[@tp-id='3-2-1']"
+            ])
+    }
+
+    def 'Converting NormalizedNode (tree) to a DataNode (tree) for known parent node -- augmentation case.'() {
+        given: 'a schema context for expected model'
+            def yangResourceNameToContent = TestUtils.getYangResourcesAsMap(networkTopologyModelRfc8345)
+            def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
+        and: 'parent node xpath referencing augmentation node within a model'
+            def parentNodeXpath = "/networks/network[@network-id='otn-hc']/link[@link-id='D1,1-2-1,D2,2-1-1']"
+        and: 'the json data fragment parsed into normalized node object for given parent node xpath'
+            def jsonData = '{"source": {"source-node": "D1", "source-tp": "1-2-1"}}'
+            def normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext, parentNodeXpath)
+        when: 'the normalized node is converted to a data node with given parent node xpath'
+            def result = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode)
+                    .withParentNodeXpath(parentNodeXpath).build()
+        then: 'the resulting data node represents a child of augmentation node'
+            assert result.xpath == "/networks/network[@network-id='otn-hc']/link[@link-id='D1,1-2-1,D2,2-1-1']/source"
+            assert result.leaves['source-node'] == 'D1'
+            assert result.leaves['source-tp'] == '1-2-1'
+    }
 
     def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) {
         expectedLeavesMap.each { key, value ->
@@ -88,5 +146,4 @@ class DataNodeBuilderSpec extends Specification {
             }
         }
     }
-
 }
diff --git a/cps-service/src/test/resources/ietf/data/ietf-network-topology-sample-rfc8345.json b/cps-service/src/test/resources/ietf/data/ietf-network-topology-sample-rfc8345.json
new file mode 100644 (file)
index 0000000..8f2ee02
--- /dev/null
@@ -0,0 +1,120 @@
+{
+     "ietf-network:networks": {
+       "network": [
+         {
+           "network-types": {
+           },
+           "network-id": "otn-hc",
+           "node": [
+             {
+               "node-id": "D1",
+               "termination-point": [
+                 {
+                   "tp-id": "1-0-1"
+                 },
+                 {
+                   "tp-id": "1-2-1"
+                 },
+                 {
+                   "tp-id": "1-3-1"
+                 }
+               ]
+             },
+             {
+               "node-id": "D2",
+               "termination-point": [
+                 {
+                   "tp-id": "2-0-1"
+                 },
+                 {
+                   "tp-id": "2-1-1"
+                 },
+                 {
+                   "tp-id": "2-3-1"
+                 }
+               ]
+             },
+             {
+               "node-id": "D3",
+               "termination-point": [
+                 {
+                   "tp-id": "3-1-1"
+                 },
+                 {
+                   "tp-id": "3-2-1"
+                 }
+               ]
+             }
+           ],
+           "ietf-network-topology:link": [
+             {
+               "link-id": "D1,1-2-1,D2,2-1-1",
+               "source": {
+                 "source-node": "D1",
+                 "source-tp": "1-2-1"
+               },
+               "destination": {
+                 "dest-node": "D2",
+                 "dest-tp": "2-1-1"
+               }
+             },
+             {
+               "link-id": "D2,2-1-1,D1,1-2-1",
+               "source": {
+                 "source-node": "D2",
+                 "source-tp": "2-1-1"
+               },
+               "destination": {
+                 "dest-node": "D1",
+                 "dest-tp": "1-2-1"
+               }
+             },
+             {
+               "link-id": "D1,1-3-1,D3,3-1-1",
+               "source": {
+                 "source-node": "D1",
+                 "source-tp": "1-3-1"
+               },
+               "destination": {
+                 "dest-node": "D3",
+                 "dest-tp": "3-1-1"
+               }
+             },
+             {
+               "link-id": "D3,3-1-1,D1,1-3-1",
+               "source": {
+                 "source-node": "D3",
+                 "source-tp": "3-1-1"
+               },
+               "destination": {
+                 "dest-node": "D1",
+                 "dest-tp": "1-3-1"
+               }
+             },
+             {
+               "link-id": "D2,2-3-1,D3,3-2-1",
+               "source": {
+                 "source-node": "D2",
+                 "source-tp": "2-3-1"
+               },
+               "destination": {
+                 "dest-node": "D3",
+                 "dest-tp": "3-2-1"
+               }
+             },
+             {
+               "link-id": "D3,3-2-1,D2,2-3-1",
+               "source": {
+                 "source-node": "D3",
+                 "source-tp": "3-2-1"
+               },
+               "destination": {
+                 "dest-node": "D2",
+                 "dest-tp": "2-3-1"
+               }
+             }
+           ]
+         }
+       ]
+     }
+   }
old mode 100755 (executable)
new mode 100644 (file)
similarity index 99%
rename from cps-service/src/test/resources/e2e/basic/ietf-inet-types.yang
rename to cps-service/src/test/resources/ietf/ietf-inet-types@2013-07-15.yang
index 2f14270..eacefb6
@@ -328,6 +328,7 @@ module ietf-inet-types {
             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
             + '(/.+)';
     }
+
     description
      "The ipv6-prefix type represents an IPv6 address prefix.
       The prefix length is given by the number following the
@@ -353,11 +354,11 @@ module ietf-inet-types {
 
   typedef domain-name {
     type string {
-      length "1..253";
       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
diff --git a/cps-service/src/test/resources/ietf/ietf-network-state@2018-02-26.yang b/cps-service/src/test/resources/ietf/ietf-network-state@2018-02-26.yang
new file mode 100644 (file)
index 0000000..9a6893d
--- /dev/null
@@ -0,0 +1,176 @@
+module ietf-network-state {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-network-state";
+  prefix nw-s;
+
+  import ietf-network {
+    prefix nw;
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  organization
+    "IETF I2RS (Interface to the Routing System) Working Group";
+
+  contact
+    "WG Web:    <https://datatracker.ietf.org/wg/i2rs/>
+     WG List:   <mailto:i2rs@ietf.org>
+
+     Editor:    Alexander Clemm
+                <mailto:ludwig@clemm.org>
+
+     Editor:    Jan Medved
+                <mailto:jmedved@cisco.com>
+
+     Editor:    Robert Varga
+                <mailto:robert.varga@pantheon.tech>
+
+     Editor:    Nitin Bahadur
+                <mailto:nitin_bahadur@yahoo.com>
+     Editor:    Hariharan Ananthakrishnan
+                <mailto:hari@packetdesign.com>
+
+     Editor:    Xufeng Liu
+                <mailto:xufeng.liu.ietf@gmail.com>";
+
+  description
+    "This module defines a common base data model for a collection
+     of nodes in a network.  Node definitions are further used
+     in network topologies and inventories.  It represents
+     information that either (1) is learned and automatically
+     populated or (2) results from applying network information
+     that has been configured per the 'ietf-network' data model,
+     mirroring the corresponding data nodes in this data model.
+
+     The data model mirrors 'ietf-network' but contains only
+     read-only state data.  The data model is not needed when the
+     underlying implementation infrastructure supports the Network
+     Management Datastore Architecture (NMDA).
+
+     Copyright (c) 2018 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
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8345;
+     see the RFC itself for full legal notices.";
+
+  revision 2018-02-26 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  grouping network-ref {
+    description
+      "Contains the information necessary to reference a network --
+       for example, an underlay network.";
+    leaf network-ref {
+      type leafref {
+        path "/nw-s:networks/nw-s:network/nw-s:network-id";
+      require-instance false;
+      }
+      description
+        "Used to reference a network -- for example, an underlay
+         network.";
+    }
+  }
+
+  grouping node-ref {
+    description
+      "Contains the information necessary to reference a node.";
+    leaf node-ref {
+      type leafref {
+        path "/nw-s:networks/nw-s:network[nw-s:network-id=current()"+
+          "/../network-ref]/nw-s:node/nw-s:node-id";
+        require-instance false;
+      }
+      description
+        "Used to reference a node.
+         Nodes are identified relative to the network that
+         contains them.";
+    }
+    uses network-ref;
+  }
+
+  container networks {
+    config false;
+    description
+      "Serves as a top-level container for a list of networks.";
+    list network {
+      key "network-id";
+      description
+        "Describes a network.
+         A network typically contains an inventory of nodes,
+         topological information (augmented through the
+         network-topology data model), and layering information.";
+      container network-types {
+        description
+          "Serves as an augmentation target.
+           The network type is indicated through corresponding
+           presence containers augmented into this container.";
+      }
+      leaf network-id {
+        type nw:network-id;
+        description
+          "Identifies a network.";
+      }
+      list supporting-network {
+        key "network-ref";
+        description
+          "An underlay network, used to represent layered network
+           topologies.";
+        leaf network-ref {
+          type leafref {
+            path "/nw-s:networks/nw-s:network/nw-s:network-id";
+          require-instance false;
+          }
+          description
+            "References the underlay network.";
+        }
+      }
+
+      list node {
+        key "node-id";
+        description
+          "The inventory of nodes of this network.";
+        leaf node-id {
+          type nw:node-id;
+          description
+            "Uniquely identifies a node within the containing
+             network.";
+        }
+        list supporting-node {
+          key "network-ref node-ref";
+          description
+            "Represents another node that is in an underlay network
+             and that supports this node.  Used to represent layering
+             structure.";
+          leaf network-ref {
+            type leafref {
+              path "../../../nw-s:supporting-network/nw-s:network-ref";
+            require-instance false;
+            }
+            description
+              "References the underlay network of which the
+               underlay node is a part.";
+          }
+          leaf node-ref {
+            type leafref {
+              path "/nw-s:networks/nw-s:network/nw-s:node/nw-s:node-id";
+            require-instance false;
+            }
+            description
+              "References the underlay node itself.";
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/cps-service/src/test/resources/ietf/ietf-network-topology-state@2018-02-26.yang b/cps-service/src/test/resources/ietf/ietf-network-topology-state@2018-02-26.yang
new file mode 100644 (file)
index 0000000..1c1ba1b
--- /dev/null
@@ -0,0 +1,273 @@
+module ietf-network-topology-state {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-network-topology-state";
+  prefix nt-s;
+
+  import ietf-network-state {
+    prefix nw-s;
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+  import ietf-network-topology {
+    prefix nt;
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  organization
+    "IETF I2RS (Interface to the Routing System) Working Group";
+
+  contact
+    "WG Web:    <https://datatracker.ietf.org/wg/i2rs/>
+     WG List:   <mailto:i2rs@ietf.org>
+
+     Editor:    Alexander Clemm
+                <mailto:ludwig@clemm.org>
+
+     Editor:    Jan Medved
+                <mailto:jmedved@cisco.com>
+
+     Editor:    Robert Varga
+                <mailto:robert.varga@pantheon.tech>
+
+     Editor:    Nitin Bahadur
+                <mailto:nitin_bahadur@yahoo.com>
+
+     Editor:    Hariharan Ananthakrishnan
+                <mailto:hari@packetdesign.com>
+
+     Editor:    Xufeng Liu
+                <mailto:xufeng.liu.ietf@gmail.com>";
+
+  description
+    "This module defines a common base data model for network
+     topology state, representing topology that either (1) is learned
+     or (2) results from applying topology that has been configured
+     per the 'ietf-network-topology' data model, mirroring the
+     corresponding data nodes in this data model.  It augments the
+     base network state data model with links to connect nodes, as
+     well as termination points to terminate links on nodes.
+
+     The data model mirrors 'ietf-network-topology' but contains only
+     read-only state data.  The data model is not needed when the
+     underlying implementation infrastructure supports the Network
+     Management Datastore Architecture (NMDA).
+
+     Copyright (c) 2018 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
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8345;
+     see the RFC itself for full legal notices.";
+
+  revision 2018-02-26 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  grouping link-ref {
+    description
+      "References a link in a specific network.  Although this
+       grouping is not used in this module, it is defined here for
+       the convenience of augmenting modules.";
+    leaf link-ref {
+      type leafref {
+        path "/nw-s:networks/nw-s:network[nw-s:network-id=current()"+
+          "/../network-ref]/nt-s:link/nt-s:link-id";
+        require-instance false;
+      }
+      description
+        "A type for an absolute reference to a link instance.
+         (This type should not be used for relative references.
+         In such a case, a relative path should be used instead.)";
+    }
+    uses nw-s:network-ref;
+  }
+
+  grouping tp-ref {
+    description
+      "References a termination point in a specific node.  Although
+       this grouping is not used in this module, it is defined here
+       for the convenience of augmenting modules.";
+    leaf tp-ref {
+      type leafref {
+        path "/nw-s:networks/nw-s:network[nw-s:network-id=current()"+
+          "/../network-ref]/nw-s:node[nw-s:node-id=current()/../"+
+          "node-ref]/nt-s:termination-point/nt-s:tp-id";
+        require-instance false;
+      }
+      description
+        "A type for an absolute reference to a termination point.
+         (This type should not be used for relative references.
+         In such a case, a relative path should be used instead.)";
+    }
+    uses nw-s:node-ref;
+  }
+
+  augment "/nw-s:networks/nw-s:network" {
+    description
+      "Add links to the network data model.";
+    list link {
+      key "link-id";
+      description
+        "A network link connects a local (source) node and
+         a remote (destination) node via a set of the respective
+         node's termination points.  It is possible to have several
+         links between the same source and destination nodes.
+         Likewise, a link could potentially be re-homed between
+         termination points.  Therefore, in order to ensure that we
+         would always know to distinguish between links, every link
+         is identified by a dedicated link identifier.  Note that a
+         link models a point-to-point link, not a multipoint link.";
+      container source {
+        description
+          "This container holds the logical source of a particular
+           link.";
+        leaf source-node {
+          type leafref {
+            path "../../../nw-s:node/nw-s:node-id";
+            require-instance false;
+          }
+          description
+            "Source node identifier.  Must be in the same topology.";
+        }
+        leaf source-tp {
+          type leafref {
+            path "../../../nw-s:node[nw-s:node-id=current()/../"+
+              "source-node]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "This termination point is located within the source node
+             and terminates the link.";
+        }
+      }
+      container destination {
+        description
+          "This container holds the logical destination of a
+           particular link.";
+        leaf dest-node {
+          type leafref {
+            path "../../../nw-s:node/nw-s:node-id";
+          require-instance false;
+          }
+          description
+            "Destination node identifier.  Must be in the same
+             network.";
+        }
+
+        leaf dest-tp {
+          type leafref {
+            path "../../../nw-s:node[nw-s:node-id=current()/../"+
+              "dest-node]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "This termination point is located within the
+             destination node and terminates the link.";
+        }
+      }
+      leaf link-id {
+        type nt:link-id;
+        description
+          "The identifier of a link in the topology.
+           A link is specific to a topology to which it belongs.";
+      }
+      list supporting-link {
+        key "network-ref link-ref";
+        description
+          "Identifies the link or links on which this link depends.";
+        leaf network-ref {
+          type leafref {
+            path "../../../nw-s:supporting-network/nw-s:network-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which underlay topology
+             the supporting link is present.";
+        }
+        leaf link-ref {
+          type leafref {
+            path "/nw-s:networks/nw-s:network[nw-s:network-id="+
+              "current()/../network-ref]/link/link-id";
+            require-instance false;
+          }
+          description
+            "This leaf identifies a link that is a part
+             of this link's underlay.  Reference loops in which
+             a link identifies itself as its underlay, either
+             directly or transitively, are not allowed.";
+        }
+      }
+    }
+  }
+
+  augment "/nw-s:networks/nw-s:network/nw-s:node" {
+    description
+      "Augments termination points that terminate links.
+       Termination points can ultimately be mapped to interfaces.";
+    list termination-point {
+      key "tp-id";
+      description
+        "A termination point can terminate a link.
+         Depending on the type of topology, a termination point
+         could, for example, refer to a port or an interface.";
+      leaf tp-id {
+        type nt:tp-id;
+        description
+          "Termination point identifier.";
+      }
+      list supporting-termination-point {
+        key "network-ref node-ref tp-ref";
+        description
+          "This list identifies any termination points on which a
+           given termination point depends or onto which it maps.
+           Those termination points will themselves be contained
+           in a supporting node.  This dependency information can be
+           inferred from the dependencies between links.  Therefore,
+           this item is not separately configurable.  Hence, no
+           corresponding constraint needs to be articulated.
+           The corresponding information is simply provided by the
+           implementing system.";
+        leaf network-ref {
+          type leafref {
+            path "../../../nw-s:supporting-node/nw-s:network-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which topology the
+             supporting termination point is present.";
+        }
+        leaf node-ref {
+          type leafref {
+            path "../../../nw-s:supporting-node/nw-s:node-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which node the supporting
+             termination point is present.";
+        }
+
+        leaf tp-ref {
+          type leafref {
+            path "/nw-s:networks/nw-s:network[nw-s:network-id="+
+              "current()/../network-ref]/nw-s:node[nw-s:node-id="+
+              "current()/../node-ref]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "Reference to the underlay node (the underlay node must
+             be in a different topology).";
+        }
+      }
+    }
+  }
+}
diff --git a/cps-service/src/test/resources/ietf/ietf-network-topology@2018-02-26.yang b/cps-service/src/test/resources/ietf/ietf-network-topology@2018-02-26.yang
new file mode 100644 (file)
index 0000000..1ec944d
--- /dev/null
@@ -0,0 +1,294 @@
+module ietf-network-topology {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-network-topology";
+  prefix nt;
+
+  import ietf-inet-types {
+    prefix inet;
+    reference
+      "RFC 6991: Common YANG Data Types";
+  }
+  import ietf-network {
+    prefix nw;
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  organization
+    "IETF I2RS (Interface to the Routing System) Working Group";
+
+  contact
+    "WG Web:    <https://datatracker.ietf.org/wg/i2rs/>
+     WG List:   <mailto:i2rs@ietf.org>
+
+     Editor:    Alexander Clemm
+                <mailto:ludwig@clemm.org>
+
+     Editor:    Jan Medved
+                <mailto:jmedved@cisco.com>
+
+     Editor:    Robert Varga
+                <mailto:robert.varga@pantheon.tech>
+
+     Editor:    Nitin Bahadur
+                <mailto:nitin_bahadur@yahoo.com>
+
+     Editor:    Hariharan Ananthakrishnan
+                <mailto:hari@packetdesign.com>
+
+     Editor:    Xufeng Liu
+                <mailto:xufeng.liu.ietf@gmail.com>";
+
+  description
+    "This module defines a common base model for a network topology,
+     augmenting the base network data model with links to connect
+     nodes, as well as termination points to terminate links
+     on nodes.
+
+     Copyright (c) 2018 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
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8345;
+     see the RFC itself for full legal notices.";
+
+  revision 2018-02-26 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  typedef link-id {
+    type inet:uri;
+    description
+      "An identifier for a link in a topology.  The precise
+       structure of the link-id will be up to the implementation.
+       The identifier SHOULD be chosen such that the same link in a
+       real network topology will always be identified through the
+       same identifier, even if the data model is instantiated in
+       separate datastores.  An implementation MAY choose to capture
+       semantics in the identifier -- for example, to indicate the
+       type of link and/or the type of topology of which the link is
+       a part.";
+  }
+
+  typedef tp-id {
+    type inet:uri;
+    description
+      "An identifier for termination points on a node.  The precise
+       structure of the tp-id will be up to the implementation.
+       The identifier SHOULD be chosen such that the same termination
+       point in a real network topology will always be identified
+       through the same identifier, even if the data model is
+       instantiated in separate datastores.  An implementation MAY
+       choose to capture semantics in the identifier -- for example,
+       to indicate the type of termination point and/or the type of
+       node that contains the termination point.";
+  }
+
+  grouping link-ref {
+    description
+      "This grouping can be used to reference a link in a specific
+       network.  Although it is not used in this module, it is
+       defined here for the convenience of augmenting modules.";
+    leaf link-ref {
+      type leafref {
+        path "/nw:networks/nw:network[nw:network-id=current()/../"+
+          "network-ref]/nt:link/nt:link-id";
+        require-instance false;
+      }
+      description
+        "A type for an absolute reference to a link instance.
+         (This type should not be used for relative references.
+         In such a case, a relative path should be used instead.)";
+    }
+    uses nw:network-ref;
+  }
+
+  grouping tp-ref {
+    description
+      "This grouping can be used to reference a termination point
+       in a specific node.  Although it is not used in this module,
+       it is defined here for the convenience of augmenting
+       modules.";
+    leaf tp-ref {
+      type leafref {
+        path "/nw:networks/nw:network[nw:network-id=current()/../"+
+          "network-ref]/nw:node[nw:node-id=current()/../"+
+          "node-ref]/nt:termination-point/nt:tp-id";
+        require-instance false;
+      }
+      description
+        "A type for an absolute reference to a termination point.
+         (This type should not be used for relative references.
+         In such a case, a relative path should be used instead.)";
+    }
+    uses nw:node-ref;
+  }
+
+  augment "/nw:networks/nw:network" {
+    description
+      "Add links to the network data model.";
+    list link {
+      key "link-id";
+      description
+        "A network link connects a local (source) node and
+         a remote (destination) node via a set of the respective
+         node's termination points.  It is possible to have several
+         links between the same source and destination nodes.
+         Likewise, a link could potentially be re-homed between
+         termination points.  Therefore, in order to ensure that we
+         would always know to distinguish between links, every link
+         is identified by a dedicated link identifier.  Note that a
+         link models a point-to-point link, not a multipoint link.";
+      leaf link-id {
+        type link-id;
+        description
+          "The identifier of a link in the topology.
+           A link is specific to a topology to which it belongs.";
+      }
+      container source {
+        description
+          "This container holds the logical source of a particular
+           link.";
+        leaf source-node {
+          type leafref {
+            path "../../../nw:node/nw:node-id";
+            require-instance false;
+          }
+          description
+            "Source node identifier.  Must be in the same topology.";
+        }
+        leaf source-tp {
+          type leafref {
+            path "../../../nw:node[nw:node-id=current()/../"+
+              "source-node]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "This termination point is located within the source node
+             and terminates the link.";
+        }
+      }
+
+      container destination {
+        description
+          "This container holds the logical destination of a
+           particular link.";
+        leaf dest-node {
+          type leafref {
+            path "../../../nw:node/nw:node-id";
+          require-instance false;
+          }
+          description
+            "Destination node identifier.  Must be in the same
+             network.";
+        }
+        leaf dest-tp {
+          type leafref {
+            path "../../../nw:node[nw:node-id=current()/../"+
+              "dest-node]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "This termination point is located within the
+             destination node and terminates the link.";
+        }
+      }
+      list supporting-link {
+        key "network-ref link-ref";
+        description
+          "Identifies the link or links on which this link depends.";
+        leaf network-ref {
+          type leafref {
+            path "../../../nw:supporting-network/nw:network-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which underlay topology
+             the supporting link is present.";
+        }
+
+        leaf link-ref {
+          type leafref {
+            path "/nw:networks/nw:network[nw:network-id=current()/"+
+              "../network-ref]/link/link-id";
+            require-instance false;
+          }
+          description
+            "This leaf identifies a link that is a part
+             of this link's underlay.  Reference loops in which
+             a link identifies itself as its underlay, either
+             directly or transitively, are not allowed.";
+        }
+      }
+    }
+  }
+  augment "/nw:networks/nw:network/nw:node" {
+    description
+      "Augments termination points that terminate links.
+       Termination points can ultimately be mapped to interfaces.";
+    list termination-point {
+      key "tp-id";
+      description
+        "A termination point can terminate a link.
+         Depending on the type of topology, a termination point
+         could, for example, refer to a port or an interface.";
+      leaf tp-id {
+        type tp-id;
+        description
+          "Termination point identifier.";
+      }
+      list supporting-termination-point {
+        key "network-ref node-ref tp-ref";
+        description
+          "This list identifies any termination points on which a
+           given termination point depends or onto which it maps.
+           Those termination points will themselves be contained
+           in a supporting node.  This dependency information can be
+           inferred from the dependencies between links.  Therefore,
+           this item is not separately configurable.  Hence, no
+           corresponding constraint needs to be articulated.
+           The corresponding information is simply provided by the
+           implementing system.";
+
+        leaf network-ref {
+          type leafref {
+            path "../../../nw:supporting-node/nw:network-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which topology the
+             supporting termination point is present.";
+        }
+        leaf node-ref {
+          type leafref {
+            path "../../../nw:supporting-node/nw:node-ref";
+          require-instance false;
+          }
+          description
+            "This leaf identifies in which node the supporting
+             termination point is present.";
+        }
+        leaf tp-ref {
+          type leafref {
+            path "/nw:networks/nw:network[nw:network-id=current()/"+
+              "../network-ref]/nw:node[nw:node-id=current()/../"+
+              "node-ref]/termination-point/tp-id";
+            require-instance false;
+          }
+          description
+            "Reference to the underlay node (the underlay node must
+             be in a different topology).";
+        }
+      }
+    }
+  }
+}
diff --git a/cps-service/src/test/resources/ietf/ietf-network@2018-02-26.yang b/cps-service/src/test/resources/ietf/ietf-network@2018-02-26.yang
new file mode 100644 (file)
index 0000000..6a03d7e
--- /dev/null
@@ -0,0 +1,192 @@
+module ietf-network {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+  prefix nw;
+
+  import ietf-inet-types {
+    prefix inet;
+    reference
+      "RFC 6991: Common YANG Data Types";
+  }
+
+  organization
+    "IETF I2RS (Interface to the Routing System) Working Group";
+
+  contact
+    "WG Web:    <https://datatracker.ietf.org/wg/i2rs/>
+     WG List:   <mailto:i2rs@ietf.org>
+
+     Editor:    Alexander Clemm
+                <mailto:ludwig@clemm.org>
+
+     Editor:    Jan Medved
+                <mailto:jmedved@cisco.com>
+
+     Editor:    Robert Varga
+                <mailto:robert.varga@pantheon.tech>
+
+     Editor:    Nitin Bahadur
+                <mailto:nitin_bahadur@yahoo.com>
+
+     Editor:    Hariharan Ananthakrishnan
+                <mailto:hari@packetdesign.com>
+
+     Editor:    Xufeng Liu
+                <mailto:xufeng.liu.ietf@gmail.com>";
+  description
+    "This module defines a common base data model for a collection
+     of nodes in a network.  Node definitions are further used
+     in network topologies and inventories.
+
+     Copyright (c) 2018 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
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8345;
+     see the RFC itself for full legal notices.";
+
+  revision 2018-02-26 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 8345: A YANG Data Model for Network Topologies";
+  }
+
+  typedef node-id {
+    type inet:uri;
+    description
+      "Identifier for a node.  The precise structure of the node-id
+       will be up to the implementation.  For example, some
+       implementations MAY pick a URI that includes the network-id
+       as part of the path.  The identifier SHOULD be chosen
+       such that the same node in a real network topology will
+       always be identified through the same identifier, even if
+       the data model is instantiated in separate datastores.  An
+       implementation MAY choose to capture semantics in the
+       identifier -- for example, to indicate the type of node.";
+  }
+
+  typedef network-id {
+    type inet:uri;
+    description
+      "Identifier for a network.  The precise structure of the
+       network-id will be up to the implementation.  The identifier
+       SHOULD be chosen such that the same network will always be
+       identified through the same identifier, even if the data model
+       is instantiated in separate datastores.  An implementation MAY
+       choose to capture semantics in the identifier -- for example,
+       to indicate the type of network.";
+  }
+
+  grouping network-ref {
+    description
+      "Contains the information necessary to reference a network --
+       for example, an underlay network.";
+    leaf network-ref {
+      type leafref {
+        path "/nw:networks/nw:network/nw:network-id";
+      require-instance false;
+      }
+      description
+        "Used to reference a network -- for example, an underlay
+         network.";
+    }
+  }
+
+  grouping node-ref {
+    description
+      "Contains the information necessary to reference a node.";
+    leaf node-ref {
+      type leafref {
+        path "/nw:networks/nw:network[nw:network-id=current()/../"+
+          "network-ref]/nw:node/nw:node-id";
+        require-instance false;
+      }
+      description
+        "Used to reference a node.
+         Nodes are identified relative to the network that
+         contains them.";
+    }
+    uses network-ref;
+  }
+
+  container networks {
+    description
+      "Serves as a top-level container for a list of networks.";
+    list network {
+      key "network-id";
+      description
+        "Describes a network.
+         A network typically contains an inventory of nodes,
+         topological information (augmented through the
+         network-topology data model), and layering information.";
+      leaf network-id {
+        type network-id;
+        description
+          "Identifies a network.";
+      }
+      container network-types {
+        description
+          "Serves as an augmentation target.
+           The network type is indicated through corresponding
+           presence containers augmented into this container.";
+      }
+      list supporting-network {
+        key "network-ref";
+        description
+          "An underlay network, used to represent layered network
+           topologies.";
+        leaf network-ref {
+          type leafref {
+            path "/nw:networks/nw:network/nw:network-id";
+          require-instance false;
+          }
+          description
+            "References the underlay network.";
+        }
+      }
+
+      list node {
+        key "node-id";
+        description
+          "The inventory of nodes of this network.";
+        leaf node-id {
+          type node-id;
+          description
+            "Uniquely identifies a node within the containing
+             network.";
+        }
+        list supporting-node {
+          key "network-ref node-ref";
+          description
+            "Represents another node that is in an underlay network
+             and that supports this node.  Used to represent layering
+             structure.";
+          leaf network-ref {
+            type leafref {
+              path "../../../nw:supporting-network/nw:network-ref";
+            require-instance false;
+            }
+            description
+              "References the underlay network of which the
+               underlay node is a part.";
+          }
+          leaf node-ref {
+            type leafref {
+              path "/nw:networks/nw:network/nw:node/nw:node-id";
+            require-instance false;
+            }
+            description
+              "References the underlay node itself.";
+          }
+        }
+      }
+    }
+  }
+}
old mode 100755 (executable)
new mode 100644 (file)
similarity index 99%
rename from cps-service/src/test/resources/e2e/basic/ietf-yang-types.yang
rename to cps-service/src/test/resources/ietf/ietf-yang-types@2013-07-15.yang
index 371a091..ee58fa3
@@ -151,9 +151,6 @@ module ietf-yang-types {
      "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),
@@ -391,9 +388,6 @@ module ietf-yang-types {
       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