X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-service%2Fsrc%2Ftest%2Fgroovy%2Forg%2Fonap%2Fcps%2Fspi%2Fmodel%2FDataNodeBuilderSpec.groovy;h=fcbae628e6b276ca528340f94f1d56d4861462c1;hb=50851e424f8cbc7b11db5c2b840a62dc1c995207;hp=16d4efc273a96491e787fab54d00e5be6cb301a7;hpb=5e80e3776bb47483ca71bcc3fbe2cd8c2b9389e3;p=cps.git diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy index 16d4efc27..fcbae628e 100644 --- a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy @@ -1,7 +1,8 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech - * Modifications Copyright (C) 2021-2022 Nordix Foundation. + * Modifications Copyright (C) 2021-2023 Nordix Foundation. + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,18 +22,19 @@ package org.onap.cps.spi.model import org.onap.cps.TestUtils -import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.utils.DataMapUtils import org.onap.cps.utils.YangUtils import org.onap.cps.yang.YangTextSchemaSourceSetBuilder -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode +import org.opendaylight.yangtools.yang.data.api.schema.ForeignDataNode import spock.lang.Specification class DataNodeBuilderSpec extends Specification { - Map> expectedLeavesByXpathMap = [ + def objectUnderTest = new DataNodeBuilder() + + def expectedLeavesByXpathMap = [ '/test-tree' : [], '/test-tree/branch[@name=\'Left\']' : [name: 'Left'], '/test-tree/branch[@name=\'Left\']/nest' : [name: 'Small', birds: ['Sparrow', 'Robin', 'Finch']], @@ -50,17 +52,17 @@ class DataNodeBuilderSpec extends Specification { 'ietf/ietf-inet-types@2013-07-15.yang' ] - def 'Converting NormalizedNode (tree) to a DataNode (tree).'() { + def 'Converting ContainerNode (tree) to a DataNode (tree).'() { given: 'the schema context for expected model' def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang') def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext() - and: 'the json data parsed into normalized node object' + and: 'the json data parsed into container node object' def jsonData = TestUtils.getResourceFileContent('test-tree.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 containerNode = YangUtils.parseJsonData(jsonData, schemaContext) + when: 'the container node is converted to a data node' + def result = objectUnderTest.withContainerNode(containerNode).build() def mappedResult = TestUtils.getFlattenMapByXpath(result) - then: '5 DataNode objects with unique xpath were created in total' + then: '6 DataNode objects with unique xpath were created in total' mappedResult.size() == 6 and: 'all expected xpaths were built' mappedResult.keySet().containsAll(expectedLeavesByXpathMap.keySet()) @@ -70,39 +72,34 @@ class DataNodeBuilderSpec extends Specification { } } - def 'Converting NormalizedNode (tree) to a DataNode (tree) for known parent node.'() { + def 'Converting ContainerNode (tree) to a DataNode (tree) for known parent node.'() { given: 'a schema context for expected model' def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang') def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext() - and: 'the json data parsed into normalized node object' + and: 'the json data parsed into container node object' def jsonData = '{ "branch": [{ "name": "Branch", "nest": { "name": "Nest", "birds": ["bird"] } }] }' - def normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext, "/test-tree") - when: 'the normalized node is converted to a data node with parent node xpath defined' - def result = new DataNodeBuilder() - .withNormalizedNodeTree(normalizedNode) - .withParentNodeXpath("/test-tree") - .build() + def containerNode = YangUtils.parseJsonData(jsonData, schemaContext, "/test-tree") + when: 'the container node is converted to a data node with parent node xpath defined' + def result = objectUnderTest.withContainerNode(containerNode).withParentNodeXpath('/test-tree').build() def mappedResult = TestUtils.getFlattenMapByXpath(result) then: '2 DataNode objects with unique xpath were created in total' mappedResult.size() == 2 and: 'all expected xpaths were built' - mappedResult.keySet() - .containsAll(['/test-tree/branch[@name=\'Branch\']', '/test-tree/branch[@name=\'Branch\']/nest']) + mappedResult.keySet().containsAll(['/test-tree/branch[@name=\'Branch\']', '/test-tree/branch[@name=\'Branch\']/nest']) } - def 'Converting NormalizedNode (tree) to a DataNode (tree) -- augmentation case.'() { + def 'Converting ContainerNode (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' + and: 'the json data parsed into container 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 containerNode = YangUtils.parseJsonData(jsonData, schemaContext) + when: 'the container node is converted to a data node ' + def result = objectUnderTest.withContainerNode(containerNode).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']", @@ -122,35 +119,50 @@ class DataNodeBuilderSpec extends Specification { ]) } - def 'Converting NormalizedNode (tree) to a DataNode (tree) for known parent node -- augmentation case.'() { + def 'Converting ContainerNode (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' + and: 'the json data fragment parsed into container 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() + def containerNode = YangUtils.parseJsonData(jsonData, schemaContext, parentNodeXpath) + when: 'the container node is converted to a data node with given parent node xpath' + def result = objectUnderTest.withContainerNode(containerNode).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 'Converting NormalizedNode into DataNode collection: #scenario.'() { + def 'Converting ContainerNode (tree) to a DataNode (tree) -- with ChoiceNode.'() { + given: 'a schema context for expected model' + def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('yang-with-choice-node.yang') + def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext() + and: 'the json data fragment parsed into container node object' + def jsonData = TestUtils.getResourceFileContent('data-with-choice-node.json') + def containerNode = YangUtils.parseJsonData(jsonData, schemaContext) + when: 'the container node is converted to a data node' + def result = objectUnderTest.withContainerNode(containerNode).build() + def mappedResult = TestUtils.getFlattenMapByXpath(result) + then: 'the resulting data node contains only one xpath with 3 leaves' + mappedResult.keySet().containsAll([ '/container-with-choice-leaves' ]) + assert result.leaves['leaf-1'] == 'test' + assert result.leaves['choice-case1-leaf-a'] == 'test' + assert result.leaves['choice-case1-leaf-b'] == 'test' + } + + def 'Converting ContainerNode into DataNode collection: #scenario.'() { given: 'a schema context for expected model' def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang') def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext() and: 'parent node xpath referencing parent of list element' - def parentNodeXpath = "/test-tree" - and: 'the json data fragment (list element) parsed into normalized node object' - def normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext, parentNodeXpath) - when: 'the normalized node is converted to a data node collection' - def result = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode) - .withParentNodeXpath(parentNodeXpath).buildCollection() + def parentNodeXpath = '/test-tree' + and: 'the json data fragment (list element) parsed into container node object' + def containerNode = YangUtils.parseJsonData(jsonData, schemaContext, parentNodeXpath) + when: 'the container node is converted to a data node collection' + def result = objectUnderTest.withContainerNode(containerNode).withParentNodeXpath(parentNodeXpath).buildCollection() def resultXpaths = result.collect { it.getXpath() } then: 'the resulting collection contains data nodes for expected list elements' assert resultXpaths.size() == expectedSize @@ -161,27 +173,53 @@ class DataNodeBuilderSpec extends Specification { 'multiple entries' | '{"branch": [{"name": "One"}, {"name": "Two"}]}' | 2 | ['/test-tree/branch[@name=\'One\']', '/test-tree/branch[@name=\'Two\']'] } - def 'Converting NormalizedNode to a DataNode collection -- edge cases: #scenario.'() { - when: 'the normalized node is #node' - def result = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode).buildCollection() - then: 'the resulting collection contains data nodes for expected list elements' - assert result.size() == expectedSize - assert result.containsAll(expectedNodes) - where: 'following parameters are used' - scenario | node | normalizedNode | expectedSize | expectedNodes - 'NormalizedNode is null' | 'null' | null | 1 | [ new DataNode() ] - 'NormalizedNode is an unsupported type' | 'not supported' | Mock(NormalizedNode) | 0 | [ ] + def 'Converting ContainerNode to a Collection with #scenario.'() { + expect: 'converting null to a collection returns an empty collection' + assert objectUnderTest.withContainerNode(containerNode).buildCollection().isEmpty() + where: 'the following container node is used' + scenario | containerNode + 'null object' | null + 'object without body' | Mock(ContainerNode) + } + + def 'Converting ContainerNode to a DataNode with unsupported Normalized Node.'() { + given: 'a container node of an unsupported type' + def mockContainerNode = Mock(ContainerNode) + mockContainerNode.body() >> [ Mock(ForeignDataNode) ] + when: 'attempt to convert it' + objectUnderTest.withContainerNode(mockContainerNode).build() + then: 'a data validation exception is thrown' + thrown(DataValidationException) + } + + def 'Build datanode from attributes.'() { + when: 'data node is built' + def result = new DataNodeBuilder() + .withDataspace('my dataspace') + .withAnchor('my anchor') + .withModuleNamePrefix('my prefix') + .withXpath('some xpath') + .withLeaves([leaf1: 'value1']) + .withChildDataNodes([Mock(DataNode)]) + .build() + then: 'the datanode has all the defined attributes' + assert result.dataspace == 'my dataspace' + assert result.anchorName == 'my anchor' + assert result.moduleNamePrefix == 'my prefix' + assert result.moduleNamePrefix == 'my prefix' + assert result.xpath == 'some xpath' + assert result.leaves == [leaf1: 'value1'] + assert result.childDataNodes.size() == 1 } def 'Use of adding the module name prefix attribute of data node.'() { when: 'data node is built with a prefix' def testDataNode = new DataNodeBuilder() - .withModuleNamePrefix('sampleModuleNamePrefix') .withXpath(xPath) .withLeaves(sampleLeaves) .build() then: 'the result when node request is a #scenario includes the correct prefix' - def result = new DataMapUtils().toDataMapWithIdentifier(testDataNode) + def result = new DataMapUtils().toDataMapWithIdentifier(testDataNode, 'sampleModuleNamePrefix') result.toString() == expectedResult where: 'the following parameters are used' scenario | xPath | sampleLeaves | expectedResult