diff options
26 files changed, 334 insertions, 34 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImpl.java index 1a54a824b2..bda0a728b4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImpl.java @@ -47,6 +47,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries { private static final String NCMP_DATASPACE_NAME = "NCMP-Admin"; private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry"; + private static final String DESCENDANT_PATH = "//"; private final CpsDataPersistenceService cpsDataPersistenceService; private static final Map<String, NcmpServiceCmHandle> NO_QUERY_TO_EXECUTE = null; @@ -72,7 +73,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries { } Map<String, NcmpServiceCmHandle> cmHandleIdToNcmpServiceCmHandles = null; for (final Map.Entry<String, String> publicPropertyQueryPair : propertyQueryPairs.entrySet()) { - final String cpsPath = "//" + propertyType.getYangContainerName() + "[@name=\"" + final String cpsPath = DESCENDANT_PATH + propertyType.getYangContainerName() + "[@name=\"" + publicPropertyQueryPair.getKey() + "\" and @value=\"" + publicPropertyQueryPair.getValue() + "\"]"; diff --git a/cps-rest/docs/openapi/cpsAdmin.yml b/cps-rest/docs/openapi/cpsAdmin.yml index e887ef2c07..595f6d7ec1 100644 --- a/cps-rest/docs/openapi/cpsAdmin.yml +++ b/cps-rest/docs/openapi/cpsAdmin.yml @@ -91,6 +91,31 @@ schemaSet: $ref: 'components.yml#/components/responses/Conflict' '500': $ref: 'components.yml#/components/responses/InternalServerError' + get: + description: Read all schema sets, given a dataspace + tags: + - cps-admin + summary: Get schema sets + operationId: getSchemaSets + parameters: + - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: 'components.yml#/components/schemas/SchemaSetDetails' + '400': + $ref: 'components.yml#/components/responses/BadRequest' + '401': + $ref: 'components.yml#/components/responses/Unauthorized' + '403': + $ref: 'components.yml#/components/responses/Forbidden' + '500': + $ref: 'components.yml#/components/responses/InternalServerError' schemaSetBySchemaSetName: get: diff --git a/cps-rest/docs/openapi/openapi.yml b/cps-rest/docs/openapi/openapi.yml index e170295504..e02d6a6715 100644 --- a/cps-rest/docs/openapi/openapi.yml +++ b/cps-rest/docs/openapi/openapi.yml @@ -84,4 +84,4 @@ paths: $ref: 'cpsQuery.yml#/nodesByDataspaceAndAnchorAndCpsPath' security: - - basicAuth: []
\ No newline at end of file + - basicAuth: [] diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java index a29f8d2969..285a15c6a3 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java @@ -110,6 +110,20 @@ public class AdminRestController implements CpsAdminApi { } /** + * Get list of schema sets for a given dataspace name. + * + * @param dataspaceName dataspace name + * @return a {@Link ResponseEntity} of schema sets & {@link HttpStatus} OK + */ + @Override + public ResponseEntity<List<SchemaSetDetails>> getSchemaSets(final String dataspaceName) { + final Collection<SchemaSet> schemaSets = cpsModuleService.getSchemaSets(dataspaceName); + final List<SchemaSetDetails> schemaSetDetails = schemaSets.stream().map(cpsRestInputMapper::toSchemaSetDetails) + .collect(Collectors.toList()); + return new ResponseEntity<>(schemaSetDetails, HttpStatus.OK); + } + + /** * Delete a {@link SchemaSet} based on given dataspace name & schemaset name. * * @param dataspaceName dataspace name diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy index e9612fc395..7120ce49f3 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy @@ -278,6 +278,21 @@ class AdminRestControllerSpec extends Specification { response.getContentAsString().contains(schemaSetName) } + def 'Get all schema sets for a given dataspace name.'() { + given: 'service method returns all schema sets for a dataspace' + mockCpsModuleService.getSchemaSets(dataspaceName) >> + [new SchemaSet(name: schemaSetName, dataspaceName: dataspaceName), + new SchemaSet(name: "test-schemaset", dataspaceName: dataspaceName)] + and: 'an endpoint' + def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets" + when: 'get schema sets API is invoked' + def response = mvc.perform(get(schemaSetEndpoint)).andReturn().response + then: 'the correct schema sets is returned' + assert response.status == HttpStatus.OK.value() + assert response.getContentAsString() == '[{"dataspaceName":"my_dataspace","moduleReferences":[],"name":' + + '"my_schema_set"},{"dataspaceName":"my_dataspace","moduleReferences":[],"name":"test-schemaset"}]' + } + def 'Create Anchor.'() { given: 'request parameters' def requestParams = new LinkedMultiValueMap<>() diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index ac1be1cd30..c725b4224e 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -24,6 +24,7 @@ package org.onap.cps.spi.impl; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -232,9 +233,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService if (isRootXpath(xpath)) { final List<FragmentExtract> fragmentExtracts = fragmentRepository.getTopLevelFragments(dataspaceEntity, anchorEntity); - final FragmentEntity fragmentEntity = FragmentEntityArranger.toFragmentEntityTree(anchorEntity, + return FragmentEntityArranger.toFragmentEntityTree(anchorEntity, fragmentExtracts); - return fragmentEntity; } else { final String normalizedXpath = getNormalizedXpath(xpath); final FragmentEntity fragmentEntity; @@ -347,7 +347,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private DataNode toDataNode(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption); - Map<String, Object> leaves = new HashMap<>(); + Map<String, Serializable> leaves = new HashMap<>(); if (fragmentEntity.getAttributes() != null) { leaves = jsonObjectMapper.convertJsonString(fragmentEntity.getAttributes(), Map.class); } @@ -369,7 +369,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService @Override public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath, - final Map<String, Object> leaves) { + final Map<String, Serializable> leaves) { final FragmentEntity fragmentEntity = getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, xpath); fragmentEntity.setAttributes(jsonObjectMapper.asJsonString(leaves)); fragmentRepository.save(fragmentEntity); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java index 8008e0324a..c9f9a78ef5 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java @@ -3,6 +3,7 @@ * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,6 +56,7 @@ import org.onap.cps.spi.exceptions.DuplicatedYangResourceException; import org.onap.cps.spi.exceptions.ModelValidationException; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; +import org.onap.cps.spi.model.SchemaSet; import org.onap.cps.spi.repository.DataspaceRepository; import org.onap.cps.spi.repository.ModuleReferenceRepository; import org.onap.cps.spi.repository.SchemaSetRepository; @@ -155,6 +157,14 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ } @Override + public Collection<SchemaSet> getSchemaSetsByDataspaceName(final String dataspaceName) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + final List<SchemaSetEntity> schemaSetEntities = schemaSetRepository.getByDataspace(dataspaceEntity); + return schemaSetEntities.stream() + .map(CpsModulePersistenceServiceImpl::toSchemaSet).collect(Collectors.toList()); + } + + @Override @Transactional // A retry is made to store the schema set if it fails because of duplicated yang resource exception that // can occur in case of specific concurrent requests. @@ -327,12 +337,14 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ */ private String getNameForChecksum( final String checksum, final Collection<YangResourceEntity> yangResourceEntities) { - return - yangResourceEntities.stream() + final Optional<String> optionalFileName = yangResourceEntities.stream() .filter(entity -> StringUtils.equals(checksum, (entity.getChecksum()))) .findFirst() - .map(YangResourceEntity::getFileName) - .orElse(null); + .map(YangResourceEntity::getFileName); + if (optionalFileName.isPresent()) { + return optionalFileName.get(); + } + return null; } /** @@ -364,4 +376,9 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ yangResourceEntity.getRevision(), yangResourceEntity.getContent()); } + + private static SchemaSet toSchemaSet(final SchemaSetEntity schemaSetEntity) { + return SchemaSet.builder().name(schemaSetEntity.getName()) + .dataspaceName(schemaSetEntity.getDataspace().getName()).build(); + } } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java index a15ce622c2..8cecb0a8e3 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Pantheon.tech + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +20,10 @@ package org.onap.cps.spi.repository; +import java.util.Collection; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.entities.SchemaSetEntity; @@ -33,6 +37,13 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte Optional<SchemaSetEntity> findByDataspaceAndName(@NotNull DataspaceEntity dataspaceEntity, @NotNull String schemaSetName); + /** + * Gets schema sets by dataspace. + * @param dataspaceEntity dataspace entity + * @return list of schema set entity + */ + Collection<SchemaSetEntity> findByDataspace(@NotNull DataspaceEntity dataspaceEntity); + Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity); /** @@ -48,4 +59,15 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte return findByDataspaceAndName(dataspaceEntity, schemaSetName) .orElseThrow(() -> new SchemaSetNotFoundException(dataspaceEntity.getName(), schemaSetName)); } + + /** + * Gets all schema sets for a given dataspace. + * + * @param dataspaceEntity dataspace entity + * @return list of schema set entity + * @throws SchemaSetNotFoundException if SchemaSet not found + */ + default List<SchemaSetEntity> getByDataspace(@NotNull final DataspaceEntity dataspaceEntity) { + return findByDataspace(dataspaceEntity).stream().collect(Collectors.toList()); + } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy index f9ebc52f18..bcb080726a 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021-2022 Bell Canada. + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -28,6 +29,7 @@ import org.onap.cps.spi.exceptions.DataspaceNotFoundException import org.onap.cps.spi.exceptions.SchemaSetNotFoundException import org.onap.cps.spi.model.ModuleDefinition import org.onap.cps.spi.model.ModuleReference +import org.onap.cps.spi.model.SchemaSet import org.onap.cps.spi.repository.AnchorRepository import org.onap.cps.spi.repository.SchemaSetRepository import org.onap.cps.spi.repository.SchemaSetYangResourceRepositoryImpl @@ -209,6 +211,14 @@ class CpsModulePersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase } @Sql([CLEAR_DATA, SET_DATA]) + def 'Retrieve schema sets for a given dataspace name'() { + when: 'the schema set resources for a given dataspace name is retrieved' + def result = objectUnderTest.getSchemaSetsByDataspaceName(DATASPACE_NAME) + then: 'the correct resources are returned' + result.contains(new SchemaSet(name: 'SCHEMA-SET-001', dataspaceName: 'DATASPACE-001')) + } + + @Sql([CLEAR_DATA, SET_DATA]) def 'Delete schema set'() { when: 'a schema set is deleted with cascade-prohibited option' objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS) diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy index fb6749c3fe..387fc1f857 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy @@ -48,16 +48,16 @@ class CpsToDataNodePerfTest extends CpsPersistenceSpecBase { createLineage() setupStopWatch.stop() def setupDurationInMillis = setupStopWatch.getTime() - and: 'setup duration is under 8000 milliseconds' - assert setupDurationInMillis < 8000 + and: 'setup duration is under 10000 milliseconds' + assert setupDurationInMillis < 10000 when: 'get parent is executed with all descendants' def readStopWatch = new StopWatch() readStopWatch.start() def result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', PERF_TEST_PARENT, INCLUDE_ALL_DESCENDANTS) readStopWatch.stop() def readDurationInMillis = readStopWatch.getTime() - then: 'read duration is under 450 milliseconds' - assert readDurationInMillis < 450 + then: 'read duration is under 500 milliseconds' + assert readDurationInMillis < 500 and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES when: 'get root is executed with all descendants' @@ -66,8 +66,8 @@ class CpsToDataNodePerfTest extends CpsPersistenceSpecBase { result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', '', INCLUDE_ALL_DESCENDANTS) readStopWatch.stop() readDurationInMillis = readStopWatch.getTime() - then: 'read duration is under 450 milliseconds' - assert readDurationInMillis < 450 + then: 'read duration is under 500 milliseconds' + assert readDurationInMillis < 500 and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES when: 'query is executed with all descendants' @@ -76,8 +76,8 @@ class CpsToDataNodePerfTest extends CpsPersistenceSpecBase { result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-parent-1', INCLUDE_ALL_DESCENDANTS) readStopWatch.stop() readDurationInMillis = readStopWatch.getTime() - then: 'read duration is under 450 milliseconds' - assert readDurationInMillis < 450 + then: 'read duration is under 500 milliseconds' + assert readDurationInMillis < 500 and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES } diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java index 6b17e820c4..b1f90d686b 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2021 Pantheon.tech + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,6 +67,14 @@ public interface CpsModuleService { SchemaSet getSchemaSet(String dataspaceName, String schemaSetName); /** + * Retrieve all schema sets in the given dataspace. + * + * @param dataspaceName dataspace name + * @return all SchemaSets + */ + Collection<SchemaSet> getSchemaSets(String dataspaceName); + + /** * Deletes Schema Set. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java index b4890f4a71..a04dd2af5b 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java @@ -3,6 +3,7 @@ * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2021 Pantheon.tech * Modifications Copyright (C) 2022 Bell Canada + * Modifications Copyright (C) 2022 TechMahindra Ltd * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +36,7 @@ import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.spi.model.SchemaSet; import org.onap.cps.spi.utils.CpsValidator; +import org.onap.cps.yang.YangTextSchemaSourceSet; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -78,6 +80,15 @@ public class CpsModuleServiceImpl implements CpsModuleService { } @Override + public Collection<SchemaSet> getSchemaSets(final String dataspaceName) { + cpsValidator.validateNameCharacters(dataspaceName); + final Collection<SchemaSet> schemaSets = + cpsModulePersistenceService.getSchemaSetsByDataspaceName(dataspaceName); + schemaSets.forEach(schemaSet -> setModuleReferences(schemaSet, dataspaceName)); + return schemaSets; + } + + @Override @Transactional public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, final CascadeDeleteAllowed cascadeDeleteAllowed) { @@ -124,4 +135,9 @@ public class CpsModuleServiceImpl implements CpsModuleService { return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed; } + private void setModuleReferences(final SchemaSet schemaSet, final String dataspaceName) { + final YangTextSchemaSourceSet yangTextSchemaSourceSet = yangTextSchemaSourceSetCache + .get(dataspaceName, schemaSet.getName()); + schemaSet.setModuleReferences(yangTextSchemaSourceSet.getModuleReferences()); + } } diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java index 8d4df20b81..28b18b3b5c 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java @@ -22,6 +22,7 @@ package org.onap.cps.spi; +import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; @@ -97,7 +98,7 @@ public interface CpsDataPersistenceService { * @param xpath xpath * @param leaves the leaves as a map where key is a leaf name and a value is a leaf value */ - void updateDataLeaves(String dataspaceName, String anchorName, String xpath, Map<String, Object> leaves); + void updateDataLeaves(String dataspaceName, String anchorName, String xpath, Map<String, Serializable> leaves); /** * Replaces an existing data node's content including descendants. diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java index aaf6b38af4..f5dc8ac3a3 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import java.util.Collection; import java.util.Map; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; +import org.onap.cps.spi.model.SchemaSet; /** * Service to manage modules. @@ -52,6 +54,14 @@ public interface CpsModulePersistenceService { Map<String, String> newModuleNameToContentMap, Collection<ModuleReference> allModuleReferences); /** + * Get all schema sets for a given dataspace. + * + * @param dataspaceName dataspace name. + * @return List of schema sets + */ + Collection<SchemaSet> getSchemaSetsByDataspaceName(String dataspaceName); + + /** * Deletes Schema Set. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetNotFoundException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetNotFoundException.java index cf63f924fd..218918fcb6 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetNotFoundException.java +++ b/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetNotFoundException.java @@ -38,4 +38,5 @@ public class SchemaSetNotFoundException extends CpsAdminException { super("Schema Set not found.", String.format("Schema Set with name %s was not found for dataspace %s.", schemaSetName, dataspaceName)); } + } 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 8170db3dad..76f33bbc14 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 @@ -46,7 +46,7 @@ public class DataNode implements Serializable { private ModuleReference moduleReference; private String xpath; private String moduleNamePrefix; - private Map<String, Object> leaves = Collections.emptyMap(); + private Map<String, Serializable> leaves = Collections.emptyMap(); private Collection<String> xpathsChildren; private Collection<DataNode> childDataNodes = Collections.emptySet(); } diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java index eaa2d77f47..1d8bac0dde 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java +++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java @@ -23,6 +23,7 @@ package org.onap.cps.spi.model; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -33,6 +34,7 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.utils.YangUtils; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; @@ -48,7 +50,7 @@ public class DataNodeBuilder { private String xpath; private String moduleNamePrefix; private String parentNodeXpath = ""; - private Map<String, Object> leaves = Collections.emptyMap(); + private Map<String, Serializable> leaves = Collections.emptyMap(); private Collection<DataNode> childDataNodes = Collections.emptySet(); /** @@ -102,7 +104,7 @@ public class DataNodeBuilder { * @param leaves for the data node * @return DataNodeBuilder */ - public DataNodeBuilder withLeaves(final Map<String, Object> leaves) { + public DataNodeBuilder withLeaves(final Map<String, Serializable> leaves) { this.leaves = leaves; return this; } @@ -173,14 +175,16 @@ public class DataNodeBuilder { private static void addDataNodeFromNormalizedNode(final DataNode currentDataNode, final NormalizedNode normalizedNode) { - if (normalizedNode instanceof DataContainerNode) { + if (normalizedNode instanceof ChoiceNode) { + addChoiceNode(currentDataNode, (ChoiceNode) normalizedNode); + } else if (normalizedNode instanceof DataContainerNode) { addYangContainer(currentDataNode, (DataContainerNode) normalizedNode); } else if (normalizedNode instanceof MapNode) { addDataNodeForEachListElement(currentDataNode, (MapNode) normalizedNode); } else if (normalizedNode instanceof ValueNode) { final ValueNode<NormalizedNode> valuesNode = (ValueNode) normalizedNode; addYangLeaf(currentDataNode, valuesNode.getIdentifier().getNodeType().getLocalName(), - valuesNode.body()); + (Serializable) valuesNode.body()); } else if (normalizedNode instanceof LeafSetNode) { addYangLeafList(currentDataNode, (LeafSetNode<?>) normalizedNode); } else { @@ -199,8 +203,9 @@ public class DataNodeBuilder { } } - private static void addYangLeaf(final DataNode currentDataNode, final String leafName, final Object leafValue) { - final Map<String, Object> leaves = new ImmutableMap.Builder<String, Object>() + private static void addYangLeaf(final DataNode currentDataNode, final String leafName, + final Serializable leafValue) { + final Map<String, Serializable> leaves = new ImmutableMap.Builder<String, Serializable>() .putAll(currentDataNode.getLeaves()) .put(leafName, leafValue) .build(); @@ -213,7 +218,7 @@ public class DataNodeBuilder { .stream() .map(normalizedNode -> (normalizedNode).body()) .collect(Collectors.toUnmodifiableList()); - addYangLeaf(currentDataNode, leafListName, leafListValues); + addYangLeaf(currentDataNode, leafListName, (Serializable) leafListValues); } private static void addDataNodeForEachListElement(final DataNode currentDataNode, final MapNode mapNode) { @@ -236,4 +241,13 @@ public class DataNodeBuilder { return newChildDataNode; } + private static void addChoiceNode(final DataNode currentDataNode, final ChoiceNode choiceNode) { + + final Collection<DataContainerChild> normalizedChildNodes = choiceNode.body(); + for (final NormalizedNode normalizedNode : normalizedChildNodes) { + addDataNodeFromNormalizedNode(currentDataNode, normalizedNode); + } + } + + } diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy index 690578ea05..358a6fb3f3 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy @@ -3,6 +3,7 @@ * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2021 Pantheon.tech * Modifications Copyright (C) 2020-2022 Bell Canada. + * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +31,8 @@ import org.onap.cps.spi.exceptions.SchemaSetInUseException import org.onap.cps.spi.utils.CpsValidator import org.onap.cps.spi.model.Anchor import org.onap.cps.spi.model.ModuleReference +import org.onap.cps.spi.model.SchemaSet +import org.onap.cps.yang.YangTextSchemaSourceSet import org.onap.cps.yang.YangTextSchemaSourceSetBuilder import spock.lang.Specification import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED @@ -91,6 +94,25 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet') } + def 'Get schema sets by dataspace name.'() { + given: 'two already present schema sets' + def moduleReference = new ModuleReference('sample1', '2022-12-07') + def sampleSchemaSet1 = new SchemaSet('testSchemaSet1', 'testDataspace', [moduleReference]) + def sampleSchemaSet2 = new SchemaSet('testSchemaSet2', 'testDataspace', [moduleReference]) + and: 'the persistence service returns the created schema sets' + mockCpsModulePersistenceService.getSchemaSetsByDataspaceName('testDataspace') >> [sampleSchemaSet1, sampleSchemaSet2] + and: 'yang resource cache always returns a schema source set' + def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet) + mockYangTextSchemaSourceSetCache.get('testDataspace', _) >> mockYangTextSchemaSourceSet + when: 'get schema sets method is invoked' + def result = objectUnderTest.getSchemaSets('testDataspace') + then: 'the correct schema sets are returned' + assert result.size() == 2 + assert result.containsAll(sampleSchemaSet1, sampleSchemaSet2) + and: 'the Cps Validator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('testDataspace') + } + def 'Delete schema-set when cascade is allowed.'() { given: '#numberOfAnchors anchors are associated with schemaset' def associatedAnchors = createAnchors(numberOfAnchors) diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy index fcfb4826d9..e46147c04d 100644 --- a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy @@ -32,7 +32,7 @@ import spock.lang.Specification class DataNodeBuilderSpec extends Specification { - Map<String, Map<String, Object>> expectedLeavesByXpathMap = [ + Map<String, Map<String, Serializable>> expectedLeavesByXpathMap = [ '/test-tree' : [], '/test-tree/branch[@name=\'Left\']' : [name: 'Left'], '/test-tree/branch[@name=\'Left\']/nest' : [name: 'Small', birds: ['Sparrow', 'Robin', 'Finch']], @@ -140,6 +140,25 @@ class DataNodeBuilderSpec extends Specification { assert result.leaves['source-tp'] == '1-2-1' } + def 'Converting NormalizedNode (tree) to a DataNode (tree) -- with ChoiceNode.'() { + given: 'a schema context for expected model' + def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('yang-with-choice-node.yang') + def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext() + and: 'the json data fragment parsed into normalized node object' + def jsonData = TestUtils.getResourceFileContent('data-with-choice-node.json') + def normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext) + when: 'the normalized node is converted to a data node' + def result = new DataNodeBuilder().withNormalizedNodeTree(normalizedNode).build() + def mappedResult = TestUtils.getFlattenMapByXpath(result) + then: 'the resulting data node contains only one xpath with 3 leaves' + mappedResult.keySet().containsAll([ + "/container-with-choice-leaves" + ]) + assert result.leaves['leaf-1'] == "test" + assert result.leaves['choice-case1-leaf-a'] == "test" + assert result.leaves['choice-case1-leaf-b'] == "test" + } + def 'Converting NormalizedNode into DataNode collection: #scenario.'() { given: 'a schema context for expected model' def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('test-tree.yang') diff --git a/cps-service/src/test/resources/data-with-choice-node.json b/cps-service/src/test/resources/data-with-choice-node.json new file mode 100644 index 0000000000..5f81ed8ed7 --- /dev/null +++ b/cps-service/src/test/resources/data-with-choice-node.json @@ -0,0 +1,8 @@ +{ + "container-with-choice-leaves": { + "leaf-1": "test", + "choice-case1-leaf-a": "test", + "choice-case1-leaf-b": "test" + } +} + diff --git a/cps-service/src/test/resources/yang-with-choice-node.yang b/cps-service/src/test/resources/yang-with-choice-node.yang new file mode 100644 index 0000000000..55c0bfbe62 --- /dev/null +++ b/cps-service/src/test/resources/yang-with-choice-node.yang @@ -0,0 +1,27 @@ +module yang-with-choice-node { + yang-version 1.1; + namespace "org:onap:cps:test:yang-with-choice-node"; + prefix "yang-with-choice-node"; + + container container-with-choice-leaves { + leaf leaf-1 { + type string; + } + + choice choicenode { + case case-1 { + leaf choice-case1-leaf-a { + type string; + } + leaf choice-case1-leaf-b { + type string; + } + } + case case-2 { + leaf choice-case2-leaf-a { + type string; + } + } + } + } +} diff --git a/csit/prepare-csit.sh b/csit/prepare-csit.sh index b56c3855dd..67412f3cf3 100755 --- a/csit/prepare-csit.sh +++ b/csit/prepare-csit.sh @@ -20,6 +20,8 @@ # Branched from ccsdk/distribution to this repository Feb 23, 2021 # +echo "---> prepare-csit.sh" + if [ -z "$WORKSPACE" ]; then export WORKSPACE=`git rev-parse --show-toplevel` fi @@ -35,11 +37,12 @@ if [ -f ${WORKSPACE}/env.properties ]; then fi if [ -f ${ROBOT3_VENV}/bin/activate ]; then source ${ROBOT3_VENV}/bin/activate -#else -# rm -rf /tmp/ci-management -# rm -f ${WORKSPACE}/env.properties -# cd /tmp -# source ${WORKSPACE}/install-robotframework.sh +else + rm -rf /tmp/ci-management + rm -f ${WORKSPACE}/env.properties + cd /tmp + git clone "https://gerrit.onap.org/r/ci-management" + source /tmp/ci-management/jjb/integration/include-raw-integration-install-robotframework-py3.sh fi # install eteutils diff --git a/csit/pylibs.txt b/csit/pylibs.txt index d6250dbab5..4952616540 100644 --- a/csit/pylibs.txt +++ b/csit/pylibs.txt @@ -5,7 +5,7 @@ netifaces pyhocon requests robotframework-httplibrary -robotframework-requests +robotframework-requests==0.9.3 robotframework-selenium2library robotframework-extendedselenium2library robotframework-sshlibrary diff --git a/csit/run-csit.sh b/csit/run-csit.sh index 25f5f6a77a..6703160a37 100755 --- a/csit/run-csit.sh +++ b/csit/run-csit.sh @@ -26,6 +26,8 @@ WORKDIR=$(mktemp -d --suffix=-robot-workdir) # functions # +echo "---> run-csit.sh" + # wrapper for sourcing a file function source_safely() { [ -z "$1" ] && return 1 diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index 8ea0d7b03e..09ccbe14a0 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -651,6 +651,69 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred + get: + tags: + - cps-admin + summary: Get schema sets for a given dataspace + description: "Read schema sets for a given dataspace" + operationId: getSchemaSets + parameters: + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SchemaSetDetails' + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 + message: Bad Request + details: The provided request is not valid + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized request + details: This request is unauthorized + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Request Forbidden + details: This request is forbidden + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred /v1/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}: get: tags: diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 6e6236b397..76e167f060 100755 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -39,6 +39,7 @@ Features -------- 3.2.1 - `CPS-1236 <https://jira.onap.org/browse/CPS-1236>`_ DMI audit support for NCMP: Filter on any properties of CM Handles + - `CPS-1187 <https://jira.onap.org/browse/CPS-1187>`_ Added API to get all schema sets for a given dataspace. 3.2.0 - `CPS-1185 <https://jira.onap.org/browse/CPS-1185>`_ Get all dataspaces - `CPS-1187 <https://jira.onap.org/browse/CPS-1187>`_ Get single dataspace |