summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-ncmp-rest/pom.xml2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java42
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java36
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy8
-rw-r--r--cps-ncmp-service/src/test/resources/dataOperationRequest.json7
-rw-r--r--cps-ncmp-service/src/test/resources/dataOperationResponseEvent.json1
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy38
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java12
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java2
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/CpsAdminService.java9
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java7
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java9
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy7
-rwxr-xr-xdocs/release-notes.rst1
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy2
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy34
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy11
-rw-r--r--integration-test/src/test/resources/data/tree/new-test-tree.json12
-rw-r--r--integration-test/src/test/resources/data/tree/new-test-tree.yang21
-rw-r--r--integration-test/src/test/resources/data/tree/updated-test-tree.json10
-rw-r--r--integration-test/src/test/resources/data/tree/updated-test-tree.yang33
23 files changed, 259 insertions, 59 deletions
diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml
index 63c5f16d0..e60e17418 100644
--- a/cps-ncmp-rest/pom.xml
+++ b/cps-ncmp-rest/pom.xml
@@ -34,7 +34,7 @@
<artifactId>cps-ncmp-rest</artifactId>
<properties>
- <minimum-coverage>0.99</minimum-coverage>
+ <minimum-coverage>1.00</minimum-coverage>
</properties>
<dependencies>
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
index 02de9854e..ba6f89192 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -261,22 +261,22 @@ public class DmiDataOperations extends DmiOperations {
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);
}
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java
index 2d9a51b84..65cda9478 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java
@@ -30,6 +30,7 @@ import lombok.NoArgsConstructor;
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;
@@ -44,49 +45,48 @@ public class DataOperationEventCreator {
*
* @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;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java
index d8fb904f2..c455337ac 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java
@@ -68,8 +68,8 @@ public class ResourceDataOperationRequestUtils {
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 =
@@ -100,15 +100,15 @@ public class ResourceDataOperationRequestUtils {
}
}
}
- 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;
}
@@ -118,16 +118,16 @@ public class ResourceDataOperationRequestUtils {
*
* @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);
}
@@ -174,14 +174,14 @@ public class ResourceDataOperationRequestUtils {
!= 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));
}
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
index c86682406..38b2056d0 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
@@ -110,9 +110,9 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
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() {
@@ -126,7 +126,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
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)
]
}
}
diff --git a/cps-ncmp-service/src/test/resources/dataOperationRequest.json b/cps-ncmp-service/src/test/resources/dataOperationRequest.json
index d2e0d6489..f69b87631 100644
--- a/cps-ncmp-service/src/test/resources/dataOperationRequest.json
+++ b/cps-ncmp-service/src/test/resources/dataOperationRequest.json
@@ -10,18 +10,20 @@
"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"
]
},
{
@@ -29,6 +31,7 @@
"operationId": "operational-15",
"datastore": "ncmp-datastore:passthrough-operational",
"options": "some option",
+ "resourceIdentifier": "some resource identifier",
"targetIds": [
"ch4-dmi2",
"ch6-dmi1"
diff --git a/cps-ncmp-service/src/test/resources/dataOperationResponseEvent.json b/cps-ncmp-service/src/test/resources/dataOperationResponseEvent.json
new file mode 100644
index 000000000..611d47d1a
--- /dev/null
+++ b/cps-ncmp-service/src/test/resources/dataOperationResponseEvent.json
@@ -0,0 +1 @@
+[{"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
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 fd669b75c..c30a63fd4 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
@@ -181,12 +181,46 @@ class QueryRestControllerSpec extends Specification {
.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'
+ }
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
index 6f9f5a482..847a4a32f 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
@@ -171,6 +171,18 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
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);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
index 5bb585781..b8503a7fe 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
@@ -99,4 +99,8 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Long> {
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);
+
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java
index 4f056c8f6..c187f20ea 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java
@@ -94,7 +94,7 @@ public class FragmentPrefetchRepositoryImpl implements FragmentPrefetchRepositor
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<>());
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
index fcf3f54cc..edd052a51 100755
--- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
@@ -135,4 +135,13 @@ public interface CpsAdminService {
* 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);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
index e286eea17..d83ee434d 100755
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
@@ -120,4 +120,11 @@ public class CpsAdminServiceImpl implements CpsAdminService {
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);
+ }
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
index 1c1e80a20..5a1810f47 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
@@ -133,4 +133,13 @@ public interface CpsAdminPersistenceService {
* @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);
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
index eb41e2085..12564fb6d 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
@@ -178,4 +178,11 @@ class CpsAdminServiceImplSpec extends Specification {
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')
+ }
}
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index cd70cf8be..3f672ad62 100755
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -39,6 +39,7 @@ Release Data
Bug Fixes
---------
3.3.6
+ - `CPS-1841 <https://jira.onap.org/browse/CPS-1841>`_ Update of top-level data node fails with exception
Features
--------
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index 4780e3642..03ef9c2fd 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -108,7 +108,7 @@ class CpsIntegrationSpecBase extends Specification {
def dataspaceExists(dataspaceName) {
try {
cpsAdminService.getDataspace(dataspaceName)
- } catch (DataspaceNotFoundException e) {
+ } catch (DataspaceNotFoundException dataspaceNotFoundException) {
return false
}
return true
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
index 92fbdaaa2..bdd894c31 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
@@ -22,10 +22,12 @@ package org.onap.cps.integration.functional
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 {
@@ -44,8 +46,8 @@ 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
}
@@ -100,8 +102,8 @@ class CpsAdminServiceIntegrationSpec extends CpsIntegrationSpecBase {
def thrown = null
try {
objectUnderTest.getAnchor(GENERAL_TEST_DATASPACE, 'newAnchor')
- } catch(Exception e) {
- thrown = e
+ } catch(Exception exception) {
+ thrown = exception
}
assert thrown instanceof AnchorNotFoundException
}
@@ -151,4 +153,28 @@ class CpsAdminServiceIntegrationSpec extends CpsIntegrationSpecBase {
'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]'
+ }
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy
index 9716cb56e..82a415ece 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy
@@ -394,6 +394,17 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
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'}}"
diff --git a/integration-test/src/test/resources/data/tree/new-test-tree.json b/integration-test/src/test/resources/data/tree/new-test-tree.json
new file mode 100644
index 000000000..f7aefc472
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/new-test-tree.json
@@ -0,0 +1,12 @@
+{
+ "test-tree": {
+ "branch": [
+ {
+ "name": "left",
+ "nest": {
+ "name": "small"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/tree/new-test-tree.yang b/integration-test/src/test/resources/data/tree/new-test-tree.yang
new file mode 100644
index 000000000..1a08b92f1
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/new-test-tree.yang
@@ -0,0 +1,21 @@
+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
diff --git a/integration-test/src/test/resources/data/tree/updated-test-tree.json b/integration-test/src/test/resources/data/tree/updated-test-tree.json
new file mode 100644
index 000000000..2c2eea4f0
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/updated-test-tree.json
@@ -0,0 +1,10 @@
+{
+ "nest": {
+ "name": "small",
+ "birds": [
+ "Night Owl",
+ "Raven",
+ "Crow"
+ ]
+ }
+} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/tree/updated-test-tree.yang b/integration-test/src/test/resources/data/tree/updated-test-tree.yang
new file mode 100644
index 000000000..bd883e8b6
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/updated-test-tree.yang
@@ -0,0 +1,33 @@
+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