Support for Patch across multiple data nodes
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / functional / CpsDataServiceIntegrationSpec.groovy
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2023 Nordix Foundation
4  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the 'License');
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an 'AS IS' BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 package org.onap.cps.integration.functional
23
24 import org.onap.cps.api.CpsDataService
25 import org.onap.cps.integration.base.FunctionalSpecBase
26 import org.onap.cps.spi.FetchDescendantsOption
27 import org.onap.cps.spi.exceptions.AnchorNotFoundException
28 import org.onap.cps.spi.exceptions.DataValidationException
29 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
30
31 import java.time.OffsetDateTime
32
33 class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
34
35     CpsDataService objectUnderTest
36
37     def setup() { objectUnderTest = cpsDataService }
38
39     def 'Read bookstore top-level container(s) using #fetchDescendantsOption.'() {
40         when: 'get data nodes for bookstore container'
41             def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', fetchDescendantsOption)
42         then: 'the tree consist ouf of #expectNumberOfDataNodes data nodes'
43             assert countDataNodesInTree(result) == expectNumberOfDataNodes
44         and: 'the top level data node has the expected attribute and value'
45             assert result.leaves['bookstore-name'] == ['Easons']
46         where: 'the following option is used'
47             fetchDescendantsOption                         || expectNumberOfDataNodes
48             FetchDescendantsOption.OMIT_DESCENDANTS        || 1
49             FetchDescendantsOption.DIRECT_CHILDREN_ONLY    || 6
50             FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS || 17
51             new FetchDescendantsOption(2)                  || 17
52     }
53
54     def 'Read bookstore top-level container(s) has correct dataspace and anchor.'() {
55         when: 'get data nodes for bookstore container'
56             def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
57         then: 'the correct dataspace was queried'
58             assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet()
59         and: 'the correct anchor was queried'
60             assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1].toSet()
61     }
62
63     def 'Update multiple data node leaves.'() {
64         given: 'Updated json for bookstore data'
65             def jsonData =  "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda','authors':['RoaldDahl']}}"
66         when: 'update is performed for leaves'
67             objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_FOR_PATCH, "/bookstore/categories[@code='1']", jsonData, OffsetDateTime.now())
68         then: 'the updated data nodes are retrieved'
69             def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_FOR_PATCH, "/bookstore/categories[@code=1]/books[@title='Matilda']", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
70         and: 'the leaf values are updated as expected'
71             assert result.leaves['lang'] == ['English/French']
72             assert result.leaves['price'] == [100]
73     }
74
75     def 'Update multiple data leaves error scenario: #scenario.'() {
76         given: 'Updated json for bookstore data'
77             def jsonData =  "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda','authors':['RoaldDahl'],'pub_year':1988}}"
78         when: 'attempt to update data node for #scenario'
79             objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, xpath, jsonData, OffsetDateTime.now())
80         then: 'a #expectedException is thrown'
81             thrown(expectedException)
82         where: 'the following data is used'
83             scenario                 | dataspaceName                  | anchorName                 | xpath                 || expectedException
84             'invalid dataspace name' | 'INVALID DATAsPACE'            | 'not-relevant'             | '/not relevant'       || DataValidationException
85             'invalid anchor name'    | FUNCTIONAL_TEST_DATASPACE_1    | 'INVALID ANCHOR'           | '/not relevant'       || DataValidationException
86             'non-existing dataspace' | 'non-existing-dataspace'       | 'not-relevant'             | '/not relevant'       || DataspaceNotFoundException
87             'non-existing anchor'    | FUNCTIONAL_TEST_DATASPACE_1    | 'non-existing-anchor'      | '/not relevant'       || AnchorNotFoundException
88             'non-existing-xpath'     | FUNCTIONAL_TEST_DATASPACE_1    | BOOKSTORE_ANCHOR_FOR_PATCH | '/non-existing'       || DataValidationException
89     }
90 }