summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-rest/docs/openapi/cpsData.yml11
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java10
-rw-r--r--cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java2
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy23
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java2
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java7
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java5
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java4
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java7
-rw-r--r--cps-service/src/main/java/org/onap/cps/init/DbCleaner.java48
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy36
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy13
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/init/DbCleanerSpec.groovy38
-rw-r--r--docs/api/swagger/cps/openapi.yaml19
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy2
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy11
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy1
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy4
20 files changed, 222 insertions, 37 deletions
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
index daf59bbfbf..36000fd7d8 100644
--- a/cps-rest/docs/openapi/cpsData.yml
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -71,15 +71,24 @@ listElementByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
application/json:
schema:
- type: object
+ type: string
examples:
dataSample:
$ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
responses:
'200':
$ref: 'components.yml#/components/responses/Ok'
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index dda88e019c..3efb6b421c 100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -173,9 +173,11 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> replaceListContent(final String apiVersion, final String dataspaceName,
final String anchorName, final String parentNodeXpath,
- final Object jsonData, final String observedTimestamp) {
+ final String nodeData, final String observedTimestamp,
+ final String contentTypeInHeader) {
+ final ContentType contentType = ContentType.fromString(contentTypeInHeader);
cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@@ -225,10 +227,10 @@ public class DataRestController implements CpsDataApi {
return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaBetweenAnchors), HttpStatus.OK);
}
- ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataMaps,
+ private ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataMaps,
final ContentType contentType) {
final String responseData;
- if (contentType == ContentType.XML) {
+ if (ContentType.XML.equals(contentType)) {
responseData = XmlFileUtils.convertDataMapsToXml(dataMaps);
} else {
responseData = jsonObjectMapper.asJsonString(dataMaps);
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
index 55a1886ce7..ec71c30a75 100644
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
@@ -151,7 +151,7 @@ public class QueryRestController implements CpsQueryApi {
private ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataNodesAsListOfMaps,
final ContentType contentType) {
final String responseData;
- if (contentType == ContentType.XML) {
+ if (ContentType.XML.equals(contentType)) {
responseData = XmlFileUtils.convertDataMapsToXml(dataNodesAsListOfMaps);
} else {
responseData = jsonObjectMapper.asJsonString(dataNodesAsListOfMaps);
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
index 72ae4c7f91..892963c827 100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -576,7 +576,28 @@ class DataRestControllerSpec extends Specification {
response.status == expectedHttpStatus.value()
and: 'the java API was called with the correct parameters'
expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
+ where:
+ scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
+ 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.OK
+ 'without observed-timestamp' | null || 1 | HttpStatus.OK
+ 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
+ }
+
+ def 'Replace list XML content #scenario.'() {
+ when: 'list-nodes endpoint is invoked with put (update) operation'
+ def putRequestBuilder = put("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes")
+ .contentType(MediaType.APPLICATION_XML)
+ .param('xpath', 'parent xpath')
+ .content(requestBodyXml)
+ if (observedTimestamp != null)
+ putRequestBuilder.param('observed-timestamp', observedTimestamp)
+ def response = mvc.perform(putRequestBuilder).andReturn().response
+ then: 'a success response is returned'
+ response.status == expectedHttpStatus.value()
+ and: 'the java API was called with the correct parameters'
+ expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedXmlData,
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.XML)
where:
scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.OK
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 3368aee148..e5853abf39 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
@@ -230,8 +230,6 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
updateAllModuleReferences(allModuleReferences, schemaSetEntity.getId());
}
-
-
@Override
@Transactional
public void deleteUnusedYangResourceModules() {
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index b3eff8eb26..29c8ad0168 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -172,11 +172,12 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath parent node xpath
- * @param jsonData json data representing the new list elements
+ * @param nodeData node data representing the new list elements
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void replaceListContent(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void replaceListContent(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces list content by removing all existing elements and inserting the given new elements as data 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 bbfe496d85..304ed288f5 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
@@ -188,4 +188,9 @@ public interface CpsModuleService {
final Map<String, String> parentAttributes,
final Map<String, String> childAttributes);
+ /**
+ * Remove any Yang Resource Modules from the DB that are no longer referenced by any schema set.
+ */
+ void deleteUnusedYangResourceModules();
+
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index b1b545be68..a63b3e5360 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -281,11 +281,11 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.list.update",
description = "Time taken to update a list")
public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath,
- final String jsonData, final OffsetDateTime observedTimestamp) {
+ final String nodeData, final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> newListElements =
- buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements, observedTimestamp);
}
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 4063a7f769..9f3f2cc571 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
@@ -106,7 +106,6 @@ public class CpsModuleServiceImpl implements CpsModuleService {
}
cpsModulePersistenceService.deleteSchemaSet(dataspaceName, schemaSetName);
yangTextSchemaSourceSetCache.removeFromCache(dataspaceName, schemaSetName);
- cpsModulePersistenceService.deleteUnusedYangResourceModules();
}
@Override
@@ -119,7 +118,6 @@ public class CpsModuleServiceImpl implements CpsModuleService {
.stream().map(Anchor::getName).collect(Collectors.toSet());
cpsAnchorService.deleteAnchors(dataspaceName, anchorNames);
cpsModulePersistenceService.deleteSchemaSets(dataspaceName, schemaSetNames);
- cpsModulePersistenceService.deleteUnusedYangResourceModules();
for (final String schemaSetName : schemaSetNames) {
yangTextSchemaSourceSetCache.removeFromCache(dataspaceName, schemaSetName);
}
@@ -182,6 +180,11 @@ public class CpsModuleServiceImpl implements CpsModuleService {
childAttributes);
}
+ @Override
+ public void deleteUnusedYangResourceModules() {
+ cpsModulePersistenceService.deleteUnusedYangResourceModules();
+ }
+
private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) {
return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed;
}
diff --git a/cps-service/src/main/java/org/onap/cps/init/DbCleaner.java b/cps-service/src/main/java/org/onap/cps/init/DbCleaner.java
new file mode 100644
index 0000000000..6bd3e1f204
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/init/DbCleaner.java
@@ -0,0 +1,48 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 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.init;
+
+import java.util.concurrent.TimeUnit;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.api.CpsModuleService;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class DbCleaner {
+
+ private final CpsModuleService cpsModuleService;
+
+ /**
+ * This method will clean up the db during application start up.
+ * It wil run once and currently only removes unused yang resource modules.
+ *
+ */
+ @Scheduled(initialDelay = 1, timeUnit = TimeUnit.SECONDS)
+ public void cleanDbAtStartUp() {
+ log.info("CPS Application started, commencing DB clean up");
+ cpsModuleService.deleteUnusedYangResourceModules();
+ log.info("DB clean up completed");
+ }
+}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index 8c208a1cf8..1543fb931b 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -448,12 +448,12 @@ class CpsDataServiceImplSpec extends Specification {
assert thrownUp == originalException
}
- def 'Replace list content data fragment under parent node.'() {
+ def 'Replace list content data fragment JSON under parent node.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace list data method is invoked with list element json data'
def jsonData = '{"branch": [{"name": "A"}, {"name": "B"}]}'
- objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, '/test-tree',
{ dataNodeCollection ->
@@ -468,12 +468,42 @@ class CpsDataServiceImplSpec extends Specification {
2 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
}
+ def 'Replace list content data fragment XML under parent node.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace list data method is invoked with list element xml data'
+ def nodeData = '<branch><name>A</name></branch>'
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', nodeData, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, '/test-tree',
+ { dataNodeCollection ->
+ {
+ assert dataNodeCollection.size() == 1
+ assert dataNodeCollection.collect { it.getXpath() }
+ .containsAll(['/test-tree/branch[@name=\'A\']'])
+ }
+ }
+ )
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName twice'
+ 2 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ }
+
def 'Replace whole list content with empty list element.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace list data method is invoked with empty list'
def jsonData = '{"branch": []}'
- objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp, ContentType.JSON)
+ then: 'invalid data exception is thrown'
+ thrown(DataValidationException)
+ }
+
+ def 'Replace whole list content XML with empty list element.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace list data method is invoked with xml empty list'
+ def nodeData = '[]'
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', nodeData, observedTimestamp, ContentType.XML)
then: 'invalid data exception is thrown'
thrown(DataValidationException)
}
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 1831506563..c02b06fd80 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
@@ -142,8 +142,6 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsModulePersistenceService.deleteSchemaSet('my-dataspace', 'my-schemaset')
and: 'schema set will be removed from the cache'
1 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', 'my-schemaset')
- and: 'orphan yang resources are deleted'
- 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules()
and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
1 * mockCpsValidator.validateNameCharacters('my-dataspace', _)
where: 'following parameters are used'
@@ -161,8 +159,6 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsModulePersistenceService.deleteSchemaSet('my-dataspace', 'my-schemaset')
and: 'schema set will be removed from the cache'
1 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', 'my-schemaset')
- and: 'orphan yang resources are deleted'
- 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules()
and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset')
}
@@ -187,8 +183,6 @@ class CpsModuleServiceImplSpec extends Specification {
mockCpsModulePersistenceService.deleteSchemaSets('my-dataspace', _)
and: 'schema sets will be removed from the cache'
2 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', _)
- and: 'orphan yang resources are deleted'
- 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules()
and: 'the CpsValidator is called on the dataspaceName'
1 * mockCpsValidator.validateNameCharacters('my-dataspace')
and: 'the CpsValidator is called on the schemaSetNames'
@@ -276,6 +270,13 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name')
}
+ def 'Delete unused yang resource modules.'() {
+ when: 'deleting unused yang resource modules'
+ objectUnderTest.deleteUnusedYangResourceModules()
+ then: 'it is delegated to the module persistence service'
+ 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules()
+ }
+
def getModuleReferences() {
return [new ModuleReference('some module name','some revision name')]
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/init/DbCleanerSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/DbCleanerSpec.groovy
new file mode 100644
index 0000000000..5106d29fa5
--- /dev/null
+++ b/cps-service/src/test/groovy/org/onap/cps/init/DbCleanerSpec.groovy
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 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.init
+
+import org.onap.cps.api.CpsModuleService
+import spock.lang.Specification
+
+class DbCleanerSpec extends Specification {
+
+ def mockCpsModuleService = Mock(CpsModuleService)
+
+ def objectUnderTest = new DbCleaner(mockCpsModuleService)
+
+ def 'DB clean up.'() {
+ when: 'scheduled method is triggered'
+ objectUnderTest.cleanDbAtStartUp()
+ then: 'the unused yang resource modules are deleted'
+ 1 * mockCpsModuleService.deleteUnusedYangResourceModules()
+ }
+}
diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml
index 812a2e4e60..fea68480ab 100644
--- a/docs/api/swagger/cps/openapi.yaml
+++ b/docs/api/swagger/cps/openapi.yaml
@@ -1927,6 +1927,16 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: false
+ schema:
+ default: application/json
+ enum:
+ - application/json
+ - application/xml
+ type: string
requestBody:
content:
application/json:
@@ -1935,7 +1945,16 @@ paths:
$ref: '#/components/examples/dataSample'
value: null
schema:
+ type: string
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/dataSampleXml'
+ value: null
+ schema:
type: object
+ xml:
+ name: stores
required: true
responses:
"200":
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
index d49931eb7e..6c68a37f81 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
@@ -310,9 +310,9 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Attempt to add empty lists.'() {
when: 'the batches of new list element(s) are saved'
- objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', [ ], now)
- then: 'an admin exception is thrown'
- thrown(CpsAdminException)
+ objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', [ ] as String, now, ContentType.JSON)
+ then: 'an data exception is thrown'
+ thrown(DataValidationException)
}
def 'Add child error scenario: #scenario.'() {
@@ -344,7 +344,7 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
assert countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="2"]', DIRECT_CHILDREN_ONLY)) > 1
when: 'the categories list is replaced with just category "1" and without child nodes (books)'
def json = '{"categories": [ {"code":"' +categoryCode + '"' + childJson + '} ] }'
- objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now)
+ objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now, ContentType.JSON)
then: 'the new replaced category can be retrieved but has no children anymore'
assert expectedNumberOfDataNodes == countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="' +categoryCode + '"]', DIRECT_CHILDREN_ONLY))
when: 'attempt to retrieve a category (code) not in the new list'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy
index d69f6cca0c..f20e4e5cad 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy
@@ -32,6 +32,8 @@ class DataspaceServiceIntegrationSpec extends FunctionalSpecBase {
def setup() { objectUnderTest = cpsDataspaceService }
+ def cleanup() { cpsModuleService.deleteUnusedYangResourceModules() }
+
def 'Dataspace CRUD operations.'() {
when: 'a dataspace is created'
objectUnderTest.createDataspace('newDataspace')
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 9e51d80d9e..a50a59a3d7 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
@@ -59,9 +59,9 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase {
def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
- def setup() {
- objectUnderTest = cpsModuleService
- }
+ def setup() { objectUnderTest = cpsModuleService }
+
+ def cleanup() { objectUnderTest.deleteUnusedYangResourceModules() }
/*
C R E A T E S C H E M A S E T U S E - C A S E S
@@ -77,7 +77,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase {
originalNumberOfModuleReferences + numberOfNewModules == yangResourceModuleReferences.size()
cleanup:
objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ 'newSchemaSet' ])
- where: 'the following parameters are use'
+ where: 'the following parameters are used'
scenario | numberOfNewModules
'two valid new modules' | 2
'empty schema set' | 0
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy
index 20fa546eba..43bcbdb4f4 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy
@@ -24,6 +24,7 @@ import io.micrometer.core.instrument.MeterRegistry
import org.onap.cps.integration.base.CpsIntegrationSpecBase
import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncWatchdog
import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.util.StopWatch
import spock.util.concurrent.PollingConditions
import java.util.concurrent.Executors
@@ -61,12 +62,13 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase {
assert moduleSyncWorkQueue.isEmpty()
}
- def 'CPS-2478 Highlight module sync inefficiencies.'() {
+ def 'CPS-2478 Highlight (and improve) module sync inefficiencies.'() {
given: 'register 250 cm handles with module set tag cps-2478-A'
def numberOfTags = 2
def cmHandlesPerTag = 250
def totalCmHandles = numberOfTags * cmHandlesPerTag
def offset = 1
+ def minimumBatches = totalCmHandles / 100
registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'cps-2478-A', cmHandlesPerTag, offset)
and: 'register anther 250 cm handles with module set tag cps-2478-B'
offset += cmHandlesPerTag
@@ -86,7 +88,7 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase {
then: 'wait till at least 5 batches of state updates are done (often more because of retries of locked cm handles)'
def dbStateUpdateTimer = meterRegistry.get('cps.ncmp.cmhandle.state.update.batch').timer()
new PollingConditions().within(10, () -> {
- assert dbStateUpdateTimer.count() >= 5
+ assert dbStateUpdateTimer.count() >= minimumBatches
})
and: 'the db has been queried for tags exactly 2 times.'
def dbModuleQueriesTimer = meterRegistry.get('cps.module.service.module.reference.query.by.attribute').timer()
@@ -100,7 +102,12 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase {
logInstrumentation(dbSchemaSetStorageTimer, 'store schema sets ')
logInstrumentation(dbStateUpdateTimer, 'batch state updates ')
cleanup: 'remove all cm handles'
+ // To properly measure performance the sample-size should be increased to 20,000 cm handles or higher (10,000 per tag)
+ def stopWatch = new StopWatch()
+ stopWatch.start()
deregisterSequenceOfCmHandles(DMI1_URL, totalCmHandles, 1)
+ stopWatch.stop()
+ println "*** CPS-2478, Deletion of $totalCmHandles cm handles took ${stopWatch.getTotalTimeMillis()} milliseconds"
}
def 'Populate module sync work queue simultaneously on two parallel threads (CPS-2403).'() {
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy
index add931a1ad..914f2030cc 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy
@@ -100,6 +100,7 @@ class ModuleQueryPerfTest extends CpsPerfTestBase {
cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, (i..i+100).collect {SCHEMA_SET_PREFIX + it})
}
cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, [SCHEMA_SET_PREFIX + '0'])
+ cpsModuleService.deleteUnusedYangResourceModules()
}
// This makes a Yang module of approximately target length in bytes by padding the description field with many '*'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
index 03abdb4b3f..d764029f02 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
@@ -94,7 +94,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def jsonListData = generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves)
when: 'the container node is updated'
resourceMeter.start()
- objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
+ objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now, ContentType.JSON)
resourceMeter.stop()
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
@@ -118,7 +118,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def 'Update leaves for 100 data nodes.'() {
given: 'there are 200 existing data nodes'
def jsonListData = generateJsonForOpenRoadmDevices(1, 200, false)
- objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
+ objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now, ContentType.JSON)
and: 'JSON for updated data leaves of 100 nodes'
def jsonDataUpdated = "{'openroadm-device':[" + (1..100).collect {"{'device-id':'C201-7-1A-" + it + "','status':'fail','ne-state':'jeopardy'}" }.join(",") + "]}"
when: 'update is performed for leaves'