diff options
author | 2025-02-11 18:44:48 +0000 | |
---|---|---|
committer | 2025-02-12 15:50:35 +0000 | |
commit | 61e1c70ebefc59356e8b6bf862ea2ba0b8e4efd9 (patch) | |
tree | 0e91ffce9d5c1fd80cfecda4e0d765936b46c46d | |
parent | ee4e49556be15ef5f881403f1cd70fab8daa68f4 (diff) |
Store yang resources with recommended RFC-6020 file-name
- Ignore input filename and create filename from module name and revision
- added integration test to verify names and edge cases (before and after change)
- Some code cleanup (vars etc)
- Implemented NB comments from last merge(https://gerrit.onap.org/r/c/cps/+/140180)
- fixed SQ warning
Out of scope:
- BLANK revision, test it but failed in ODL Yang Parser and many other places: not supported!
Issue-ID: CPS-138
Change-Id: I6fe6d0f8f3683196b183c6e6582ad8eefdfbb7d7
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
8 files changed, 86 insertions, 42 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java index dbc6c28ec5..412c6f9c0b 100755 --- a/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java @@ -24,6 +24,7 @@ package org.onap.cps.ri; import static com.google.common.base.Preconditions.checkNotNull; +import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_FILE_EXTENSION; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; @@ -253,25 +254,24 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ private static Map<String, YangResourceEntity> getYangResourceEntityPerChecksum( final Map<String, String> yangResourceContentPerName) { - final Map<String, YangResourceEntity> yangResourceEntityPerChecksum = - yangResourceContentPerName.entrySet().stream() - .map(entry -> { - final String checksum = DigestUtils.sha256Hex(entry.getValue().getBytes(StandardCharsets.UTF_8)); - final Map<String, String> moduleNameAndRevisionMap = createModuleNameAndRevisionMap(entry.getKey(), - entry.getValue()); - final YangResourceEntity yangResourceEntity = new YangResourceEntity(); - yangResourceEntity.setFileName(entry.getKey()); - yangResourceEntity.setContent(entry.getValue()); - yangResourceEntity.setModuleName(moduleNameAndRevisionMap.get("moduleName")); - yangResourceEntity.setRevision(moduleNameAndRevisionMap.get("revision")); - yangResourceEntity.setChecksum(checksum); - return yangResourceEntity; - }) - .collect(Collectors.toMap( - YangResourceEntity::getChecksum, - entity -> entity - )); - return yangResourceEntityPerChecksum; + return yangResourceContentPerName.entrySet().stream().map(entry -> { + final String checksum = DigestUtils.sha256Hex(entry.getValue().getBytes(StandardCharsets.UTF_8)); + final Map<String, String> moduleNameAndRevisionMap = createModuleNameAndRevisionMap(entry.getKey(), + entry.getValue()); + final YangResourceEntity yangResourceEntity = new YangResourceEntity(); + yangResourceEntity.setContent(entry.getValue()); + final String moduleName = moduleNameAndRevisionMap.get("moduleName"); + final String revision = moduleNameAndRevisionMap.get("revision"); + yangResourceEntity.setModuleName(moduleName); + yangResourceEntity.setRevision(revision); + yangResourceEntity.setFileName(moduleName + "@" + revision + RFC6020_YANG_FILE_EXTENSION); + yangResourceEntity.setChecksum(checksum); + return yangResourceEntity; + }) + .collect(Collectors.toMap( + YangResourceEntity::getChecksum, + entity -> entity + )); } private void createAndSaveSchemaSetEntity(final String dataspaceName, diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java index bf354be024..5563ba6d50 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java index 4ee6555b79..50c7494b29 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2025 Nordix Foundation. * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java index 3044fe0a90..30c8bbbdf3 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2024 Nordix Foundation + * Copyright (C) 2020-2025 Nordix Foundation * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ import org.onap.cps.api.parameters.PaginationOption; */ public interface CpsQueryService { - public static int NO_LIMIT = 0; + int NO_LIMIT = 0; /** * Get data nodes for the given dataspace and anchor by cps path. diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java index f27445f7c9..a3884820c7 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java @@ -52,12 +52,12 @@ public class CpsQueryServiceImpl implements CpsQueryService { @Override @Timed(value = "cps.data.service.datanode.query", description = "Time taken to query data nodes with a limit on results") - public Collection<DataNode> queryDataNodes(final String dataSpaceName, final String anchorName, + public Collection<DataNode> queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption, final int queryResultLimit) { - cpsValidator.validateNameCharacters(dataSpaceName, anchorName); - return cpsDataPersistenceService.queryDataNodes(dataSpaceName, + cpsValidator.validateNameCharacters(dataspaceName, anchorName); + return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption, diff --git a/cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java b/cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java index ab7a095572..04b491692a 100644 --- a/cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java +++ b/cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.NoArgsConstructor; @@ -77,7 +78,7 @@ public final class YangTextSchemaSourceSetBuilder { * @return the YangTextSchemaSourceSet */ public YangTextSchemaSourceSet build() { - final var schemaContext = generateSchemaContext(yangModelMap.build()); + final SchemaContext schemaContext = generateSchemaContext(yangModelMap.build()); return new YangTextSchemaSourceSetImpl(schemaContext); } @@ -113,9 +114,7 @@ public final class YangTextSchemaSourceSetBuilder { @Override public List<ModuleReference> getModuleReferences() { - return schemaContext.getModules().stream() - .map(YangTextSchemaSourceSetImpl::toModuleReference) - .collect(Collectors.toList()); + return schemaContext.getModules().stream().map(YangTextSchemaSourceSetImpl::toModuleReference).toList(); } private static ModuleReference toModuleReference(final Module module) { @@ -164,12 +163,11 @@ public final class YangTextSchemaSourceSetBuilder { private static List<YangTextSchemaSource> forResources(final Map<String, String> yangResourceNameToContent) { return yangResourceNameToContent.entrySet().stream() - .map(entry -> toYangTextSchemaSource(entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + .map(entry -> toYangTextSchemaSource(entry.getKey(), entry.getValue())).toList(); } private static YangTextSchemaSource toYangTextSchemaSource(final String sourceName, final String source) { - final var revisionSourceIdentifier = + final RevisionSourceIdentifier revisionSourceIdentifier = createIdentifierFromSourceName(checkNotNull(sourceName)); return new YangTextSchemaSource(revisionSourceIdentifier) { @@ -192,7 +190,7 @@ public final class YangTextSchemaSourceSetBuilder { } private static RevisionSourceIdentifier createIdentifierFromSourceName(final String sourceName) { - final var matcher = RFC6020_RECOMMENDED_FILENAME_PATTERN.matcher(sourceName); + final Matcher matcher = RFC6020_RECOMMENDED_FILENAME_PATTERN.matcher(sourceName); if (matcher.matches()) { return RevisionSourceIdentifier.create(matcher.group(1), Revision.of(matcher.group(2))); } 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 453dbca2bd..693cf992ee 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 @@ -48,6 +48,7 @@ import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher import org.onap.cps.ri.repository.DataspaceRepository import org.onap.cps.ri.repository.SchemaSetRepository import org.onap.cps.ri.utils.SessionManager +import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.utils.JsonObjectMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value @@ -101,6 +102,9 @@ abstract class CpsIntegrationSpecBase extends Specification { SessionManager sessionManager @Autowired + CpsModulePersistenceService cpsModulePersistenceService + + @Autowired DataspaceRepository dataspaceRepository @Autowired diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy index 49201e8f22..9a48dd72f3 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy @@ -21,8 +21,6 @@ package org.onap.cps.integration.functional.cps import org.onap.cps.api.CpsModuleService -import org.onap.cps.integration.base.FunctionalSpecBase -import org.onap.cps.api.parameters.CascadeDeleteAllowed import org.onap.cps.api.exceptions.AlreadyDefinedException import org.onap.cps.api.exceptions.DataspaceNotFoundException import org.onap.cps.api.exceptions.ModelValidationException @@ -30,6 +28,8 @@ import org.onap.cps.api.exceptions.SchemaSetInUseException import org.onap.cps.api.exceptions.SchemaSetNotFoundException import org.onap.cps.api.model.ModuleDefinition import org.onap.cps.api.model.ModuleReference +import org.onap.cps.api.parameters.CascadeDeleteAllowed +import org.onap.cps.integration.base.FunctionalSpecBase class ModuleServiceIntegrationSpec extends FunctionalSpecBase { @@ -132,7 +132,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema2', yangResourceContentPerName) then: 'the dataspace has no additional module (reference)' assert numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded == objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ 'newSchema1', 'newSchema2']) } @@ -216,6 +216,9 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { assert result.name == 'bookstoreSchemaSet' assert result.moduleReferences.size() == 2 assert result.moduleReferences.containsAll(bookStoreModuleReferenceWithNamespace, bookStoreTypesModuleReferenceWithNamespace) + and: 'the yang resource is stored with the normalized filename' + def fileName = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET).keySet()[0] + assert fileName == 'bookstore-types@2024-01-30.yang' } def 'Retrieve all schema sets.'() { @@ -227,10 +230,49 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { then: 'the result contains all expected schema sets' assert result.name.size() == 2 assert result.name.containsAll('bookstoreSchemaSet', 'newSchema1') - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema1']) } + def 'Create schema set with duplicate module filename [CPS-138].'() { + given: 'store the original number of sets and modules' + def numberOfSchemaSets = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).size() + def numberOfModuleReferences = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() + and: 'create a new schema set using a module with filename identical to a previously stored module (e.g. bookstore)' + populateYangResourceContentPerNameAndAllModuleReferences('otherModule', 1) + def otherModuleContent = yangResourceContentPerName.values()[0] + def mapWithDuplicateName = ['bookstore' : otherModuleContent] + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema', mapWithDuplicateName) + when: 'the yang resource details are retrieved' + def yangSchemaResources = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema') + then: 'the file name of the resource has been normalized' + def fileName = yangSchemaResources.keySet()[0] + assert fileName == 'otherModule_0@2000-01-01.yang' + and: 'the yang resource has the correct content' + assert yangSchemaResources.get(fileName) == otherModuleContent + and: 'the number of schema sets and modules has increased as expected' + assert objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).size() == numberOfSchemaSets + 1 + assert objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() == numberOfModuleReferences + 1 + cleanup: 'the data created in this test' + objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema']) + } + + def 'Create schema set with RFC-6020 filename pattern but incorrect details [CPS-138].'() { + given: 'create a new schema set using a module with filename identical to a previously stored module (e.g. bookstore)' + populateYangResourceContentPerNameAndAllModuleReferences('otherModule', 1) + def otherModuleContent = yangResourceContentPerName.values()[0] + def mapIncorrectName = ['wrongModuleAndRevision@1999-08-08.yang': otherModuleContent] + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema', mapIncorrectName) + when: 'the yang resource details are retrieved' + def yangSchemaResources = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema') + then: 'the file name of the resource has been normalized' + def fileName = yangSchemaResources.keySet()[0] + assert fileName == 'otherModule_0@2000-01-01.yang' + cleanup: 'the data created in this test' + objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema']) + } + + /* D E L E T E S C H E M A S E T U S E - C A S E S */ @@ -253,7 +295,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { then: 'check if the dataspace still contains the new schema set or not' def remainingSchemaSetNames = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).name assert remainingSchemaSetNames.contains('newSchemaSet') == expectSchemaSetStillPresent - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet']) where: 'the following options are used' associateWithAnchor | cascadeDeleteAllowedOption || expectSchemaSetStillPresent @@ -284,7 +326,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def remainingModuleRevisions = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).revision assert remainingModuleRevisions.contains('2000-01-01') assert !remainingModuleRevisions.contains('2001-01-01') - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet1']) } @@ -325,7 +367,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { assert yangResourceModuleReferencesAfterUpgrade.size() == 3 assert yangResourceModuleReferencesAfterUpgrade.contains(bookStoreModuleReference) assert yangResourceModuleReferencesAfterUpgrade.containsAll(newModuleReferences); - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['targetSchema']) } @@ -351,7 +393,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { and: 'the associated target anchor has the same module references (without namespace but that is a legacy issue)' def anchorModuleReferencesAfterUpgrade = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'targetAnchor') assert anchorModuleReferencesAfterUpgrade.containsAll([new ModuleReference('source_0','2000-01-01'),new ModuleReference('source_1','2001-01-01')]); - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['sourceSchema', 'targetSchema']) } |