summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]cps-rest/docs/api/swagger/cpsAdmin.yml2
-rw-r--r--cps-rest/docs/api/swagger/cpsData.yml43
-rwxr-xr-x[-rw-r--r--]cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java3
-rw-r--r--cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java18
-rwxr-xr-x[-rw-r--r--]cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy204
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy72
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy4
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java13
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java63
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java8
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangUtils.java17
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy70
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy11
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy54
-rw-r--r--cps-service/src/test/resources/e2e/basic/Data.txt42
-rw-r--r--cps-service/src/test/resources/e2e/basic/cps-cavsta-onap-internal2021-01-28.yang153
16 files changed, 639 insertions, 138 deletions
diff --git a/cps-rest/docs/api/swagger/cpsAdmin.yml b/cps-rest/docs/api/swagger/cpsAdmin.yml
index d33c8e55c..18ed1a2ec 100644..100755
--- a/cps-rest/docs/api/swagger/cpsAdmin.yml
+++ b/cps-rest/docs/api/swagger/cpsAdmin.yml
@@ -146,7 +146,7 @@ anchorByDataspaceAndAnchorName:
get:
tags:
- cps-admin
- summary: Read an anchor given a anchor and a dataspace - DRAFT
+ summary: Read an anchor given a anchor and a dataspace
operationId: getAnchor
parameters:
- $ref: 'components.yaml#/components/parameters/dataspaceNameInPath'
diff --git a/cps-rest/docs/api/swagger/cpsData.yml b/cps-rest/docs/api/swagger/cpsData.yml
index c33cf168e..dcdb99adc 100644
--- a/cps-rest/docs/api/swagger/cpsData.yml
+++ b/cps-rest/docs/api/swagger/cpsData.yml
@@ -20,46 +20,47 @@ nodesByDataspaceAndAnchor:
$ref: 'components.yaml#/components/responses/NotFound'
x-codegen-request-body-name: xpath
-nodesByDataspace:
- get:
+ post:
tags:
- cps-data
- summary: Get all nodes for a given dataspace using an xpath or schema node identifier - DRAFT
- operationId: getNode
+ summary: Create a node for a given anchor for the given dataspace
+ operationId: createNode
parameters:
- $ref: 'components.yaml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yaml#/components/parameters/anchorNameInPath'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: string
responses:
- 200:
- $ref: 'components.yaml#/components/responses/Ok'
+ 201:
+ $ref: 'components.yaml#/components/responses/Created'
400:
$ref: 'components.yaml#/components/responses/BadRequest'
401:
$ref: 'components.yaml#/components/responses/Unauthorized'
403:
$ref: 'components.yaml#/components/responses/Forbidden'
- 404:
- $ref: 'components.yaml#/components/responses/NotFound'
- x-codegen-request-body-name: requestBody
- post:
+nodesByDataspace:
+ get:
tags:
- cps-data
- summary: Create a node for a given anchor for the given dataspace - DRAFT
- operationId: createNode
+ summary: Get all nodes for a given dataspace using an xpath or schema node identifier - DRAFT
+ operationId: getNode
parameters:
- $ref: 'components.yaml#/components/parameters/dataspaceNameInPath'
- requestBody:
- content:
- multipart/form-data:
- schema:
- $ref: 'components.yaml#/components/schemas/MultipartFile'
- required: true
responses:
- 201:
- $ref: 'components.yaml#/components/responses/Created'
+ 200:
+ $ref: 'components.yaml#/components/responses/Ok'
400:
$ref: 'components.yaml#/components/responses/BadRequest'
401:
$ref: 'components.yaml#/components/responses/Unauthorized'
403:
- $ref: 'components.yaml#/components/responses/Forbidden' \ No newline at end of file
+ $ref: 'components.yaml#/components/responses/Forbidden'
+ 404:
+ $ref: 'components.yaml#/components/responses/NotFound'
+ x-codegen-request-body-name: requestBody \ No newline at end of file
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java
index 8f4bdb716..d74e9b1cf 100644..100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java
@@ -102,7 +102,8 @@ public class AdminRestController implements CpsAdminApi {
@Override
public ResponseEntity<Object> getAnchor(final String dataspaceName, final String anchorName) {
- return null;
+ final Anchor anchor = cpsAdminService.getAnchor(dataspaceName, anchorName);
+ return new ResponseEntity<>(anchor, HttpStatus.OK);
}
@Override
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index 61f9399e7..9b31df563 100644
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -20,28 +20,27 @@
package org.onap.cps.rest.controller;
import javax.validation.Valid;
-import org.modelmapper.ModelMapper;
-import org.onap.cps.api.CpsAdminService;
+import javax.validation.constraints.NotNull;
+import org.onap.cps.api.CpsDataService;
import org.onap.cps.rest.api.CpsDataApi;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("${rest.api.cps-base-path}")
public class DataRestController implements CpsDataApi {
@Autowired
- private CpsAdminService cpsAdminService;
-
- @Autowired
- private ModelMapper modelMapper;
+ private CpsDataService cpsDataService;
@Override
- public ResponseEntity<String> createNode(@Valid final MultipartFile multipartFile, final String dataspaceName) {
- return null;
+ public ResponseEntity<String> createNode(@Valid final String jsonData, @NotNull final String dataspaceName,
+ @NotNull @Valid final String anchorName) {
+ cpsDataService.saveData(dataspaceName, anchorName, jsonData);
+ return new ResponseEntity<>(HttpStatus.CREATED);
}
@Override
@@ -53,4 +52,5 @@ public class DataRestController implements CpsDataApi {
public ResponseEntity<Object> getNodeByDataspaceAndAnchor(final String dataspaceName, final String anchorName) {
return null;
}
+
}
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy
index 88adf10ef..926021e81 100644..100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy
@@ -20,8 +20,15 @@
package org.onap.cps.rest.controller
+import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+
import org.modelmapper.ModelMapper
import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.spi.exceptions.DataspaceAlreadyDefinedException
import org.onap.cps.spi.exceptions.SchemaSetInUseException
@@ -40,12 +47,6 @@ import org.springframework.util.MultiValueMap
import spock.lang.Specification
import spock.lang.Unroll
-import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
-
@WebMvcTest
class AdminRestControllerSpec extends Specification {
@@ -56,6 +57,9 @@ class AdminRestControllerSpec extends Specification {
CpsAdminService mockCpsAdminService = Mock()
@SpringBean
+ CpsDataService mockCpsDataService = Mock()
+
+ @SpringBean
ModelMapper modelMapper = Mock()
@Autowired
@@ -64,29 +68,33 @@ class AdminRestControllerSpec extends Specification {
@Value('${rest.api.cps-base-path}')
def basePath
- def anchorsEndpoint = '/v1/dataspaces/my_dataspace/anchors'
- def schemaSetsEndpoint = '/v1/dataspaces/test-dataspace/schema-sets'
- def schemaSetEndpoint = schemaSetsEndpoint + '/my_schema_set'
-
+ def dataspaceName = 'my_dataspace'
def anchor = new Anchor(name: 'my_anchor')
def anchorList = [anchor]
+ def anchorName = 'my_anchor'
+ def schemaSetName = 'my_schema_set'
- def 'Create new dataspace'() {
- when:
- def response = performCreateDataspaceRequest("new-dataspace")
- then: 'Service method is invoked with expected parameters'
- 1 * mockCpsAdminService.createDataspace("new-dataspace")
- and: 'Dataspace is create successfully'
+ def 'Create new dataspace.'() {
+ given: 'an endpoint'
+ def createDataspaceEndpoint = "$basePath/v1/dataspaces";
+ when: 'post is invoked'
+ def response = mvc.perform(
+ post(createDataspaceEndpoint).param('dataspace-name', dataspaceName)).andReturn().response
+ then: 'service method is invoked with expected parameters'
+ 1 * mockCpsAdminService.createDataspace(dataspaceName)
+ and: 'dataspace is create successfully'
response.status == HttpStatus.CREATED.value()
}
- def 'Create dataspace over existing with same name'() {
- given:
+ def 'Create dataspace over existing with same name.'() {
+ given: 'an endpoint'
+ def createDataspaceEndpoint = "$basePath/v1/dataspaces";
+ and: 'the service method throws an exception indicating the dataspace is already defined'
def thrownException = new DataspaceAlreadyDefinedException("", new RuntimeException())
- mockCpsAdminService.createDataspace("existing-dataspace") >> { throw thrownException }
- when:
- def response = performCreateDataspaceRequest("existing-dataspace")
- then: 'Dataspace creation fails'
+ mockCpsAdminService.createDataspace(dataspaceName) >> { throw thrownException }
+ when: 'post is invoked'
+ def response = mvc.perform(post(createDataspaceEndpoint).param('dataspace-name', dataspaceName)).andReturn().response
+ then: 'dataspace creation fails'
response.status == HttpStatus.BAD_REQUEST.value()
}
@@ -94,10 +102,13 @@ class AdminRestControllerSpec extends Specification {
def yangResourceMapCapture
given: 'single yang file'
def multipartFile = createMultipartFile("filename.yang", "content")
+ and: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets"
when: 'file uploaded with schema set create request'
- def response = performCreateSchemaSetRequest(multipartFile)
+ def response = mvc.perform(multipart(schemaSetEndpoint)
+ .file(multipartFile).param('schema-set-name', schemaSetName)).andReturn().response
then: 'associated service method is invoked with expected parameters'
- 1 * mockCpsModuleService.createSchemaSet('test-dataspace', 'test-schema-set', _) >>
+ 1 * mockCpsModuleService.createSchemaSet(dataspaceName, schemaSetName, _) >>
{ args -> yangResourceMapCapture = args[2] }
yangResourceMapCapture['filename.yang'] == 'content'
and: 'response code indicates success'
@@ -108,10 +119,13 @@ class AdminRestControllerSpec extends Specification {
def yangResourceMapCapture
given: 'zip archive with multiple .yang files inside'
def multipartFile = createZipMultipartFileFromResource("/yang-files-set.zip")
+ and: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets"
when: 'file uploaded with schema set create request'
- def response = performCreateSchemaSetRequest(multipartFile)
+ def response = mvc.perform(multipart(schemaSetEndpoint)
+ .file(multipartFile).param('schema-set-name', schemaSetName)).andReturn().response
then: 'associated service method is invoked with expected parameters'
- 1 * mockCpsModuleService.createSchemaSet('test-dataspace', 'test-schema-set', _) >>
+ 1 * mockCpsModuleService.createSchemaSet(dataspaceName, schemaSetName, _) >>
{ args -> yangResourceMapCapture = args[2] }
yangResourceMapCapture['assembly.yang'] == "fake assembly content 1\n"
yangResourceMapCapture['component.yang'] == "fake component content 1\n"
@@ -121,8 +135,11 @@ class AdminRestControllerSpec extends Specification {
@Unroll
def 'Create schema set from zip archive having #caseDescriptor.'() {
+ given: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets"
when: 'zip archive having #caseDescriptor is uploaded with create schema set request'
- def response = performCreateSchemaSetRequest(multipartFile)
+ def response = mvc.perform(multipart(schemaSetEndpoint)
+ .file(multipartFile).param('schema-set-name', schemaSetName)).andReturn().response
then: 'create schema set rejected'
response.status == HttpStatus.BAD_REQUEST.value()
where: 'following cases are tested'
@@ -134,16 +151,23 @@ class AdminRestControllerSpec extends Specification {
def 'Create schema set from file with unsupported filename extension.'() {
given: 'file with unsupported filename extension (.doc)'
def multipartFile = createMultipartFile("filename.doc", "content")
+ and: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets"
when: 'file uploaded with schema set create request'
- def response = performCreateSchemaSetRequest(multipartFile)
+ def response = mvc.perform(multipart(schemaSetEndpoint)
+ .file(multipartFile).param('schema-set-name', schemaSetName)).andReturn().response
then: 'create schema set rejected'
response.status == HttpStatus.BAD_REQUEST.value()
}
@Unroll
def 'Create schema set from #fileType file with IOException occurrence on processing.'() {
+ given: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets"
when: 'file uploaded with schema set create request'
- def response = performCreateSchemaSetRequest(createMultipartFileForIOException(fileType))
+ def multipartFile = createMultipartFileForIOException(fileType)
+ def response = mvc.perform(multipart(schemaSetEndpoint)
+ .file(multipartFile).param('schema-set-name', schemaSetName)).andReturn().response
then: 'the error response returned indicating internal server error occurrence'
response.status == HttpStatus.INTERNAL_SERVER_ERROR.value()
where: 'following file types are used'
@@ -151,29 +175,84 @@ class AdminRestControllerSpec extends Specification {
}
def 'Delete schema set.'() {
+ given: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName"
when: 'delete schema set endpoint is invoked'
- def response = performDeleteRequest(schemaSetEndpoint)
+ def response = mvc.perform(delete(schemaSetEndpoint)).andReturn().response
then: 'associated service method is invoked with expected parameters'
- 1 * mockCpsModuleService.deleteSchemaSet('test-dataspace', 'my_schema_set', CASCADE_DELETE_PROHIBITED)
+ 1 * mockCpsModuleService.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED)
and: 'response code indicates success'
response.status == HttpStatus.NO_CONTENT.value()
}
def 'Delete schema set which is in use.'() {
- given: 'the service method throws an exception indicating the schema set is in use'
- def thrownException = new SchemaSetInUseException('test-dataspace', 'my_schema_set')
- mockCpsModuleService.deleteSchemaSet('test-dataspace', 'my_schema_set', CASCADE_DELETE_PROHIBITED) >>
+ given: 'service method throws an exception indicating the schema set is in use'
+ def thrownException = new SchemaSetInUseException(dataspaceName, schemaSetName)
+ mockCpsModuleService.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED) >>
{ throw thrownException }
+ and: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName"
when: 'delete schema set endpoint is invoked'
- def response = performDeleteRequest(schemaSetEndpoint)
+ def response = mvc.perform(delete(schemaSetEndpoint)).andReturn().response
then: 'schema set deletion fails with conflict response code'
response.status == HttpStatus.CONFLICT.value()
}
- def performCreateDataspaceRequest(String dataspaceName) {
- return mvc.perform(
- post("$basePath/v1/dataspaces").param('dataspace-name', dataspaceName)
- ).andReturn().response
+ def 'Get existing schema set.'() {
+ given: 'service method returns a new schema set'
+ mockCpsModuleService.getSchemaSet(dataspaceName, schemaSetName) >>
+ new SchemaSet(name: schemaSetName, dataspaceName: dataspaceName)
+ and: 'an endpoint'
+ def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName"
+ when: 'get schema set API is invoked'
+ def response = mvc.perform(get(schemaSetEndpoint)).andReturn().response
+ then: 'the correct schema set is returned'
+ response.status == HttpStatus.OK.value()
+ response.getContentAsString().contains(schemaSetName)
+ }
+
+ def 'Create Anchor.'() {
+ given: 'request parameters'
+ def requestParams = new LinkedMultiValueMap<>()
+ requestParams.add('schema-set-name', schemaSetName)
+ requestParams.add('anchor-name', anchorName)
+ and: 'an endpoint'
+ def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors"
+ when: 'post is invoked'
+ def response = mvc.perform(post(anchorEndpoint).contentType(MediaType.APPLICATION_JSON)
+ .params(requestParams as MultiValueMap)).andReturn().response
+ then: 'anchor is created successfully'
+ 1 * mockCpsAdminService.createAnchor(dataspaceName, schemaSetName, anchorName)
+ response.status == HttpStatus.CREATED.value()
+ response.getContentAsString().contains(anchorName)
+ }
+
+ def 'Get existing anchor.'() {
+ given: 'service method returns a list of anchors'
+ mockCpsAdminService.getAnchors(dataspaceName) >> anchorList
+ and: 'an endpoint'
+ def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors"
+ when: 'get all anchors API is invoked'
+ def response = mvc.perform(get(anchorEndpoint)).andReturn().response
+ then: 'the correct anchor is returned'
+ response.status == HttpStatus.OK.value()
+ response.getContentAsString().contains(anchorName)
+ }
+
+ def 'Get existing anchor by dataspace and anchor name.'() {
+ given: 'service method returns an anchor'
+ mockCpsAdminService.getAnchor(dataspaceName,anchorName) >> new Anchor(name: anchorName, dataspaceName: dataspaceName, schemaSetName:schemaSetName)
+ and: 'an endpoint'
+ def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName"
+ when: 'get anchor API is invoked'
+ def response = mvc.perform(get(anchorEndpoint))
+ .andReturn().response
+ def responseContent = response.getContentAsString()
+ then: 'the correct anchor is returned'
+ response.status == HttpStatus.OK.value()
+ responseContent.contains(anchorName)
+ responseContent.contains(dataspaceName)
+ responseContent.contains(schemaSetName)
}
def createMultipartFile(filename, content) {
@@ -192,51 +271,4 @@ class AdminRestControllerSpec extends Specification {
multipartFile.getInputStream() >> { throw new IOException() }
return multipartFile
}
-
- def performCreateSchemaSetRequest(multipartFile) {
- return mvc.perform(
- multipart("$basePath$schemaSetsEndpoint")
- .file(multipartFile)
- .param('schema-set-name', 'test-schema-set')
- ).andReturn().response
- }
-
- def performDeleteRequest(String deleteEndpoint) {
- return mvc.perform(delete("$basePath$deleteEndpoint")).andReturn().response
- }
-
- def 'Get existing schema set'() {
- given:
- mockCpsModuleService.getSchemaSet('test-dataspace', 'my_schema_set') >>
- new SchemaSet(name: 'my_schema_set', dataspaceName: 'test-dataspace')
- when: 'get schema set API is invoked'
- def response = mvc.perform(get("$basePath$schemaSetEndpoint")).andReturn().response
- then: 'the correct schema set is returned'
- response.status == HttpStatus.OK.value()
- response.getContentAsString().contains('my_schema_set')
- }
-
- def 'Create Anchor'() {
- given:
- def requestParams = new LinkedMultiValueMap<>()
- requestParams.add('schema-set-name', 'my_schema-set')
- requestParams.add('anchor-name', 'my_anchor')
- when: 'post is invoked'
- def response = mvc.perform(post("$basePath$anchorsEndpoint").contentType(MediaType.APPLICATION_JSON)
- .params(requestParams as MultiValueMap)).andReturn().response
- then: 'Anchor is created successfully'
- 1 * mockCpsAdminService.createAnchor('my_dataspace', 'my_schema-set', 'my_anchor')
- response.status == HttpStatus.CREATED.value()
- response.getContentAsString().contains('my_anchor')
- }
-
- def 'Get existing anchor'() {
- given:
- mockCpsAdminService.getAnchors('my_dataspace') >> anchorList
- when: 'get all anchors API is invoked'
- def response = mvc.perform(get("$basePath$anchorsEndpoint")).andReturn().response
- then: 'the correct anchor is returned'
- response.status == HttpStatus.OK.value()
- response.getContentAsString().contains('my_anchor')
- }
}
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
new file mode 100644
index 000000000..bed3ba2c9
--- /dev/null
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -0,0 +1,72 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.rest.controller
+
+import org.modelmapper.ModelMapper
+import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsModuleService
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.test.web.servlet.MockMvc
+import spock.lang.Specification
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+
+@WebMvcTest
+class DataRestControllerSpec extends Specification {
+
+ @SpringBean
+ CpsDataService mockCpsDataService = Mock()
+
+ @SpringBean
+ CpsModuleService mockCpsModuleService = Mock()
+
+ @SpringBean
+ CpsAdminService mockCpsAdminService = Mock()
+
+ @SpringBean
+ ModelMapper modelMapper = Mock()
+
+ @Autowired
+ MockMvc mvc
+
+ @Value('${rest.api.base-path}')
+ def basePath
+
+ def dataspaceName = 'my_dataspace'
+ def anchorName = 'my_anchor'
+
+ def 'Create a node.'() {
+ given:'an endpoint'
+ def nodeEndpoint ="$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName/nodes"
+ def json = 'some json (this is not validated)'
+ when: 'post is invoked'
+ def response = mvc.perform(post(nodeEndpoint).contentType(MediaType.APPLICATION_JSON).content(json))
+ .andReturn().response
+ then: 'the java API is called with the correct parameters'
+ 1 * mockCpsDataService.saveData(dataspaceName, anchorName, json)
+ response.status == HttpStatus.CREATED.value()
+ }
+} \ No newline at end of file
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 45f6102a2..8b02d73e8 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
@@ -22,6 +22,7 @@ package org.onap.cps.rest.exceptions
import groovy.json.JsonSlurper
import org.modelmapper.ModelMapper
import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.spi.exceptions.AnchorAlreadyDefinedException
import org.onap.cps.spi.exceptions.CpsException
@@ -56,6 +57,9 @@ class CpsRestExceptionHandlerSpec extends Specification {
CpsModuleService mockCpsModuleService = Mock()
@SpringBean
+ CpsDataService mockCpsDataService = Mock()
+
+ @SpringBean
ModelMapper modelMapper = Mock()
@Autowired
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index ebeeb9a82..a8f49655a 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -19,9 +19,20 @@
package org.onap.cps.api;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.onap.cps.spi.exceptions.DataValidationException;
+
/*
* Datastore interface for handling CPS data.
*/
public interface CpsDataService {
-
+ /**
+ * Persists data for the given anchor and dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param jsonData json data
+ * @throws DataValidationException when json data is invalid
+ */
+ void saveData(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull String jsonData);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
new file mode 100644
index 000000000..2a1e18b6d
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.api.impl;
+
+import org.onap.cps.api.CpsAdminService;
+import org.onap.cps.api.CpsDataService;
+import org.onap.cps.api.CpsModuleService;
+import org.onap.cps.spi.CpsDataPersistenceService;
+import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.DataNode;
+import org.onap.cps.spi.model.DataNodeBuilder;
+import org.onap.cps.utils.YangUtils;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CpsDataServiceImpl implements CpsDataService {
+
+ @Autowired
+ private CpsDataPersistenceService cpsDataPersistenceService;
+
+ @Autowired
+ private CpsAdminService cpsAdminService;
+
+ @Autowired
+ private CpsModuleService cpsModuleService;
+
+ @Autowired
+ private YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache;
+
+ @Override
+ public void saveData(final String dataspaceName, final String anchorName, final String jsonData) {
+ final Anchor anchor = cpsAdminService.getAnchor(dataspaceName, anchorName);
+ final SchemaContext schemaContext = getSchemaContext(dataspaceName, anchor.getSchemaSetName());
+ final NormalizedNode normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext);
+ final DataNode dataNode = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode).build();
+ cpsDataPersistenceService.storeDataNode(dataspaceName, anchor.getName(), dataNode);
+ }
+
+ private SchemaContext getSchemaContext(final String dataspaceName, final String schemaSetName) {
+ return yangTextSchemaSourceSetCache.get(dataspaceName, schemaSetName).getSchemaContext();
+ }
+} \ No newline at end of file
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 427ddd6c6..990b7bb93 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -40,9 +40,9 @@ public class CpsModuleServiceImpl implements CpsModuleService {
@Override
public void createSchemaSet(final String dataspaceName, final String schemaSetName,
- final Map<String, String> yangResourcesNameToContentMap) {
+ final Map<String, String> yangResourcesNameToContentMap) {
final YangTextSchemaSourceSet yangTextSchemaSourceSet
- = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap);
+ = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap);
cpsModulePersistenceService.storeSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap);
yangTextSchemaSourceSetCache.updateCache(dataspaceName, schemaSetName, yangTextSchemaSourceSet);
}
@@ -50,9 +50,9 @@ public class CpsModuleServiceImpl implements CpsModuleService {
@Override
public SchemaSet getSchemaSet(final String dataspaceName, final String schemaSetName) {
final YangTextSchemaSourceSet yangTextSchemaSourceSet = yangTextSchemaSourceSetCache
- .get(dataspaceName, schemaSetName);
+ .get(dataspaceName, schemaSetName);
return SchemaSet.builder().name(schemaSetName).dataspaceName(dataspaceName)
- .moduleReferences(yangTextSchemaSourceSet.getModuleReferences()).build();
+ .moduleReferences(yangTextSchemaSourceSet.getModuleReferences()).build();
}
@Override
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java b/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java
index 1244d54af..1ba94328d 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java
@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.spi.exceptions.DataValidationException;
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.stream.NormalizedNodeStreamWriter;
@@ -52,17 +53,21 @@ public class YangUtils {
* @param schemaContext the SchemaContext for the given data
* @return the NormalizedNode representing the json data
*/
- public static NormalizedNode parseJsonData(final String jsonData, final SchemaContext schemaContext)
- throws IOException {
+ public static NormalizedNode parseJsonData(final String jsonData, final SchemaContext schemaContext) {
final JSONCodecFactory jsonCodecFactory = JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02
.getShared(schemaContext);
final NormalizedNodeResult normalizedNodeResult = new NormalizedNodeResult();
final NormalizedNodeStreamWriter normalizedNodeStreamWriter = ImmutableNormalizedNodeStreamWriter
.from(normalizedNodeResult);
- try (final JsonParserStream jsonParserStream = JsonParserStream
- .create(normalizedNodeStreamWriter, jsonCodecFactory)) {
- final JsonReader jsonReader = new JsonReader(new StringReader(jsonData));
- jsonParserStream.parse(jsonReader);
+ try {
+ try (final JsonParserStream jsonParserStream = JsonParserStream
+ .create(normalizedNodeStreamWriter, jsonCodecFactory)) {
+ final JsonReader jsonReader = new JsonReader(new StringReader(jsonData));
+ jsonParserStream.parse(jsonReader);
+ }
+ } catch (final IOException e) {
+ throw new DataValidationException("Failed to parse json data.", String
+ .format("Exception occurred on parsing string %s.", jsonData), e);
}
return normalizedNodeResult.getResult();
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
new file mode 100644
index 000000000..5874e27ec
--- /dev/null
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.api.impl
+
+import org.onap.cps.TestUtils
+import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsModuleService
+import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.model.Anchor
+import org.onap.cps.yang.YangTextSchemaSourceSet
+import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
+import spock.lang.Specification
+
+class CpsDataServiceImplSpec extends Specification {
+ def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
+ def mockCpsAdminService = Mock(CpsAdminService)
+ def mockCpsModuleService = Mock(CpsModuleService)
+ def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
+
+ def objectUnderTest = new CpsDataServiceImpl()
+
+ def setup() {
+ objectUnderTest.cpsDataPersistenceService = mockCpsDataPersistenceService;
+ objectUnderTest.cpsAdminService = mockCpsAdminService;
+ objectUnderTest.cpsModuleService = mockCpsModuleService;
+ objectUnderTest.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache;
+ }
+
+ def dataspaceName = 'some dataspace'
+ def anchorName = 'some anchor'
+ def schemaSetName = 'some schema set'
+
+ def 'Saving json data.'() {
+ given: 'that the admin service will return an anchor'
+ def anchor = new Anchor()
+ anchor.name = anchorName
+ anchor.schemaSetName = schemaSetName
+ mockCpsAdminService.getAnchor(dataspaceName, anchorName) >> anchor
+ and: 'the schema source set cache returns a schema source set'
+ def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet)
+ mockYangTextSchemaSourceSetCache.get(dataspaceName,schemaSetName) >> mockYangTextSchemaSourceSet
+ and: 'the schema source sets returns the test-tree schema context'
+ def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang')
+ def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext()
+ mockYangTextSchemaSourceSet.getSchemaContext() >> schemaContext
+ when: 'save data method is invoked with test-tree json data'
+ def jsonData = org.onap.cps.TestUtils.getResourceFileContent('test-tree.json')
+ objectUnderTest.saveData(dataspaceName, anchorName, jsonData)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.storeDataNode(dataspaceName, anchorName,
+ { dataNode -> dataNode.xpath == '/test-tree' })
+ }
+} \ No newline at end of file
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index 5f2168aeb..261d17493 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -22,6 +22,7 @@ package org.onap.cps.api.impl
import org.onap.cps.TestUtils
import org.onap.cps.api.CpsAdminService
+import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.CpsModulePersistenceService
import org.onap.cps.spi.exceptions.ModelValidationException
import org.onap.cps.spi.model.ModuleReference
@@ -46,6 +47,8 @@ class CpsModuleServiceImplSpec extends Specification {
CpsModulePersistenceService mockModuleStoreService = Mock()
@SpringBean
CpsAdminService mockCpsAdminService = Mock()
+ @SpringBean
+ CpsDataPersistenceService mockDataPersistenceService = Mock()
@Autowired
CpsModuleServiceImpl objectUnderTest = new CpsModuleServiceImpl()
@SpringBean
@@ -93,14 +96,14 @@ class CpsModuleServiceImplSpec extends Specification {
}
@Unroll
- def 'Delete set by name and dataspace with #cascadeDeleteOption.'(){
+ def 'Delete set by name and dataspace with #cascadeDeleteOption.'() {
when: 'schema set deletion is requested'
objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetname, cascadeDeleteOption)
then: 'persistence service method is invoked with same parameters'
mockModuleStoreService.deleteSchemaSet(dataspaceName, schemaSetname, cascadeDeleteOption)
where: 'following parameters are used'
- dataspaceName | schemaSetname | cascadeDeleteOption
- 'dataspace-1' | 'schemas-set-1' | CASCADE_DELETE_ALLOWED
- 'dataspace-2' | 'schemas-set-2' | CASCADE_DELETE_PROHIBITED
+ dataspaceName | schemaSetname | cascadeDeleteOption
+ 'dataspace-1' | 'schemas-set-1' | CASCADE_DELETE_ALLOWED
+ 'dataspace-2' | 'schemas-set-2' | CASCADE_DELETE_PROHIBITED
}
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
index d6751bb4e..904e8263b 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
@@ -21,25 +21,69 @@
package org.onap.cps.api.impl
import org.onap.cps.TestUtils
+import org.onap.cps.api.CpsAdminService
+import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.CpsModulePersistenceService
+import org.onap.cps.spi.model.Anchor
+import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import spock.lang.Specification
class E2ENetworkSliceSpec extends Specification {
def mockModuleStoreService = Mock(CpsModulePersistenceService)
+ def mockDataStoreService = Mock(CpsDataPersistenceService)
+ def mockCpsAdminService = Mock(CpsAdminService)
+ def cpsModuleServiceImpl = new CpsModuleServiceImpl()
+ def cpsDataServiceImple = new CpsDataServiceImpl()
def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
- def objectUnderTest = new CpsModuleServiceImpl()
+
+ def dataspaceName = 'someDataspace'
+ def anchorName = 'someAnchor'
+ def schemaSetName = 'someSchemaSet'
def setup() {
- objectUnderTest.cpsModulePersistenceService = mockModuleStoreService
- objectUnderTest.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
+ cpsDataServiceImple.cpsDataPersistenceService = mockDataStoreService
+ cpsDataServiceImple.cpsAdminService = mockCpsAdminService
+ cpsDataServiceImple.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
+ cpsModuleServiceImpl.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
+ cpsModuleServiceImpl.cpsModulePersistenceService = mockModuleStoreService
}
def 'E2E model can be parsed by CPS.'() {
given: 'Valid yang resource as name-to-content map'
def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('e2e/basic/ietf-inet-types.yang','e2e/basic/ietf-yang-types.yang','e2e/basic/ran-network2020-08-06.yang')
when: 'Create schema set method is invoked'
- objectUnderTest.createSchemaSet('someDataspace', 'someSchemaSet', yangResourcesNameToContentMap)
+ cpsModuleServiceImpl.createSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap)
+ then: 'Parameters are validated and processing is delegated to persistence service'
+ 1 * mockModuleStoreService.storeSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap)
+ }
+
+ def 'E2E Coverage Area-Tracking Area & TA-Cell mapping model can be parsed by CPS.'() {
+ given: 'Valid yang resource as name-to-content map'
+ def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap(
+ 'e2e/basic/cps-cavsta-onap-internal2021-01-28.yang')
+ when: 'Create schema set method is invoked'
+ cpsModuleServiceImpl.createSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap)
+ then: 'Parameters are validated and processing is delegated to persistence service'
+ 1 * mockModuleStoreService.storeSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap)
+ }
+
+ def 'E2E Coverage Area-Tracking Area & TA-Cell mapping data can be parsed by CPS.'() {
+ given: 'Valid yang resource as name-to-content map'
+ def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap(
+ 'e2e/basic/cps-cavsta-onap-internal2021-01-28.yang')
+ def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap).getSchemaContext()
+ and : 'a valid json is provided for the model'
+ def jsonData = TestUtils.getResourceFileContent('e2e/basic/Data.txt')
+ and : 'all the further dependencies are mocked '
+ mockCpsAdminService.getAnchor(dataspaceName, anchorName) >>
+ new Anchor().builder().name(anchorName).schemaSetName(schemaSetName).build()
+ mockYangTextSchemaSourceSetCache.get(dataspaceName, schemaSetName) >>
+ YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap)
+ mockModuleStoreService.getYangSchemaResources(dataspaceName, schemaSetName) >> schemaContext
+ when: 'saveData method is invoked'
+ cpsDataServiceImple.saveData(dataspaceName, anchorName, jsonData)
then: 'Parameters are validated and processing is delegated to persistence service'
- 1 * mockModuleStoreService.storeSchemaSet('someDataspace', 'someSchemaSet', yangResourcesNameToContentMap)
+ 1 * mockDataStoreService.storeDataNode(dataspaceName, anchorName,
+ {dataNode -> dataNode.xpath == '/ran-coverage-area' && dataNode.childDataNodes.size() == 4})
}
}
diff --git a/cps-service/src/test/resources/e2e/basic/Data.txt b/cps-service/src/test/resources/e2e/basic/Data.txt
new file mode 100644
index 000000000..c10c6d9c7
--- /dev/null
+++ b/cps-service/src/test/resources/e2e/basic/Data.txt
@@ -0,0 +1,42 @@
+{
+"ran-coverage-area":{
+ "pLMNIdList": [
+ {
+ "mcc": "310",
+ "mnc": "410"
+ },
+ {
+ "mcc": "2310",
+ "mnc": "2410"
+ }
+ ],
+ "coverage-area": [
+ {
+ "coverageArea": "Washington",
+ "coverageAreaTAList": [
+ {
+ "nRTAC": 234,
+ "taCellsList": [
+ {
+ "cellLocalId": 15709
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "coverageArea": "Dublin",
+ "coverageAreaTAList": [
+ {
+ "nRTAC": 2234,
+ "taCellsList": [
+ {
+ "cellLocalId": 15809
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/cps-service/src/test/resources/e2e/basic/cps-cavsta-onap-internal2021-01-28.yang b/cps-service/src/test/resources/e2e/basic/cps-cavsta-onap-internal2021-01-28.yang
new file mode 100644
index 000000000..2a8a92579
--- /dev/null
+++ b/cps-service/src/test/resources/e2e/basic/cps-cavsta-onap-internal2021-01-28.yang
@@ -0,0 +1,153 @@
+module cps-cavsta-onap-internal {
+ yang-version 1.1;
+ namespace "org:onap:ccsdk:features:sdnr:northbound:cps-cavsta-onap-internal";
+ prefix onap-cavsta;
+
+ organization
+ "Open Network Automation Platform - ONAP
+ <https://www.onap.org>";
+ contact
+ "Editors:
+ Àhila Pandaram
+ <mailto:ahila.pandaram@wipro.com>
+
+ Swaminathan Seetharaman
+ <mailto:swaminathan.seetharaman@wipro.com>";
+ description
+ "This module contains YANG definitions for the relationship among coverage area,
+ tracking area list and cells under each tracking area.
+ This relationship is used for internal purpose of ONAP to populate the details.
+
+ Copyright (C) 2020-2021 Wipro Limited.
+
+ Licensed under the Apache License, Version 2.0 (the 'License')
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an 'AS IS' BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.";
+
+ revision 2021-01-28 {
+ description
+ "RAN Network YANG Model for ONAP/O-RAN POC";
+ reference
+ "https://wiki.onap.org/display/DW/E2E+Network+Slicing+Use+Case+in+R7+Guilin";
+ }
+
+ typedef Tac {
+ type int64 {
+ range "0..16777215";
+ }
+ description
+ "Tracking Area Code";
+ reference
+ "TS 23.003 clause 19.4.2.3";
+ }
+
+
+ typedef Mcc {
+ type string;
+ description
+ "The mobile country code consists of three decimal digits,
+ The first digit of the mobile country code identifies the geographic
+ region (the digits 1 and 8 are not used):";
+ reference
+ "3GPP TS 23.003 subclause 2.2 and 12.1";
+ }
+
+ typedef Mnc {
+ type string;
+ description
+ "The mobile network code consists of two or three
+ decimal digits (for example: MNC of 001 is not the same as MNC of 01)";
+ reference
+ "3GPP TS 23.003 subclause 2.2 and 12.1";
+ }
+
+
+ grouping trackingAreaGroup{
+ leaf nRTAC {
+ type Tac;
+ description "Identity of the common Tracking Area Code for the PLMNs
+ allowedValues:
+ a) It is the TAC or Extended-TAC.
+ b) A cell can only broadcast one TAC or Extended-TAC.
+ See TS 36.300, subclause 10.1.7 (PLMNID and TAC relation).
+ c) TAC is defined in subclause 19.4.2.3 of 3GPP TS 23.003 and
+ Extended-TAC is defined in subclause 9.3.1.29 of 3GPP TS 38.473.
+ d) For a 5G SA (Stand Alone), it has a non-null value.";
+ }
+ list taCellsList{
+ key cellLocalId;
+ leaf cellLocalId {
+ description "Identifies an NR cell of a gNB. Together with corresponding
+ gNB ID it forms the NR Cell Identifier (NCI).";
+ mandatory true;
+ type int32 { range "0..16383"; }
+ }
+ }
+ }
+
+ grouping PLMNId {
+ description
+ "It specifies the PLMN identifier to be used as part of the global RAN node identity";
+ reference
+ "TS 23.658";
+ leaf mcc {
+ type Mcc;
+ mandatory true;
+ description
+ "The mobile country code consists of three decimal digits,
+ The first digit of the mobile country code identifies the geographic
+ region (the digits 1 and 8 are not used)";
+ }
+ leaf mnc {
+ type Mnc;
+ mandatory true;
+ description
+ "The mobile network code consists of two or three
+ decimal digits (for example: MNC of 001 is not the same as MNC of 01)";
+ }
+ }
+
+
+ grouping coverageAreaGroup{
+ leaf coverageArea{
+ description "An attribute specifies the coverage area of the network slice,
+ i.e. the geographic region where a 3GPP communication service is accessible,
+ see Table 7.1-1 of TS 22.261 [28]) and NG.116 [50].";
+ type string;
+ }
+
+ list coverageAreaTAList{
+ uses trackingAreaGroup;
+ key "nRTAC";
+ description "This list contains the tracking area list for the coverageArea";
+ }
+ }
+
+ container ran-coverage-area{
+
+ list pLMNIdList {
+ description "List of at most six entries of PLMN Identifiers, but at least
+ one (the primary PLMN Id).
+ The PLMN Identifier is composed of a Mobile Country Code (MCC) and a
+ Mobile Network Code (MNC).";
+ key "mcc mnc";
+ uses PLMNId;
+ }
+
+
+ list coverage-area{
+ uses coverageAreaGroup;
+ key "coverageArea";
+ description "This list contains the list of coverage area of a PLMNID";
+ }
+
+ }
+ }