aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosephKeenan <joseph.keenan@est.tech>2022-03-28 12:26:07 +0100
committerJosephKeenan <joseph.keenan@est.tech>2022-04-06 15:50:08 +0100
commitdeac4777c1a245be1dc4c423658523b41071b110 (patch)
tree6dea5a08ae885840fbc4aff566f74f815a8444bf
parentea01d09861289ff162dff318713d1c24eba89259 (diff)
Query based on Public CM Properties
-Updated OpenAPI for new Endpoint -Will replace SQL with CPSPathQuery once investigation is complete -Functionality in place to determine if public properties match - -Added Unit and CSIT tests - small modifications may need to be made -CSIT tests enhanced to add additional nodes and tests Issue-ID: CPS-731 Change-Id: I403e603ce79c4a4a6994d51b459b5703510d5a83 Signed-off-by: DylanB95EST <dylan.byrne@est.tech> Signed-off-by: JosephKeenan <joseph.keenan@est.tech>
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml10
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml27
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml5
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java16
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy30
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java9
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java17
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java41
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java9
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java10
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java3
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java63
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy25
-rwxr-xr-xcps-ri/src/test/resources/data/fragment.sql21
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/CpsAdminService.java12
-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.java12
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java41
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java2
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy12
-rw-r--r--csit/data/cmHandleRegistration.json5
-rw-r--r--csit/plans/cps/testplan.txt8
-rw-r--r--csit/tests/cps-model-sync/cps-model-sync.robot2
-rw-r--r--csit/tests/public-properties-query/public-properties-query.robot51
24 files changed, 415 insertions, 23 deletions
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 247fabd02..a7955c19f 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -211,6 +211,16 @@ components:
type: string
example: my-module-revision
+ CmHandleQueryRestParameters:
+ type: object
+ title: Cm Handle query parameters for executing cm handle search
+ properties:
+ publicCmHandleProperties:
+ type: object
+ additionalProperties:
+ type: string
+ example: Book Type
+
RestOutputCmHandle:
type: object
title: CM handle Details
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index 03ed98a0e..05e4b8485 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -291,6 +291,33 @@ retrieveCmHandleDetailsById:
application/json:
schema:
$ref: 'components.yaml#/components/schemas/RestOutputCmHandle'
+ 404:
+ $ref: 'components.yaml#/components/responses/NotFound'
+ 500:
+ $ref: 'components.yaml#/components/responses/InternalServerError'
+
+queryCmHandles:
+ post:
+ description: Execute cm handle query search
+ tags:
+ - network-cm-proxy
+ summary: Execute cm handle query upon a given set of query parameters
+ operationId: queryCmHandles
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yaml#/components/schemas/CmHandleQueryRestParameters'
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
400:
$ref: 'components.yaml#/components/responses/BadRequest'
401:
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index 12a8318ef..935b657e1 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -39,4 +39,7 @@ paths:
$ref: 'ncmp.yml#/executeCmHandleSearch'
/v1/ch/{cm-handle}:
- $ref: 'ncmp.yml#/retrieveCmHandleDetailsById' \ No newline at end of file
+ $ref: 'ncmp.yml#/retrieveCmHandleDetailsById'
+
+ /v1/data/ch/searches:
+ $ref: 'ncmp.yml#/queryCmHandles'
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 19b919333..84fcd88a9 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -34,6 +34,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.validation.Valid;
@@ -42,11 +43,13 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException;
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
import org.onap.cps.ncmp.rest.model.CmHandleProperties;
import org.onap.cps.ncmp.rest.model.CmHandleProperty;
import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
+import org.onap.cps.ncmp.rest.model.CmHandleQueryRestParameters;
import org.onap.cps.ncmp.rest.model.CmHandles;
import org.onap.cps.ncmp.rest.model.ConditionProperties;
import org.onap.cps.ncmp.rest.model.Conditions;
@@ -213,6 +216,19 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
}
/**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryRestParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ public ResponseEntity<List<String>> queryCmHandles(
+ final CmHandleQueryRestParameters cmHandleQueryRestParameters) {
+ final Set<String> cmHandleIds = networkCmProxyDataService.queryCmHandles(
+ jsonObjectMapper.convertToValueType(cmHandleQueryRestParameters, CmHandleQueryApiParameters.class));
+ return ResponseEntity.ok(List.copyOf(cmHandleIds));
+ }
+
+ /**
* Search for Cm Handle and Properties by Name.
* @param cmHandleId cm-handle identifier
* @return cm handle and its properties
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index d79d9622e..efe0f3ae6 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -60,7 +60,10 @@ class NetworkCmProxyControllerSpec extends Specification {
NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
@SpringBean
- JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ ObjectMapper objectMapper = new ObjectMapper()
+
+ @SpringBean
+ JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(objectMapper)
@SpringBean
NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper)
@@ -255,6 +258,31 @@ class NetworkCmProxyControllerSpec extends Specification {
response.contentAsString == '{"cmHandles":[]}'
}
+ def 'Query for cm handles matching query parameters'() {
+ given: 'an endpoint and json data'
+ def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
+ String jsonString = '{"publicCmHandleProperties": {"name": "Contact", "value": "newemailforstore@bookstore.com"}}'
+ and: 'the service method is invoked with module names and returns cm handle ids'
+ 1 * mockNetworkCmProxyDataService.queryCmHandles(_) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
+ when: 'the searches api is invoked'
+ def response = mvc.perform(post(searchesEndpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(jsonString)).andReturn().response
+ then: 'cm handle ids are returned'
+ response.contentAsString == '["some-cmhandle-id1","some-cmhandle-id2"]'
+ }
+
+ def 'Query for cm handles with invalid request payload'() {
+ when: 'the searches api is invoked'
+ def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
+ def invalidInputData = '{invalidJson}'
+ def response = mvc.perform(post(searchesEndpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(invalidInputData)).andReturn().response
+ then: 'BAD_REQUEST is returned'
+ response.getStatus() == 400
+ }
+
def 'Patch resource data in pass-through running datastore.' () {
given: 'patch resource data url'
def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
index cbd0756c0..058c42b7b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
@@ -26,6 +26,8 @@ package org.onap.cps.ncmp.api;
import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
import java.util.Collection;
+import java.util.Set;
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
@@ -119,4 +121,11 @@ public interface NetworkCmProxyDataService {
*/
NcmpServiceCmHandle getNcmpServiceCmHandle(String cmHandleId);
+ /**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryApiParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ Set<String> queryCmHandles(CmHandleQueryApiParameters cmHandleQueryApiParameters);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
index 696bb0a37..9c3d9448e 100755
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
@@ -31,12 +31,14 @@ import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMES
import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
+import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -50,6 +52,7 @@ import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError;
import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
@@ -157,6 +160,20 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
}
+ @Override
+ public Set<String> queryCmHandles(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+
+ cmHandleQueryApiParameters.getPublicProperties().forEach((key, value) -> {
+ if (Strings.isNullOrEmpty(key)) {
+ throw new DataValidationException("Invalid Query Parameter.",
+ "Missing property name - please supply a valid name.");
+ }
+ });
+
+ return cpsAdminService.queryCmHandles(jsonObjectMapper.convertToValueType(cmHandleQueryApiParameters,
+ org.onap.cps.spi.model.CmHandleQueryParameters.class));
+ }
+
/**
* Retrieve cm handle details for a given cm handle.
*
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
new file mode 100644
index 000000000..3f584ed15
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 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.ncmp.api.models;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.Map;
+import javax.validation.Valid;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@JsonInclude(Include.NON_NULL)
+public class CmHandleQueryApiParameters {
+
+ @JsonProperty("publicCmHandleProperties")
+ @Valid
+ private Map<String, String> publicProperties = Collections.emptyMap();
+
+}
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 50b27207e..2e7bb7e96 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
@@ -24,6 +24,7 @@ package org.onap.cps.spi.impl;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import lombok.AllArgsConstructor;
@@ -36,8 +37,10 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DataspaceInUseException;
import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException;
import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
import org.onap.cps.spi.repository.AnchorRepository;
import org.onap.cps.spi.repository.DataspaceRepository;
+import org.onap.cps.spi.repository.ModuleReferenceRepository;
import org.onap.cps.spi.repository.SchemaSetRepository;
import org.onap.cps.spi.repository.YangResourceRepository;
import org.springframework.dao.DataIntegrityViolationException;
@@ -51,6 +54,7 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
private final AnchorRepository anchorRepository;
private final SchemaSetRepository schemaSetRepository;
private final YangResourceRepository yangResourceRepository;
+ private final ModuleReferenceRepository moduleReferenceRepository;
@Override
public void createDataspace(final String dataspaceName) {
@@ -132,6 +136,11 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
anchorRepository.delete(anchorEntity);
}
+ @Override
+ public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
+ return moduleReferenceRepository.queryCmHandles(cmHandleQueryParameters);
+ }
+
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/ModuleReferenceQuery.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
index 6551937e1..4bc9dd960 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
@@ -21,6 +21,8 @@
package org.onap.cps.spi.repository;
import java.util.Collection;
+import java.util.Set;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
import org.onap.cps.spi.model.ModuleReference;
/**
@@ -31,4 +33,12 @@ public interface ModuleReferenceQuery {
Collection<ModuleReference> identifyNewModuleReferences(
final Collection<ModuleReference> moduleReferencesToCheck);
+ /**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
+
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java
index ce2bfe784..f70e21837 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java
@@ -27,8 +27,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
-public interface ModuleReferenceRepository extends
- JpaRepository<YangResourceEntity, Long>, ModuleReferenceQuery {
+public interface ModuleReferenceRepository extends JpaRepository<YangResourceEntity, Long>, ModuleReferenceQuery {
Collection<ModuleReference> identifyNewModuleReferences(
final Collection<ModuleReference> moduleReferencesToCheck);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
index 0e79deb8e..40a93da71 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
@@ -24,21 +24,32 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.UUID;
+import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
+import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.spi.CpsDataPersistenceService;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Transactional
+@AllArgsConstructor
public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
@PersistenceContext
private EntityManager entityManager;
+ private final CpsDataPersistenceService cpsDataPersistenceService;
+
@Override
@SneakyThrows
public Collection<ModuleReference> identifyNewModuleReferences(
@@ -57,6 +68,56 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
return identifyNewModuleReferencesForCmHandle(tempTableName);
}
+ /**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ @Override
+ public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
+
+ if (cmHandleQueryParameters.getPublicProperties().entrySet().isEmpty()) {
+ return getAllCmHandles();
+ }
+
+ final Collection<DataNode> amalgamatedQueryResult = new ArrayList<>();
+ int queryConditionCounter = 0;
+ for (final Map.Entry<String, String> entry : cmHandleQueryParameters.getPublicProperties().entrySet()) {
+ final StringBuilder cmHandlePath = new StringBuilder();
+ cmHandlePath.append("//public-properties[@name='").append(entry.getKey()).append("' ");
+ cmHandlePath.append("and @value='").append(entry.getValue()).append("']");
+ cmHandlePath.append("/ancestor::cm-handles");
+
+ final Collection<DataNode> singleConditionQueryResult =
+ cpsDataPersistenceService.queryDataNodes("NCMP-Admin",
+ "ncmp-dmi-registry", String.valueOf(cmHandlePath), FetchDescendantsOption.OMIT_DESCENDANTS);
+ if (++queryConditionCounter == 1) {
+ amalgamatedQueryResult.addAll(singleConditionQueryResult);
+ } else {
+ amalgamatedQueryResult.retainAll(singleConditionQueryResult);
+ }
+
+ if (amalgamatedQueryResult.isEmpty()) {
+ break;
+ }
+ }
+
+ return extractCmHandleIds(amalgamatedQueryResult);
+ }
+
+ private Set<String> getAllCmHandles() {
+ final Collection<DataNode> cmHandles = cpsDataPersistenceService.queryDataNodes("NCMP-Admin",
+ "ncmp-dmi-registry", "//public-properties/ancestor::cm-handles",
+ FetchDescendantsOption.OMIT_DESCENDANTS);
+ return extractCmHandleIds(cmHandles);
+ }
+
+ private Set<String> extractCmHandleIds(final Collection<DataNode> cmHandles) {
+ return cmHandles.stream().map(cmHandle -> cmHandle.getLeaves().get("id").toString())
+ .collect(Collectors.toSet());
+ }
+
private void createTemporaryTable(final String tempTableName) {
final StringBuilder sqlStringBuilder = new StringBuilder("CREATE TEMPORARY TABLE " + tempTableName + "(");
sqlStringBuilder.append(" id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,");
@@ -95,7 +156,7 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
+ " WHERE yang_resource.module_name IS NULL;", tempTableName);
final List<Object[]> resultsAsObjects =
- entityManager.createNativeQuery(sql).getResultList();
+ (List<Object[]>) entityManager.createNativeQuery(sql).getResultList();
final List<ModuleReference> resultsAsModuleReferences = new ArrayList<>(resultsAsObjects.size());
for (final Object[] row : resultsAsObjects) {
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
index 063bd5b5a..f486cb76d 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation
+ * Copyright (C) 2021-2022 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
@@ -22,6 +22,7 @@
package org.onap.cps.spi.impl
+import org.mockito.Mock
import org.onap.cps.spi.CpsAdminPersistenceService
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.AnchorNotFoundException
@@ -30,15 +31,21 @@ import org.onap.cps.spi.exceptions.DataspaceNotFoundException
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException
import org.onap.cps.spi.model.Anchor
+import org.onap.cps.spi.model.CmHandleQueryParameters
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.jdbc.Sql
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper
class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
@Autowired
CpsAdminPersistenceService objectUnderTest
+ @Mock
+ ObjectMapper objectMapper
+
static final String SET_DATA = '/data/anchor.sql'
+ static final String SET_FRAGMENT_DATA = '/data/fragment.sql'
static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql'
static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA'
static final Integer DELETED_ANCHOR_ID = 3002
@@ -219,4 +226,20 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)'
}
+ @Sql([CLEAR_DATA, SET_FRAGMENT_DATA])
+ def 'Retrieve cm handle ids when #scenario.'() {
+ when: 'the service is invoked'
+ def cmHandleQueryParameters = new CmHandleQueryParameters()
+ cmHandleQueryParameters.setPublicProperties(publicProperties)
+ def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+ then: 'the correct expected cm handles are returned'
+ returnedCmHandles == expectedCmHandleIds
+ where: 'the following data is used'
+ scenario | publicProperties || expectedCmHandleIds
+ 'single matching property' | ['Contact' : 'newemailforstore@bookstore.com'] || ['PNFDemo2', 'PNFDemo', 'PNFDemo4'] as Set
+ 'public property dont match' | ['wont_match' : 'wont_match'] || [] as Set
+ '2 properties, only one match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': 'newemailforstore2@bookstore.com'] || ['PNFDemo4'] as Set
+ '2 properties, no match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': ''] || [] as Set
+ 'No public properties - return all cm handles' | [ : ] || ['PNFDemo3', 'PNFDemo', 'PNFDemo2', 'PNFDemo4'] as Set
+ }
}
diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql
index a27bb5fde..fb4a5f77c 100755
--- a/cps-ri/src/test/resources/data/fragment.sql
+++ b/cps-ri/src/test/resources/data/fragment.sql
@@ -1,6 +1,6 @@
/*
============LICENSE_START=======================================================
- Copyright (C) 2021 Nordix Foundation.
+ Copyright (C) 2021-2022 Nordix Foundation.
Modifications Copyright (C) 2021 Pantheon.tech
Modifications Copyright (C) 2021-2022 Bell Canada.
================================================================================
@@ -21,14 +21,16 @@
*/
INSERT INTO DATASPACE (ID, NAME) VALUES
- (1001, 'DATASPACE-001');
+ (1001, 'DATASPACE-001'),
+ (1002, 'NCMP-Admin');
INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
(2001, 'SCHEMA-SET-001', 1001);
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(3001, 'ANCHOR-001', 1001, 2001),
- (3003, 'ANCHOR-003', 1001, 2001);
+ (3003, 'ANCHOR-003', 1001, 2001),
+ (3004, 'ncmp-dmi-registry', 1002, 2001);
INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES
(4001, 1001, 3001, null, '/parent-1'),
@@ -67,4 +69,15 @@ INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES)
(4230, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key="X"]', '{"key": "X"}'),
(4231, 1001, 3003, null, '/parent-206[@key="A"]', '{"key": "A"}'),
(4232, 1001, 3003, 4231, '/parent-206[@key="A"]/child-206', '{}'),
- (4233, 1001, 3003, null, '/parent-206[@key="B"]', '{"key": "B"}'); \ No newline at end of file
+ (4233, 1001, 3003, null, '/parent-206[@key="B"]', '{"key": "B"}');
+
+INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
+ (5000, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo"]', '{"id": "PNFDemo", "dmi-service-name": "http://172.21.235.14:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+ (5001, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo2"]', '{"id": "PNFDemo2", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+ (5002, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo3"]', '{"id": "PNFDemo3", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+ (5003, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo4"]', '{"id": "PNFDemo4", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'),
+ (5004, 1002, 3004, 5000, '/dmi-registry/cm-handles[@id="PNFDemo"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+ (5005, 1002, 3004, 5001, '/dmi-registry/cm-handles[@id="PNFDemo2"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+ (5006, 1002, 3004, 5002, '/dmi-registry/cm-handles[@id="PNFDemo3"]/public-properties[@name="Contact"]', '{"name": "Contact3", "value": "PNF3@bookstore.com"}'),
+ (5007, 1002, 3004, 5003, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'),
+ (5008, 1002, 3004, 5004, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact2"]', '{"name": "Contact2", "value": "newemailforstore2@bookstore.com"}'); \ No newline at end of file
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 2cb01ac1e..2106f1584 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2021 Nordix Foundation
+ * Copyright (C) 2020-2022 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
@@ -23,9 +23,11 @@
package org.onap.cps.api;
import java.util.Collection;
+import java.util.Set;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
/**
* CPS Admin Service.
@@ -100,4 +102,12 @@ public interface CpsAdminService {
* given module names
*/
Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames);
+
+ /**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
}
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 7bec1e39f..762754f9a 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
@@ -24,12 +24,14 @@ package org.onap.cps.api.impl;
import java.time.OffsetDateTime;
import java.util.Collection;
+import java.util.Set;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.onap.cps.api.CpsAdminService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
import org.onap.cps.utils.CpsValidator;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@@ -91,4 +93,9 @@ public class CpsAdminServiceImpl implements CpsAdminService {
final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames);
return anchors.stream().map(Anchor::getName).collect(Collectors.toList());
}
+
+ @Override
+ public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
+ return cpsAdminPersistenceService.queryCmHandles(cmHandleQueryParameters);
+ }
}
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 dd4059d88..25167e844 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020 Nordix Foundation.
+ * Copyright (C) 2020-2022 Nordix Foundation.
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
@@ -23,8 +23,10 @@
package org.onap.cps.spi;
import java.util.Collection;
+import java.util.Set;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
/*
Service for handling CPS admin data.
@@ -99,4 +101,12 @@ public interface CpsAdminPersistenceService {
* @param anchorName anchor name
*/
void deleteAnchor(String dataspaceName, String anchorName);
+
+ /**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
new file mode 100644
index 000000000..ff4e62763
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 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.spi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.Map;
+import javax.validation.Valid;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@JsonInclude(Include.NON_NULL)
+public class CmHandleQueryParameters {
+
+ @JsonProperty("publicCmHandleProperties")
+ @Valid
+ private Map<String, String> publicProperties = Collections.emptyMap();
+
+}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
index 55e7b9970..43aa06b81 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
@@ -26,11 +26,13 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Setter(AccessLevel.PROTECTED)
@Getter
+@EqualsAndHashCode
public class DataNode {
DataNode() { }
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 bb122d1ae..cbe1ebbbd 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020 Nordix Foundation
+ * Copyright (C) 2020-2022 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
@@ -25,6 +25,7 @@ package org.onap.cps.api.impl
import org.onap.cps.api.CpsDataService
import org.onap.cps.spi.CpsAdminPersistenceService
import org.onap.cps.spi.model.Anchor
+import org.onap.cps.spi.model.CmHandleQueryParameters
import spock.lang.Specification
import java.time.OffsetDateTime
@@ -95,4 +96,13 @@ class CpsAdminServiceImplSpec extends Specification {
1 * mockCpsAdminPersistenceService.deleteDataspace('someDataspace')
}
+ def 'Query CM Handles.'() {
+ given: 'a cm handle query'
+ def cmHandleQueryParameters = new CmHandleQueryParameters()
+ when: 'query cm handles is invoked'
+ objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+ then: 'associated persistence service method is invoked with correct parameter'
+ 1 * mockCpsAdminPersistenceService.queryCmHandles(cmHandleQueryParameters)
+ }
+
}
diff --git a/csit/data/cmHandleRegistration.json b/csit/data/cmHandleRegistration.json
deleted file mode 100644
index 0133148fd..000000000
--- a/csit/data/cmHandleRegistration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "cmHandles": [
- "PNFDemo"
- ]
-} \ No newline at end of file
diff --git a/csit/plans/cps/testplan.txt b/csit/plans/cps/testplan.txt
index 8069bb72e..d4615e701 100644
--- a/csit/plans/cps/testplan.txt
+++ b/csit/plans/cps/testplan.txt
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021 Nordix Foundation
+# Copyright (C) 2021-2022 Nordix Foundation
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
# Test suites are relative paths under csit/tests/.
# Place the suites in run order.
actuator
-cps-model-sync
-ncmp-passthrough
cps-admin
cps-data
-
+cps-model-sync
+ncmp-passthrough
+public-properties-query \ No newline at end of file
diff --git a/csit/tests/cps-model-sync/cps-model-sync.robot b/csit/tests/cps-model-sync/cps-model-sync.robot
index 7de1f3a1b..ea082b5a8 100644
--- a/csit/tests/cps-model-sync/cps-model-sync.robot
+++ b/csit/tests/cps-model-sync/cps-model-sync.robot
@@ -34,7 +34,7 @@ ${auth} Basic Y3BzdXNlcjpjcHNyMGNrcyE=
${ncmpInventoryBasePath} /ncmpInventory
${ncmpBasePath} /ncmp
${dmiUrl} http://${DMI_HOST}:${DMI_PORT}
-${jsonDataCreate} {"dmiPlugin":"${dmiUrl}","dmiDataPlugin":"","dmiModelPlugin":"","createdCmHandles":[{"cmHandle":"PNFDemo","cmHandleProperties":{"Book1":"Sci-Fi Book"},"publicCmHandleProperties":{"Contact":"storeemail@bookstore.com"}}]}
+${jsonDataCreate} {"dmiPlugin":"${dmiUrl}","dmiDataPlugin":"","dmiModelPlugin":"","createdCmHandles":[{"cmHandle":"PNFDemo","cmHandleProperties":{"Book1":"Sci-Fi Book"},"publicCmHandleProperties":{"Contact":"storeemail@bookstore.com", "Contact2":"storeemail2@bookstore.com"}}]}
${jsonDataUpdate} {"dmiPlugin":"${dmiUrl}","dmiDataPlugin":"","dmiModelPlugin":"","updatedCmHandles":[{"cmHandle":"PNFDemo","cmHandleProperties":{"Book1":"Romance Book"},"publicCmHandleProperties":{"Contact":"newemailforstore@bookstore.com"}}]}
*** Test Cases ***
diff --git a/csit/tests/public-properties-query/public-properties-query.robot b/csit/tests/public-properties-query/public-properties-query.robot
new file mode 100644
index 000000000..3a640871b
--- /dev/null
+++ b/csit/tests/public-properties-query/public-properties-query.robot
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 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=========================================================
+ */
+
+*** Settings ***
+Documentation Public Properties Query Test
+
+Library Collections
+Library OperatingSystem
+Library RequestsLibrary
+Library BuiltIn
+
+Suite Setup Create Session CPS_URL http://${CPS_CORE_HOST}:${CPS_CORE_PORT}
+
+*** Variables ***
+
+${auth} Basic Y3BzdXNlcjpjcHNyMGNrcyE=
+${ncmpBasePath} /ncmp/v1
+${jsonMatchingQueryParameters} {"publicCmHandleProperties": {"Contact" : "newemailforstore@bookstore.com", "Contact2" : "storeemail2@bookstore.com"}}
+${jsonMissingPropertyQueryParameters} {"publicCmHandleProperties": { "" : "doesnt matter"}}
+
+*** Test Cases ***
+Retrieve CM Handles where query parameters Match
+ ${uri}= Set Variable ${ncmpBasePath}/data/ch/searches
+ ${headers}= Create Dictionary Content-Type=application/json Authorization=${auth}
+ ${response}= POST On Session CPS_URL ${uri} headers=${headers} data=${jsonMatchingQueryParameters}
+ ${responseJson}= Set Variable ${response.json()}
+ Should Be Equal As Strings ${response.status_code} 200
+ Should Contain ${responseJson} PNFDemo
+
+Throw 400 when Structure of Request is Incorrect
+ ${uri}= Set Variable ${ncmpBasePath}/data/ch/searches
+ ${headers}= Create Dictionary Content-Type=application/json Authorization=${auth}
+ ${response}= POST On Session CPS_URL ${uri} headers=${headers} data=${jsonMissingPropertyQueryParameters} expected_status=400
+ Should Be Equal As Strings ${response} <Response [400]>