<artifactId>cps-ncmp-rest</artifactId>
<properties>
- <minimum-coverage>0.99</minimum-coverage>
+ <minimum-coverage>1.00</minimum-coverage>
</properties>
<dependencies>
final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
- final MultiValueMap<String, Map<NcmpEventResponseCode, List<String>>>
- cmHandleIdsPerResponseCodesPerOperationId = new LinkedMultiValueMap<>();
+ final MultiValueMap<DmiDataOperation, Map<NcmpEventResponseCode, List<String>>>
+ cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> {
final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream()
.map(CmHandle::getId).collect(Collectors.toList());
if (throwable.getCause() instanceof HttpClientRequestException) {
- cmHandleIdsPerResponseCodesPerOperationId.add(dmiDataOperationRequestBody.getOperationId(),
+ cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
Map.of(NcmpEventResponseCode.UNABLE_TO_READ_RESOURCE_DATA, cmHandleIds));
} else {
- cmHandleIdsPerResponseCodesPerOperationId.add(dmiDataOperationRequestBody.getOperationId(),
+ cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
Map.of(NcmpEventResponseCode.DMI_SERVICE_NOT_RESPONDING, cmHandleIds));
}
});
ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId,
- cmHandleIdsPerResponseCodesPerOperationId);
+ cmHandleIdsPerResponseCodesPerOperation);
}
}
}
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.NcmpEventResponseCode;
import org.onap.cps.ncmp.api.impl.events.NcmpCloudEventBuilder;
+import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation;
import org.onap.cps.ncmp.events.async1_0_0.Data;
import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent;
import org.onap.cps.ncmp.events.async1_0_0.Response;
*
* @param clientTopic topic the client wants to use for responses
* @param requestId unique identifier per request
- * @param cmHandleIdsPerResponseCodesPerOperationId map of cm handles per operation response per response code
+ * @param cmHandleIdsPerResponseCodesPerOperation map of cm handles per operation response per response code
* @return Cloud Event
*/
public static CloudEvent createDataOperationEvent(final String clientTopic,
final String requestId,
- final MultiValueMap<String,
+ final MultiValueMap<DmiDataOperation,
Map<NcmpEventResponseCode, List<String>>>
- cmHandleIdsPerResponseCodesPerOperationId) {
+ cmHandleIdsPerResponseCodesPerOperation) {
final DataOperationEvent dataOperationEvent = new DataOperationEvent();
- final Data data = createPayloadFromDataOperationResponses(cmHandleIdsPerResponseCodesPerOperationId);
+ final Data data = createPayloadFromDataOperationResponses(cmHandleIdsPerResponseCodesPerOperation);
dataOperationEvent.setData(data);
final Map<String, String> extensions = createDataOperationExtensions(requestId, clientTopic);
return NcmpCloudEventBuilder.builder().type(DataOperationEvent.class.getName())
.event(dataOperationEvent).extensions(extensions).setCloudEvent().build();
}
- private static Data createPayloadFromDataOperationResponses(final MultiValueMap<String, Map<NcmpEventResponseCode,
- List<String>>> cmHandleIdsPerOperationIdPerResponseCode) {
+ private static Data createPayloadFromDataOperationResponses(final MultiValueMap<DmiDataOperation,
+ Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperation) {
final Data data = new Data();
final List<org.onap.cps.ncmp.events.async1_0_0.Response> responses = new ArrayList<>();
- cmHandleIdsPerOperationIdPerResponseCode.entrySet().forEach(cmHandleIdsPerOperationIdPerResponseCodeEntries ->
- cmHandleIdsPerOperationIdPerResponseCodeEntries.getValue().forEach(cmHandleIdsPerResponseCodeEntries ->
+ cmHandleIdsPerResponseCodesPerOperation.forEach((dmiDataOperation, cmHandleIdsPerResponseCodes) ->
+ cmHandleIdsPerResponseCodes.forEach(cmHandleIdsPerResponseCodeEntries ->
responses.addAll(createResponseFromDataOperationResponses(
- cmHandleIdsPerOperationIdPerResponseCodeEntries.getKey(),
- cmHandleIdsPerResponseCodeEntries)
- )));
+ dmiDataOperation, cmHandleIdsPerResponseCodeEntries))));
data.setResponses(responses);
return data;
}
private static List<Response> createResponseFromDataOperationResponses(
- final String operationId,
+ final DmiDataOperation dmiDataOperation,
final Map<NcmpEventResponseCode, List<String>> cmHandleIdsPerResponseCodeEntries) {
final List<org.onap.cps.ncmp.events.async1_0_0.Response> responses = new ArrayList<>();
- cmHandleIdsPerResponseCodeEntries.entrySet()
- .forEach(cmHandleIdsPerResponseCodeEntry -> {
- final Response response = new Response();
- response.setOperationId(operationId);
- response.setStatusCode(cmHandleIdsPerResponseCodeEntry.getKey().getStatusCode());
- response.setStatusMessage(cmHandleIdsPerResponseCodeEntry.getKey().getStatusMessage());
- response.setIds(cmHandleIdsPerResponseCodeEntry.getValue());
- responses.add(response);
- });
+ cmHandleIdsPerResponseCodeEntries.forEach((ncmpEventResponseCode, cmHandleIds) -> {
+ final Response response = new Response();
+ response.setOperationId(dmiDataOperation.getOperationId());
+ response.setStatusCode(ncmpEventResponseCode.getStatusCode());
+ response.setStatusMessage(ncmpEventResponseCode.getStatusMessage());
+ response.setIds(cmHandleIds);
+ response.setResourceIdentifier(dmiDataOperation.getResourceIdentifier());
+ response.setOptions(dmiDataOperation.getOptions());
+ responses.add(response);
+ });
return responses;
}
final Collection<YangModelCmHandle> yangModelCmHandles) {
final Map<String, List<DmiDataOperation>> dmiDataOperationsOutPerDmiServiceName = new HashMap<>();
- final MultiValueMap<String, Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperationId
- = new LinkedMultiValueMap<>();
+ final MultiValueMap<DmiDataOperation, Map<NcmpEventResponseCode,
+ List<String>>> cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
final Set<String> nonReadyCmHandleIdsLookup = filterAndGetNonReadyCmHandleIds(yangModelCmHandles);
final Map<String, Map<String, Map<String, String>>> dmiPropertiesPerCmHandleIdPerServiceName =
}
}
}
- populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperationId,
- dataOperationDefinitionIn.getOperationId(), NcmpEventResponseCode.CM_HANDLES_NOT_FOUND,
- nonExistingCmHandleIds);
- populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperationId,
- dataOperationDefinitionIn.getOperationId(), NcmpEventResponseCode.CM_HANDLES_NOT_READY,
- nonReadyCmHandleIds);
+ populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation,
+ DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn),
+ NcmpEventResponseCode.CM_HANDLES_NOT_FOUND, nonExistingCmHandleIds);
+ populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation,
+ DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn),
+ NcmpEventResponseCode.CM_HANDLES_NOT_READY, nonReadyCmHandleIds);
}
- if (!cmHandleIdsPerResponseCodesPerOperationId.isEmpty()) {
- publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleIdsPerResponseCodesPerOperationId);
+ if (!cmHandleIdsPerResponseCodesPerOperation.isEmpty()) {
+ publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleIdsPerResponseCodesPerOperation);
}
return dmiDataOperationsOutPerDmiServiceName;
}
*
* @param clientTopic client given topic
* @param requestId unique identifier per request
- * @param cmHandleIdsPerResponseCodesPerOperationId list of cm handle ids per operation id with response code
+ * @param cmHandleIdsPerResponseCodesPerOperation list of cm handle ids per operation with response code
*/
@Async
public static void publishErrorMessageToClientTopic(final String clientTopic,
final String requestId,
- final MultiValueMap<String,
+ final MultiValueMap<DmiDataOperation,
Map<NcmpEventResponseCode, List<String>>>
- cmHandleIdsPerResponseCodesPerOperationId) {
+ cmHandleIdsPerResponseCodesPerOperation) {
final CloudEvent dataOperationCloudEvent = DataOperationEventCreator.createDataOperationEvent(clientTopic,
- requestId, cmHandleIdsPerResponseCodesPerOperationId);
+ requestId, cmHandleIdsPerResponseCodesPerOperation);
final EventsPublisher<CloudEvent> eventsPublisher = CpsApplicationContext.getCpsBean(EventsPublisher.class);
eventsPublisher.publishCloudEvent(clientTopic, requestId, dataOperationCloudEvent);
}
!= CmHandleState.READY).map(YangModelCmHandle::getId).collect(Collectors.toSet());
}
- private static void populateCmHandleIdsPerOperationIdPerResponseCode(final MultiValueMap<String,
- Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperationId,
- final String operationId,
+ private static void populateCmHandleIdsPerOperationIdPerResponseCode(final MultiValueMap<DmiDataOperation,
+ Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperation,
+ final DmiDataOperation dmiDataOperation,
final NcmpEventResponseCode
ncmpEventResponseCode,
final List<String> cmHandleIds) {
if (!cmHandleIds.isEmpty()) {
- cmHandleIdsPerResponseCodesPerOperationId.add(operationId, Map.of(ncmpEventResponseCode, cmHandleIds));
+ cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperation, Map.of(ncmpEventResponseCode, cmHandleIds));
}
}
}
toTargetEvent(consumerRecordOut.value(), DataOperationEvent.class)
and: 'data operation response event response size is 3'
dataOperationResponseEvent.data.responses.size() == 3
- and: 'verify published response data as json string'
- jsonObjectMapper.asJsonString(dataOperationResponseEvent.data.responses)
- == '[{"operationId":"operational-14","ids":["unknown-cm-handle"],"statusCode":"100","statusMessage":"cm handle id(s) not found"},{"operationId":"operational-14","ids":["non-ready-cm handle"],"statusCode":"101","statusMessage":"cm handle(s) not ready"},{"operationId":"running-12","ids":["non-ready-cm handle"],"statusCode":"101","statusMessage":"cm handle(s) not ready"}]'
+ and: 'verify published data operation response as json string'
+ def dataOperationResponseEventJson = TestUtils.getResourceFileContent('dataOperationResponseEvent.json')
+ jsonObjectMapper.asJsonString(dataOperationResponseEvent.data.responses) == dataOperationResponseEventJson
}
static def getYangModelCmHandles() {
new YangModelCmHandle(id: 'ch3-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState),
new YangModelCmHandle(id: 'ch4-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState),
new YangModelCmHandle(id: 'ch7-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState),
- new YangModelCmHandle(id: 'non-ready-cm handle', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: advisedState)
+ new YangModelCmHandle(id: 'non-ready-cm-handle', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: advisedState)
]
}
}
"ch3-dmi2",
"unknown-cm-handle",
"ch6-dmi1",
- "non-ready-cm handle"
+ "non-ready-cm-handle"
]
},
{
"operation": "read",
"operationId": "running-12",
"datastore": "ncmp-datastore:passthrough-running",
+ "options": "some option",
+ "resourceIdentifier": "some resource identifier",
"targetIds": [
"ch1-dmi1",
"ch7-dmi2",
"ch2-dmi1",
- "non-ready-cm handle"
+ "non-ready-cm-handle"
]
},
{
"operationId": "operational-15",
"datastore": "ncmp-datastore:passthrough-operational",
"options": "some option",
+ "resourceIdentifier": "some resource identifier",
"targetIds": [
"ch4-dmi2",
"ch6-dmi1"
--- /dev/null
+[{"operationId":"operational-14","ids":["unknown-cm-handle"],"resourceIdentifier":"some resource identifier","options":"some option","statusCode":"100","statusMessage":"cm handle id(s) not found"},{"operationId":"operational-14","ids":["non-ready-cm-handle"],"resourceIdentifier":"some resource identifier","options":"some option","statusCode":"101","statusMessage":"cm handle(s) not ready"},{"operationId":"running-12","ids":["non-ready-cm-handle"],"resourceIdentifier":"some resource identifier","options":"some option","statusCode":"101","statusMessage":"cm handle(s) not ready"}]
\ No newline at end of file
.andReturn().response
then: 'the response contains the the datanode in json format'
assert response.status == HttpStatus.OK.value()
- assert Integer.valueOf(response.getHeaderValue("total-pages")) == expectedPageSize
+ 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 || expectedPageSize
+ scenario | pageIndex | pageSize | totalAnchors || expectedTotalPageSize
'1st page with all anchors' | 1 | 3 | 3 || 1
'1st page with less anchors' | 1 | 2 | 3 || 2
}
+
+ 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
+ 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'
+ 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:
+ scenario | parameterName
+ 'only page size' | 'pageSize'
+ 'only page index' | 'pageIndex'
+ }
}
anchorRepository.deleteAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
}
+ @Transactional
+ @Override
+ public void updateAnchorSchemaSet(final String dataspaceName,
+ final String anchorName,
+ final String schemaSetName) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
+ final SchemaSetEntity schemaSetEntity = schemaSetRepository
+ .getByDataspaceAndName(dataspaceEntity, schemaSetName);
+ anchorRepository.updateAnchorSchemaSetId(schemaSetEntity.getId(), anchorEntity.getId());
+ }
+
private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
deleteAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames.toArray(new String[0]));
}
+ @Modifying
+ @Query(value = "UPDATE anchor SET schema_set_id =:schemaSetId WHERE id = :anchorId ", nativeQuery = true)
+ void updateAnchorSchemaSetId(@Param("schemaSetId") int schemaSetId, @Param("anchorId") long anchorId);
+
}
final FragmentEntity fragmentEntity = new FragmentEntity();
fragmentEntity.setId(resultSet.getLong("id"));
fragmentEntity.setXpath(resultSet.getString("xpath"));
- fragmentEntity.setParentId(resultSet.getLong("parentId"));
+ fragmentEntity.setParentId(resultSet.getObject("parentId", Long.class));
fragmentEntity.setAttributes(resultSet.getString("attributes"));
fragmentEntity.setAnchor(anchorEntityPerId.get(resultSet.getLong("anchorId")));
fragmentEntity.setChildFragments(new HashSet<>());
* given module names
*/
Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames);
+
+ /**
+ * Update schema set of an anchor.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param schemaSetName schema set name
+ */
+ void updateAnchorSchemaSet(String dataspaceName, String anchorName, String schemaSetName);
}
final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames);
return anchors.stream().map(Anchor::getName).collect(Collectors.toList());
}
+
+ @Override
+ public void updateAnchorSchemaSet(final String dataspaceName,
+ final String anchorName,
+ final String schemaSetName) {
+ cpsAdminPersistenceService.updateAnchorSchemaSet(dataspaceName, anchorName, schemaSetName);
+ }
}
* @param anchorNames anchor names
*/
void deleteAnchors(String dataspaceName, Collection<String> anchorNames);
+
+ /**
+ * Delete anchors by name in given dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param schemaSetName schema set name
+ */
+ void updateAnchorSchemaSet(String dataspaceName, String anchorName, String schemaSetName);
}
and: 'the CpsValidator is called on the dataspaceName'
1 * mockCpsValidator.validateNameCharacters('someDataspace')
}
+
+ def 'Update anchor schema set.'() {
+ when: 'update anchor is invoked'
+ objectUnderTest.updateAnchorSchemaSet('someDataspace', 'someAnchor', 'someSchemaSetName')
+ then: 'associated persistence service method is invoked with correct parameter'
+ 1 * mockCpsAdminPersistenceService.updateAnchorSchemaSet('someDataspace', 'someAnchor', 'someSchemaSetName')
+ }
}
Bug Fixes
---------
3.3.6
+ - `CPS-1841 <https://jira.onap.org/browse/CPS-1841>`_ Update of top-level data node fails with exception
Features
--------
def dataspaceExists(dataspaceName) {
try {
cpsAdminService.getDataspace(dataspaceName)
- } catch (DataspaceNotFoundException e) {
+ } catch (DataspaceNotFoundException dataspaceNotFoundException) {
return false
}
return true
import org.onap.cps.api.CpsAdminService
import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.AnchorNotFoundException
import org.onap.cps.spi.exceptions.DataspaceInUseException
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
+import java.time.OffsetDateTime
class CpsAdminServiceIntegrationSpec extends CpsIntegrationSpecBase {
def thrown = null
try {
objectUnderTest.getDataspace('newDataspace')
- } catch(Exception e) {
- thrown = e
+ } catch(Exception exception) {
+ thrown = exception
}
assert thrown instanceof DataspaceNotFoundException
}
def thrown = null
try {
objectUnderTest.getAnchor(GENERAL_TEST_DATASPACE, 'newAnchor')
- } catch(Exception e) {
- thrown = e
+ } catch(Exception exception) {
+ thrown = exception
}
assert thrown instanceof AnchorNotFoundException
}
'just unknown module(s)' | GENERAL_TEST_DATASPACE
}
+ def 'Update anchor schema set.'() {
+ when: 'a new schema set with tree yang model is created'
+ def newTreeYangModelAsString = readResourceDataFile('tree/new-test-tree.yang')
+ cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, 'newTreeSchemaSet', [tree: newTreeYangModelAsString])
+ then: 'an anchor with new schema set is created'
+ objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, 'newTreeSchemaSet', 'anchor4')
+ and: 'the new tree datanode is saved'
+ def treeJsonData = readResourceDataFile('tree/new-test-tree.json')
+ cpsDataService.saveData(GENERAL_TEST_DATASPACE, 'anchor4', treeJsonData, OffsetDateTime.now())
+ and: 'saved tree data node can be retrieved by its normalized xpath'
+ def branchName = cpsDataService.getDataNodes(GENERAL_TEST_DATASPACE, 'anchor4', "/test-tree/branch", FetchDescendantsOption.DIRECT_CHILDREN_ONLY)[0].leaves['name']
+ assert branchName == 'left'
+ and: 'a another schema set with updated tree yang model is created'
+ def updatedTreeYangModelAsString = readResourceDataFile('tree/updated-test-tree.yang')
+ cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, 'anotherTreeSchemaSet', [tree: updatedTreeYangModelAsString])
+ and: 'anchor4 schema set is updated with another schema set successfully'
+ objectUnderTest.updateAnchorSchemaSet(GENERAL_TEST_DATASPACE, 'anchor4', 'anotherTreeSchemaSet')
+ when: 'updated tree data node with new leaves'
+ def updatedTreeJsonData = readResourceDataFile('tree/updated-test-tree.json')
+ cpsDataService.updateNodeLeaves(GENERAL_TEST_DATASPACE, "anchor4", "/test-tree/branch[@name='left']", updatedTreeJsonData, OffsetDateTime.now())
+ then: 'updated tree data node can be retrieved by its normalized xpath'
+ def birdsName = cpsDataService.getDataNodes(GENERAL_TEST_DATASPACE, 'anchor4',"/test-tree/branch[@name='left']/nest", FetchDescendantsOption.DIRECT_CHILDREN_ONLY)[0].leaves['birds']
+ assert birdsName as String == '[Raven, Night Owl, Crow]'
+ }
}
restoreBookstoreDataAnchor(1)
}
+ def 'Update bookstore top-level container data node.'() {
+ when: 'the bookstore top-level container is updated'
+ def json = '{ "bookstore": { "bookstore-name": "new bookstore" }}'
+ objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/', json, now)
+ then: 'bookstore name has been updated'
+ def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', DIRECT_CHILDREN_ONLY)
+ result.leaves.'bookstore-name'[0] == 'new bookstore'
+ cleanup:
+ restoreBookstoreDataAnchor(1)
+ }
+
def 'Update multiple data node leaves.'() {
given: 'Updated json for bookstore data'
def jsonData = "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda'}}"
--- /dev/null
+{
+ "test-tree": {
+ "branch": [
+ {
+ "name": "left",
+ "nest": {
+ "name": "small"
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
--- /dev/null
+module test-tree {
+ yang-version 1.1;
+
+ namespace "org:onap:cps:test:test-tree";
+ prefix tree;
+ revision "2020-02-02";
+
+ container test-tree {
+ list branch {
+ key "name";
+ leaf name {
+ type string;
+ }
+ container nest {
+ leaf name {
+ type string;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "nest": {
+ "name": "small",
+ "birds": [
+ "Night Owl",
+ "Raven",
+ "Crow"
+ ]
+ }
+}
\ No newline at end of file
--- /dev/null
+module test-tree {
+ yang-version 1.1;
+
+ namespace "org:onap:cps:test:test-tree";
+ prefix tree;
+
+ revision "2023-08-17" {
+ description
+ "added list of birds to nest";
+ }
+
+ revision "2020-09-15" {
+ description
+ "Sample Model";
+ }
+
+ container test-tree {
+ list branch {
+ key "name";
+ leaf name {
+ type string;
+ }
+ container nest {
+ leaf name {
+ type string;
+ }
+ leaf-list birds {
+ type string;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file