aboutsummaryrefslogtreecommitdiffstats
path: root/cps-rest/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'cps-rest/src/test')
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy231
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy229
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy16
3 files changed, 119 insertions, 357 deletions
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
index f2f962422f..e4cd8c4be6 100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
+ * Copyright (C) 2021-2025 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Bell Canada.
* Modifications Copyright (C) 2022 Deutsche Telekom AG
@@ -25,17 +25,12 @@
package org.onap.cps.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
-import groovy.json.JsonSlurper
-import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
-import org.onap.cps.api.parameters.FetchDescendantsOption
-import org.onap.cps.api.model.DataNode
-import org.onap.cps.impl.DataNodeBuilder
+import org.onap.cps.api.CpsFacade
import org.onap.cps.impl.DeltaReportBuilder
import org.onap.cps.utils.ContentType
import org.onap.cps.utils.DateTimeUtility
import org.onap.cps.utils.JsonObjectMapper
-import org.onap.cps.utils.PrefixResolver
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
@@ -44,7 +39,6 @@ import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.mock.web.MockMultipartFile
import org.springframework.test.web.servlet.MockMvc
-import org.springframework.web.multipart.MultipartFile
import spock.lang.Shared
import spock.lang.Specification
@@ -61,17 +55,14 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
class DataRestControllerSpec extends Specification {
@SpringBean
- CpsDataService mockCpsDataService = Mock()
+ CpsFacade mockCpsFacade = Mock()
@SpringBean
- CpsAnchorService mockCpsAnchorService = Mock()
+ CpsDataService mockCpsDataService = Mock()
@SpringBean
JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- @SpringBean
- PrefixResolver prefixResolver = Mock()
-
@Autowired
MockMvc mvc
@@ -97,20 +88,7 @@ class DataRestControllerSpec extends Specification {
def expectedXmlData = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n<bookstore xmlns="org:onap:ccsdk:sample">\n</bookstore>'
@Shared
- static DataNode dataNodeWithLeavesNoChildren = new DataNodeBuilder().withXpath('/parent-1')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
-
- @Shared
- static DataNode dataNodeWithLeavesNoChildren2 = new DataNodeBuilder().withXpath('/parent-2')
- .withLeaves([leaf: 'value']).build()
-
- @Shared
- static DataNode dataNodeWithChild = new DataNodeBuilder().withXpath('/parent')
- .withChildDataNodes([new DataNodeBuilder().withXpath("/parent/child").build()]).build()
-
- @Shared
- static MultipartFile multipartYangFile = new MockMultipartFile("file", 'filename.yang', "text/plain", 'content'.getBytes())
-
+ def multipartYangFile = new MockMultipartFile("file", 'filename.yang', "text/plain", 'content'.getBytes())
def setup() {
dataNodeBaseEndpointV1 = "$basePath/v1/dataspaces/$dataspaceName"
@@ -130,7 +108,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a created response is returned'
response.status == HttpStatus.CREATED.value()
- then: 'the java API was called with the correct parameters'
+ then: 'the cps data service was called with the correct parameters'
1 * mockCpsDataService.saveData(dataspaceName, anchorName, expectedData, noTimestamp, expectedContentType)
where: 'following xpath parameters are are used'
scenario | parentNodeXpath | contentType | expectedContentType | requestBody | expectedData
@@ -140,7 +118,7 @@ class DataRestControllerSpec extends Specification {
'XML content: xpath parameter point root' | '/' | MediaType.APPLICATION_XML | ContentType.XML | requestBodyXml | expectedXmlData
}
- def 'Create a node with observed-timestamp'() {
+ def 'Create a node with observed-timestamp.'() {
given: 'endpoint to create a node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
when: 'post is invoked with datanode endpoint and json'
@@ -154,7 +132,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a created response is returned'
response.status == expectedHttpStatus.value()
- then: 'the java API was called with the correct parameters'
+ then: 'the cps data service was called with the correct parameters'
expectedApiCount * mockCpsDataService.saveData(dataspaceName, anchorName, expectedData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType)
where:
@@ -164,7 +142,7 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON
}
- def 'Validate data using create a node API'() {
+ def 'Validate data using create a node API.'() {
given: 'an endpoint to create a node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
def parentNodeXpath = '/'
@@ -181,11 +159,11 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
- then: 'the service was called with correct parameters'
+ then: 'the cps data service was called with correct parameters'
1 * mockCpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, requestBodyJson, ContentType.JSON)
}
- def 'Create a child node #scenario'() {
+ def 'Create a child node #scenario.'() {
given: 'endpoint to create a node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
and: 'parent node xpath'
@@ -201,7 +179,7 @@ class DataRestControllerSpec extends Specification {
mvc.perform(postRequestBuilder).andReturn().response
then: 'a created response is returned'
response.status == HttpStatus.CREATED.value()
- then: 'the java API was called with the correct parameters'
+ then: 'the cps data service was called with the correct parameters'
1 * mockCpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, expectedData,
DateTimeUtility.toOffsetDateTime(observedTimestamp), expectedContentType)
where:
@@ -251,10 +229,10 @@ class DataRestControllerSpec extends Specification {
def response = mvc.perform(postRequestBuilder).andReturn().response
then: 'a created response is returned'
response.status == expectedHttpStatus.value()
- then: 'the java API was called with the correct parameters'
+ then: 'the cps data service was called with the correct parameters when needed'
expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, expectedData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType)
- where:
+ where: 'the following parameters are used'
scenario | observedTimestamp | contentType | requestBody || expectedApiCount | expectedHttpStatus | expectedData | expectedContentType
'Content type JSON with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
'Content type JSON without observed-timestamp' | null | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
@@ -280,34 +258,14 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
- then: 'the service was called with correct parameters'
+ then: 'the cps data service was called with correct parameters'
1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
}
- def 'Get data node with leaves'() {
- given: 'the service returns data node leaves'
- def xpath = 'parent-1'
- def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, OMIT_DESCENDANTS) >> [dataNodeWithLeavesNoChildren]
- when: 'get request is performed through REST API'
- def response =
- mvc.perform(get(endpoint).param('xpath', xpath))
- .andReturn().response
- then: 'a success response is returned'
- response.status == HttpStatus.OK.value()
- then: 'the response contains the the datanode in json format'
- response.getContentAsString() == '{"parent-1":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}'
- and: 'response contains expected leaf and value'
- response.contentAsString.contains('"leaf":"value"')
- and: 'response contains expected leaf-list and values'
- response.contentAsString.contains('"leafList":["leaveListElement1","leaveListElement2"]')
- }
-
- def 'Get data node with #scenario.'() {
+ def 'Get data nodes [V1] with #scenario.'() {
given: 'the service returns data node with #scenario'
- def xpath = 'some xPath'
+ def xpath = 'my/path'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, expectedCpsDataServiceOption) >> [dataNode]
when: 'get request is performed through REST API'
def response =
mvc.perform(
@@ -315,121 +273,42 @@ class DataRestControllerSpec extends Specification {
.param('xpath', xpath)
.param('include-descendants', includeDescendantsOption))
.andReturn().response
+ then: 'the cps facade is called with the correct parameters'
+ 1 * mockCpsFacade.getFirstDataNodeByAnchor(dataspaceName, anchorName, xpath, expectedCpsDataServiceOption) >> [mocked:'result']
then: 'a success response is returned'
response.status == HttpStatus.OK.value()
- and: 'the response contains the root node identifier: #expectedRootidentifier'
- response.contentAsString.contains(expectedRootidentifier)
- and: 'the response contains child is #expectChildInResponse'
- response.contentAsString.contains('"child"') == expectChildInResponse
- where:
- scenario | dataNode | includeDescendantsOption || expectedCpsDataServiceOption | expectChildInResponse | expectedRootidentifier
- 'no descendants by default' | dataNodeWithLeavesNoChildren | '' || OMIT_DESCENDANTS | false | 'parent-1'
- 'no descendant explicitly' | dataNodeWithLeavesNoChildren | 'false' || OMIT_DESCENDANTS | false | 'parent-1'
- 'with descendants' | dataNodeWithChild | 'true' || INCLUDE_ALL_DESCENDANTS | true | 'parent'
- }
-
- def 'Get all the data trees as json array with root node xPath using V2'() {
- given: 'the service returns all data node leaves'
- def xpath = '/'
- def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, OMIT_DESCENDANTS) >> [dataNodeWithLeavesNoChildren, dataNodeWithLeavesNoChildren2]
- when: 'V2 of get request is performed through REST API'
- def response =
- mvc.perform(get(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .param('xpath', xpath))
- .andReturn().response
- then: 'a success response is returned'
- response.status == HttpStatus.OK.value()
- and: 'the response contains the datanode in json array format'
- response.getContentAsString() == '[{"parent-1":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}},' +
- '{"parent-2":{"leaf":"value"}}]'
- and: 'the json array contains expected number of data trees'
- def numberOfDataTrees = new JsonSlurper().parseText(response.getContentAsString()).iterator().size()
- assert numberOfDataTrees == 2
- }
-
- def 'Get all the data trees using V2 without Content-Type defaults to json'() {
- given: 'the service returns all data node leaves'
- def xpath = '/'
- def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, OMIT_DESCENDANTS) >> [dataNodeWithLeavesNoChildren, dataNodeWithLeavesNoChildren2]
- when: 'V2 of get request is performed through REST API without specifying content-type header'
- def response =
- mvc.perform(get(endpoint)
- .param('xpath', xpath))
- .andReturn().response
- then: 'a success response is returned'
- response.status == HttpStatus.OK.value()
- and: 'the response contains the datanode in json array format'
- response.getContentAsString() == '[{"parent-1":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}},' +
- '{"parent-2":{"leaf":"value"}}]'
- }
-
- def 'Get all the data trees as XML with root node xPath using V2'() {
- given: 'the service returns all data node leaves'
- def xpath = '/'
- def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, OMIT_DESCENDANTS) >> [dataNodeWithLeavesNoChildren]
- when: 'V2 of get request is performed through REST API with XML content type'
- def response =
- mvc.perform(get(endpoint).contentType(MediaType.APPLICATION_XML).param('xpath', xpath))
- .andReturn().response
- then: 'a success response is returned'
- response.status == HttpStatus.OK.value()
- and: 'the response contains the datanode in XML format'
- response.getContentAsString() == '<parent-1><leaf>value</leaf><leafList>leaveListElement1</leafList><leafList>leaveListElement2</leafList></parent-1>'
+ and: 'the response contains the facade result in json format'
+ response.getContentAsString() == '{"mocked":"result"}'
+ where: 'the following parameters are used'
+ scenario | includeDescendantsOption || expectedCpsDataServiceOption
+ 'no descendants (default) ' | '' || OMIT_DESCENDANTS
+ 'with descendants' | 'true' || INCLUDE_ALL_DESCENDANTS
}
- def 'Get data node with #scenario using V2.'() {
+ def 'Get data node with #scenario using V2. output type #scenario.'() {
given: 'the service returns data nodes with #scenario'
def xpath = 'some xPath'
def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, expectedCpsDataServiceOption) >> [dataNode]
when: 'V2 of get request is performed through REST API'
def response =
- mvc.perform(
- get(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .param('xpath', xpath)
- .param('descendants', includeDescendantsOption))
- .andReturn().response
- then: 'a success response is returned'
- response.status == HttpStatus.OK.value()
- and: 'the response contains the root node identifier: #expectedRootidentifier'
- response.contentAsString.contains(expectedRootidentifier)
- and: 'the response contains child is #expectChildInResponse'
- response.contentAsString.contains('"child"') == expectChildInResponse
- where:
- scenario | dataNode | includeDescendantsOption || expectedCpsDataServiceOption | expectChildInResponse | expectedRootidentifier
- 'no descendants by default' | dataNodeWithLeavesNoChildren | '' || OMIT_DESCENDANTS | false | 'parent-1'
- 'no descendant explicitly' | dataNodeWithLeavesNoChildren | '0' || OMIT_DESCENDANTS | false | 'parent-1'
- 'with descendants' | dataNodeWithChild | '-1' || INCLUDE_ALL_DESCENDANTS | true | 'parent'
- }
-
- def 'Get data node using v2 api'() {
- given: 'the service returns data node'
- def xpath = 'some xPath'
- def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
- mockCpsDataService.getDataNodes(dataspaceName, anchorName, xpath, { descendantsOption -> {
- assert descendantsOption.depth == 2}} as FetchDescendantsOption) >> [dataNodeWithChild]
- when: 'get request is performed through REST API'
- def response =
- mvc.perform(
- get(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
+ mvc.perform(get(endpoint)
+ .contentType(contentType)
.param('xpath', xpath)
- .param('descendants', '2'))
+ .param('descendants', 'all'))
.andReturn().response
- then: 'a success response is returned'
+ then: 'the cps service facade is called with the correct parameters and returns some data'
+ 1 * mockCpsFacade.getDataNodesByAnchor(dataspaceName, anchorName, xpath, INCLUDE_ALL_DESCENDANTS) >> [[mocked:'result1'], [mocked:'result2']]
+ and: 'a success response is returned'
assert response.status == HttpStatus.OK.value()
- and: 'the response contains the root node identifier'
- assert response.contentAsString.contains('parent')
- and: 'the response contains child is true'
- assert response.contentAsString.contains('"child"')
+ and: 'the response is in the expected format'
+ assert response.contentAsString == expectedResult
+ where: 'the following content types are used'
+ scenario | contentType || expectedResult
+ 'XML' | MediaType.APPLICATION_XML || '<mocked>result1</mocked><mocked>result2</mocked>'
+ 'JSON' | MediaType.APPLICATION_JSON || '[{"mocked":"result1"},{"mocked":"result2"}]'
}
- def 'Get delta between two anchors'() {
+ def 'Get delta between two anchors.'() {
given: 'the service returns a list containing delta reports'
def deltaReports = new DeltaReportBuilder().actionReplace().withXpath('some xpath').withSourceData('some key': 'some value').withTargetData('some key': 'some value').build()
def xpath = 'some xpath'
@@ -468,7 +347,7 @@ class DataRestControllerSpec extends Specification {
assert response.contentAsString.contains("[{\"action\":\"create\",\"xpath\":\"some xpath\"}]")
}
- def 'Get delta between anchor and JSON payload without multipart file'() {
+ def 'Get delta between anchor and JSON payload without multipart file.'() {
given: 'sample delta report, xpath, and json payload'
def deltaReports = new DeltaReportBuilder().actionRemove().withXpath('some xpath').build()
def xpath = 'some xpath'
@@ -499,7 +378,7 @@ class DataRestControllerSpec extends Specification {
.content(requestBody)
.param('xpath', inputXpath)
).andReturn().response
- then: 'the service method is invoked with expected parameters'
+ then: 'the cps data service method is invoked with expected parameters'
1 * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, xpathServiceParameter, expectedData, null, expectedContentType)
and: 'response status indicates success'
response.status == HttpStatus.OK.value()
@@ -513,7 +392,7 @@ class DataRestControllerSpec extends Specification {
'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
- def 'Update data node leaves with observedTimestamp'() {
+ def 'Update data node leaves with observedTimestamp.'() {
given: 'endpoint to update a node leaves '
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
when: 'patch request is performed'
@@ -525,7 +404,7 @@ class DataRestControllerSpec extends Specification {
.param('xpath', '/')
.param('observed-timestamp', observedTimestamp)
).andReturn().response
- then: 'the service method is invoked with expected parameters'
+ then: 'the cps data service method is invoked with expected parameters'
expectedApiCount * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, '/', expectedJsonData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
and: 'response status indicates success'
@@ -536,7 +415,7 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
}
- def 'Validate data using Update a node API'() {
+ def 'Validate data using Update a node API.'() {
given: 'endpoint to update a node leaves'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
and: 'dryRunEnabled flag is set to true'
@@ -552,7 +431,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
- then: 'the service was called with correct parameters'
+ then: 'the cps data service was called with correct parameters'
1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
}
@@ -567,7 +446,7 @@ class DataRestControllerSpec extends Specification {
.content(requestBody)
.param('xpath', inputXpath))
.andReturn().response
- then: 'the service method is invoked with expected parameters'
+ then: 'the cps data service method is invoked with expected parameters'
1 * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, xpathServiceParameter, expectedData, noTimestamp, expectedContentType)
and: 'response status indicates success'
response.status == HttpStatus.OK.value()
@@ -581,7 +460,7 @@ class DataRestControllerSpec extends Specification {
'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
- def 'Validate data using Replace data node API'() {
+ def 'Validate data using Replace data node API.'() {
given: 'endpoint to replace node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
and: 'dryRunEnabled flag is set to true'
@@ -597,7 +476,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
- then: 'the service was called with correct parameters'
+ then: 'the cps data service was called with correct parameters'
1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
}
@@ -613,7 +492,7 @@ class DataRestControllerSpec extends Specification {
.param('xpath', '')
.param('observed-timestamp', observedTimestamp))
.andReturn().response
- then: 'the service method is invoked with expected parameters'
+ then: 'the cps data service method is invoked with expected parameters'
expectedApiCount * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, '/', expectedJsonData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
and: 'response status indicates success'
@@ -635,7 +514,7 @@ class DataRestControllerSpec extends Specification {
def response = mvc.perform(putRequestBuilder).andReturn().response
then: 'a success response is returned'
response.status == expectedHttpStatus.value()
- and: 'the java API was called with the correct parameters'
+ and: 'the cps data service was called with the correct parameters'
expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedJsonData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
where:
@@ -656,7 +535,7 @@ class DataRestControllerSpec extends Specification {
def response = mvc.perform(putRequestBuilder).andReturn().response
then: 'a success response is returned'
response.status == expectedHttpStatus.value()
- and: 'the java API was called with the correct parameters'
+ and: 'the cps data service was called with the correct parameters'
expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedXmlData,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.XML)
where:
@@ -666,7 +545,7 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
}
- def 'Validate data using Replace list content API'() {
+ def 'Validate data using Replace list content API.'() {
given: 'endpoint to replace list-nodes'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes"
and: 'dryRunEnabled flag is set to true'
@@ -682,7 +561,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
- then: 'the service was called with correct parameters'
+ then: 'the cps data service was called with correct parameters'
1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
}
@@ -695,7 +574,7 @@ class DataRestControllerSpec extends Specification {
def response = mvc.perform(deleteRequestBuilder).andReturn().response
then: 'a success response is returned'
response.status == expectedHttpStatus.value()
- and: 'the java API was called with the correct parameters'
+ and: 'the cps data service was called with the correct parameters'
expectedApiCount * mockCpsDataService.deleteListOrListElement(dataspaceName, anchorName, 'list element xpath',
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
where:
@@ -717,7 +596,7 @@ class DataRestControllerSpec extends Specification {
def response = mvc.perform(deleteDataNodeRequest).andReturn().response
then: 'a successful response is returned'
response.status == expectedHttpStatus.value()
- and: 'the api is called with the correct parameters'
+ and: 'the cps data service is called with the correct parameters'
expectedApiCount * mockCpsDataService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath,
{ it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
where:
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
index 2b5c471287..5f6de2ec4c 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
+ * Copyright (C) 2021-2025 Nordix Foundation
* Modifications Copyright (C) 2021-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
@@ -24,12 +24,9 @@
package org.onap.cps.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.api.CpsAnchorService
-import org.onap.cps.api.CpsQueryService
+import org.onap.cps.api.CpsFacade
import org.onap.cps.api.parameters.PaginationOption
-import org.onap.cps.impl.DataNodeBuilder
import org.onap.cps.utils.JsonObjectMapper
-import org.onap.cps.utils.PrefixResolver
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
@@ -39,216 +36,98 @@ import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification
-import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
@WebMvcTest(QueryRestController)
class QueryRestControllerSpec extends Specification {
@SpringBean
- CpsQueryService mockCpsQueryService = Mock()
-
- @SpringBean
- CpsAnchorService mockCpsAnchorService = Mock()
+ CpsFacade mockCpsFacade = Mock()
@SpringBean
JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- @SpringBean
- PrefixResolver prefixResolver = Mock()
-
@Autowired
MockMvc mvc
@Value('${rest.api.cps-base-path}')
def basePath
- def dataspaceName = 'my_dataspace'
- def anchorName = 'my_anchor'
- def cpsPath = 'some cps-path'
- def dataNodeEndpointV2
-
- def setup() {
- dataNodeEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query"
- }
+ def dataNodeAsMap = ['prefixedPath':[path:[leaf:'value']]]
- def 'Query data node by cps path for the given dataspace and anchor with #scenario.'() {
- given: 'service method returns a list containing a data node'
- def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, expectedCpsDataServiceOption) >> [dataNode1, dataNode1]
- and: 'the query endpoint'
- def dataNodeEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query"
+ def 'Query data node (v1) by cps path for the given dataspace and anchor with #scenario.'() {
+ given: 'the query endpoint'
+ def dataNodeEndpoint = "$basePath/v1/dataspaces/my_dataspace/anchors/my_anchor/nodes/query"
when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpoint)
- .param('cps-path', cpsPath)
- .param('include-descendants', includeDescendantsOption))
- .andReturn().response
+ def response = mvc.perform(get(dataNodeEndpoint).param('cps-path', 'my/path').param('include-descendants', includeDescendantsOption))
+ .andReturn().response
+ then: 'the call is delegated to the cps service facade which returns a list containing one data node as a map'
+ 1 * mockCpsFacade.executeAnchorQuery('my_dataspace', 'my_anchor', 'my/path', expectedCpsDataServiceOption) >> [dataNodeAsMap]
then: 'the response contains the the datanode in json format'
- response.status == HttpStatus.OK.value()
- response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
+ assert response.status == HttpStatus.OK.value()
+ assert response.getContentAsString() == '[{"prefixedPath":{"path":{"leaf":"value"}}}]'
where: 'the following options for include descendants are provided in the request'
scenario | includeDescendantsOption || expectedCpsDataServiceOption
'no descendants by default' | '' || OMIT_DESCENDANTS
- 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS
'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS
}
- def 'Query data node v2 API by cps path for the given dataspace and anchor with #scenario and media type JSON'() {
- given: 'service method returns a list containing a data node'
- def dataNode = new DataNodeBuilder().withXpath('/xpath')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption ->
- assert descendantsOption.depth == expectedDepth
- }) >> [dataNode, dataNode]
+ def 'Query data node (v2) by cps path for given dataspace and anchor with #scenario'() {
+ given: 'the query endpoint'
+ def dataNodeEndpointV2 = "$basePath/v2/dataspaces/my_dataspace/anchors/my_anchor/nodes/query"
when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpointV2)
- .contentType(MediaType.APPLICATION_JSON)
- .param('cps-path', cpsPath)
- .param('descendants', includeDescendantsOptionString))
+ def response = mvc.perform(get(dataNodeEndpointV2).contentType(contentType).param('cps-path', 'my/path') .param('descendants', includeDescendantsOptionString))
.andReturn().response
- then: 'the response contains the datanode in the expected JSON format'
+ then: 'the call is delegated to the cps service facade which returns a list containing one data node as a map'
+ 1 * mockCpsFacade.executeAnchorQuery('my_dataspace', 'my_anchor', 'my/path',
+ { descendantsOption -> assert descendantsOption.depth == expectedDepth }) >> [dataNodeAsMap]
+ and: 'the response contains the datanode in the expected format'
assert response.status == HttpStatus.OK.value()
- assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
+ assert response.getContentAsString() == expectedOutput
where: 'the following options for include descendants are provided in the request'
- scenario | includeDescendantsOptionString || expectedDepth
- 'direct children' | 'direct' || 1
- 'descendants' | '2' || 2
+ scenario | includeDescendantsOptionString | contentType || expectedDepth || expectedOutput
+ 'direct children JSON' | 'direct' | MediaType.APPLICATION_JSON || 1 || '[{"prefixedPath":{"path":{"leaf":"value"}}}]'
+ 'descendants JSON' | '2' | MediaType.APPLICATION_JSON || 2 || '[{"prefixedPath":{"path":{"leaf":"value"}}}]'
+ 'descendants XML' | '2' | MediaType.APPLICATION_XML || 2 || '<prefixedPath><path><leaf>value</leaf></path></prefixedPath>'
}
- def 'Query data node v2 API by cps path for the given dataspace and anchor with #scenario and media type XML'() {
- given: 'service method returns a list containing a data node'
- def dataNode = new DataNodeBuilder().withXpath('/xpath')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption ->
- assert descendantsOption.depth == expectedDepth
- }) >> [dataNode, dataNode]
+ def 'Query data node by cps path for given dataspace across all anchors'() {
+ given: 'the query endpoint'
+ def dataNodeEndpoint = "$basePath/v2/dataspaces/my_dataspace/nodes/query"
+ and: 'the cps service facade will say there are 123 pages '
+ mockCpsFacade.countAnchorsInDataspaceQuery('my_dataspace', 'my/path', new PaginationOption(2,5) ) >> 123
when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpointV2)
- .contentType(MediaType.APPLICATION_XML)
- .param('cps-path', cpsPath)
- .param('descendants', includeDescendantsOptionString))
- .andReturn().response
- then: 'the response contains the datanode in the expected XML format'
- assert response.status == HttpStatus.OK.value()
- assert response.getContentAsString().contains('<xpath><leaf>value</leaf><leafList>leaveListElement1</leafList><leafList>leaveListElement2</leafList></xpath>')
- where: 'the following options for include descendants are provided in the request'
- scenario | includeDescendantsOptionString || expectedDepth
- 'direct children' | 'direct' || 1
- 'descendants' | '2' || 2
- }
-
- def 'Query data node by cps path for the given dataspace across all anchors with #scenario.'() {
- given: 'service method returns a list containing a data node from different anchors'
- def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- def dataNode2 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor_2')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement3', 'leaveListElement4']]).build()
- and: 'second data node for the same anchor'
- def dataNode3 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor_2')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement5', 'leaveListElement6']]).build()
- and: 'the query endpoint'
- def dataspaceName = 'my_dataspace'
- def cpsPath = 'some/cps/path'
- def dataNodeEndpoint = "$basePath/v2/dataspaces/$dataspaceName/nodes/query"
- mockCpsQueryService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath,
- expectedCpsDataServiceOption, PaginationOption.NO_PAGINATION) >> [dataNode1, dataNode2, dataNode3]
- mockCpsQueryService.countAnchorsForDataspaceAndCpsPath(dataspaceName, cpsPath) >> 2
- when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpoint)
- .param('cps-path', cpsPath)
- .param('descendants', includeDescendantsOptionString))
+ def response = mvc.perform(
+ get(dataNodeEndpoint).param('cps-path', 'my/path').param('pageIndex', String.valueOf(2)).param('pageSize', String.valueOf(5)))
.andReturn().response
- then: 'the response contains the the datanode in json format'
- response.status == HttpStatus.OK.value()
- response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
- response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement3","leaveListElement4"]}}')
- response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement5","leaveListElement6"]}}')
- where: 'the following options for include descendants are provided in the request'
- scenario | includeDescendantsOptionString || expectedCpsDataServiceOption
- 'no descendants by default' | '' || OMIT_DESCENDANTS
- 'no descendant explicitly' | 'none' || OMIT_DESCENDANTS
- 'descendants' | 'all' || INCLUDE_ALL_DESCENDANTS
- 'direct children' | 'direct' || DIRECT_CHILDREN_ONLY
- }
-
- def 'Query data node by cps path for the given dataspace across all anchors with pagination #scenario.'() {
- given: 'service method returns a list containing a data node from different anchors'
- def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- def dataNode2 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor_2')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement3', 'leaveListElement4']]).build()
- and: 'the query endpoint'
- def dataspaceName = 'my_dataspace'
- def cpsPath = 'some/cps/path'
- def dataNodeEndpoint = "$basePath/v2/dataspaces/$dataspaceName/nodes/query"
- mockCpsQueryService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath,
- INCLUDE_ALL_DESCENDANTS, new PaginationOption(pageIndex,pageSize)) >> [dataNode1, dataNode2]
- mockCpsQueryService.countAnchorsForDataspaceAndCpsPath(dataspaceName, cpsPath) >> totalAnchors
- when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpoint)
- .param('cps-path', cpsPath)
- .param('descendants', "all")
- .param('pageIndex', String.valueOf(pageIndex))
- .param('pageSize', String.valueOf(pageSize)))
- .andReturn().response
- then: 'the response contains the the datanode in json format'
+ then: 'the call is delegated to the cps service facade which returns a list containing one data node as a map'
+ 1 * mockCpsFacade.executeDataspaceQuery('my_dataspace', 'my/path', OMIT_DESCENDANTS, new PaginationOption(2,5)) >> [dataNodeAsMap]
+ then: 'the response is OK and contains the the datanode in json format'
assert response.status == HttpStatus.OK.value()
- assert Integer.valueOf(response.getHeaderValue("total-pages")) == expectedTotalPageSize
- assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
- assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement3","leaveListElement4"]}}')
- where: 'the following options for include descendants are provided in the request'
- scenario | pageIndex | pageSize | totalAnchors || expectedTotalPageSize
- '1st page with all anchors' | 1 | 3 | 3 || 1
- '1st page with less anchors' | 1 | 2 | 3 || 2
+ assert response.getContentAsString() == '[{"prefixedPath":{"path":{"leaf":"value"}}}]'
+ and: 'the header indicates the correct number of pages'
+ assert response.getHeaderValue('total-pages') == '123'
}
- def 'Query data node across all anchors with pagination option with #scenario.'() {
- given: 'service method returns a list containing a data node from different anchors'
- def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
- def dataNode2 = new DataNodeBuilder().withXpath('/xpath')
- .withAnchor('my_anchor_2')
- .withLeaves([leaf: 'value', leafList: ['leaveListElement3', 'leaveListElement4']]).build()
- and: 'the query endpoint'
- def dataspaceName = 'my_dataspace'
- def cpsPath = 'some/cps/path'
- def dataNodeEndpoint = "$basePath/v2/dataspaces/$dataspaceName/nodes/query"
- mockCpsQueryService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath,
- INCLUDE_ALL_DESCENDANTS, PaginationOption.NO_PAGINATION) >> [dataNode1, dataNode2]
- mockCpsQueryService.countAnchorsForDataspaceAndCpsPath(dataspaceName, cpsPath) >> 2
+ def 'Query data node across all anchors with pagination option with #scenario i.e. no pagination.'() {
+ given: 'the query endpoint'
+ def dataNodeEndpoint = "$basePath/v2/dataspaces/my_dataspace/nodes/query"
+ and: 'the cps service facade will say there is 1 page '
+ mockCpsFacade.countAnchorsInDataspaceQuery('my_dataspace', 'my/path', NO_PAGINATION ) >> 1
when: 'query data nodes API is invoked'
- def response =
- mvc.perform(
- get(dataNodeEndpoint)
- .param('cps-path', cpsPath)
- .param('descendants', "all")
- .param(parameterName, "1"))
- .andReturn().response
- then: 'the response contains the the datanode in json format'
+ def response = mvc.perform(get(dataNodeEndpoint).param('cps-path', 'my/path').param(parameterName, '1'))
+ .andReturn().response
+ then: 'the call is delegated to the cps service facade which returns a list containing one data node as a map'
+ 1 * mockCpsFacade.executeDataspaceQuery('my_dataspace', 'my/path', OMIT_DESCENDANTS, PaginationOption.NO_PAGINATION) >> [dataNodeAsMap]
+ then: 'the response is OK and contains the datanode in json format'
assert response.status == HttpStatus.OK.value()
- assert Integer.valueOf(response.getHeaderValue("total-pages")) == 1
- assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
- assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement3","leaveListElement4"]}}')
- where:
+ assert response.getContentAsString() == '[{"prefixedPath":{"path":{"leaf":"value"}}}]'
+ and: 'the header indicates the correct number of pages'
+ assert response.getHeaderValue('total-pages') == '1'
+ where: 'only the following rest parameter is used'
scenario | parameterName
'only page size' | 'pageSize'
'only page index' | 'pageIndex'
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy
index 4e1d27cda2..0cbdffbdc4 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2025 Nordix Foundation
* Modifications Copyright (C) 2021 Bell Canada.
* Modifications Copyright (C) 2022-2025 TechMahindra Ltd.
* Modifications Copyright (C) 2022 Deutsche Telekom AG
@@ -26,23 +26,24 @@ package org.onap.cps.rest.exceptions
import com.fasterxml.jackson.databind.ObjectMapper
import groovy.json.JsonSlurper
-import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsDataspaceService
+import org.onap.cps.api.CpsFacade
import org.onap.cps.api.CpsModuleService
import org.onap.cps.api.CpsNotificationService
import org.onap.cps.api.CpsQueryService
-import org.onap.cps.rest.controller.CpsRestInputMapper
import org.onap.cps.api.exceptions.AlreadyDefinedException
import org.onap.cps.api.exceptions.CpsException
import org.onap.cps.api.exceptions.CpsPathException
import org.onap.cps.api.exceptions.DataInUseException
import org.onap.cps.api.exceptions.DataNodeNotFoundException
import org.onap.cps.api.exceptions.DataValidationException
+import org.onap.cps.api.exceptions.DataspaceInUseException
import org.onap.cps.api.exceptions.ModelValidationException
import org.onap.cps.api.exceptions.NotFoundInDataspaceException
import org.onap.cps.api.exceptions.SchemaSetInUseException
-import org.onap.cps.api.exceptions.DataspaceInUseException
+import org.onap.cps.rest.controller.CpsRestInputMapper
import org.onap.cps.utils.JsonObjectMapper
import org.onap.cps.utils.PrefixResolver
import org.spockframework.spring.SpringBean
@@ -65,6 +66,9 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
class CpsRestExceptionHandlerSpec extends Specification {
@SpringBean
+ CpsFacade mockCpsFacade = Stub()
+
+ @SpringBean
CpsDataspaceService mockCpsAdminService = Stub()
@SpringBean
@@ -86,10 +90,10 @@ class CpsRestExceptionHandlerSpec extends Specification {
CpsRestInputMapper cpsRestInputMapper = Stub()
@SpringBean
- PrefixResolver prefixResolver = Mock()
+ PrefixResolver prefixResolver = Stub()
@SpringBean
- CpsNotificationService mockCpsNotificationService = Mock()
+ CpsNotificationService mockCpsNotificationService = Stub()
@Autowired
MockMvc mvc