aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToineSiebelink <toine.siebelink@est.tech>2025-02-11 18:44:48 +0000
committerToineSiebelink <toine.siebelink@est.tech>2025-02-12 15:50:35 +0000
commit61e1c70ebefc59356e8b6bf862ea2ba0b8e4efd9 (patch)
tree0e91ffce9d5c1fd80cfecda4e0d765936b46c46d
parentee4e49556be15ef5f881403f1cd70fab8daa68f4 (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>
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java38
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java2
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java4
-rw-r--r--cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java6
-rw-r--r--cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java14
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy58
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'])
}