Perf Test for Module Search is dependent on module size (CPS-2190 #1) 59/137759/3
authordanielhanrahan <daniel.hanrahan@est.tech>
Wed, 24 Apr 2024 13:15:47 +0000 (14:15 +0100)
committerdanielhanrahan <daniel.hanrahan@est.tech>
Thu, 25 Apr 2024 14:31:10 +0000 (15:31 +0100)
Add a new test showing that Yang module search is dependent on the
 file size of the Yang modules being searched for.

Issue-ID: CPS-2190
Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech>
Change-Id: I8fd28f4c91be11ef7428251397a887af17649015

integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy [new file with mode: 0644]

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
new file mode 100644 (file)
index 0000000..8609dd5
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  ============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.integration.performance.cps
+
+import org.onap.cps.integration.performance.base.CpsPerfTestBase
+import org.onap.cps.spi.model.ModuleReference
+
+class ModuleQueryPerfTest extends CpsPerfTestBase {
+
+    static final KILOBYTE = 1000
+    static final TOTAL_TEST_ANCHORS = 10_000
+    static final SCHEMA_SET_PREFIX = 'mySchemaSet'
+    static final ANCHOR_PREFIX = 'myAnchor'
+    static final MODULE_REVISION = '2024-04-25'
+    static final MODULE_TEMPLATE = """
+        module <MODULE_NAME> {
+            yang-version 1.1;
+            namespace "org:onap:cps:test:<MODULE_NAME>";
+            prefix tree;
+            revision "<MODULE_REVISION>" {
+                description "<DESCRIPTION>";
+            }
+            container tree {
+                list branch {
+                    key "name";
+                    leaf name {
+                        type string;
+                    }
+                }
+            }
+        }
+    """
+
+    def 'Module query - Preload test data (needed for other tests).'() {
+        given: 'a schema set with different sizes of Yang modules is created'
+            cpsModuleService.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, SCHEMA_SET_PREFIX + '0', [
+                    'module0.yang': makeYangModuleOfLength('module0', 1 * KILOBYTE),
+                    'module1.yang': makeYangModuleOfLength('module1', 1000 * KILOBYTE)
+            ])
+        and: 'these modules will be used again to create many schema sets'
+            def allModuleReferences = [
+                    new ModuleReference('module0', MODULE_REVISION),
+                    new ModuleReference('module1', MODULE_REVISION)
+            ]
+        when: 'many schema sets and anchors are created using those modules'
+            resourceMeter.start()
+            (1..TOTAL_TEST_ANCHORS).each {
+                def schemaSetName = SCHEMA_SET_PREFIX + it
+                def anchorName = ANCHOR_PREFIX + it
+                cpsModuleService.createSchemaSetFromModules(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetName, [:], allModuleReferences)
+                cpsAnchorService.createAnchor(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetName, anchorName)
+            }
+            resourceMeter.stop()
+        then: 'operation takes less than expected duration'
+            recordAndAssertResourceUsage('Module query test setup',
+                    45, resourceMeter.totalTimeInSeconds,
+                    500, resourceMeter.totalMemoryUsageInMB
+            )
+    }
+
+    def 'Bug CPS-2190: Querying anchors by module name IS dependant on the file size of the module.'() {
+        when: 'we search for anchors with given Yang module name'
+            resourceMeter.start()
+            def result = cpsAnchorService.queryAnchorNames(CPS_PERFORMANCE_TEST_DATASPACE, [yangModuleName])
+            resourceMeter.stop()
+        then: 'expected number of anchors is returned'
+            assert result.size() == TOTAL_TEST_ANCHORS
+        and: 'operation completes with expected resource usage'
+            recordAndAssertResourceUsage("Query for anchors with ${scenario}",
+                    expectedTimeInSeconds, resourceMeter.totalTimeInSeconds,
+                    300, resourceMeter.totalMemoryUsageInMB)
+        where: 'the following parameters are used'
+            scenario         | yangModuleName || expectedTimeInSeconds
+            '1 KB module'    | 'module0'      || 3
+            '1000 KB module' | 'module1'      || 12
+    }
+
+    def 'Module query - Clean up test data.'() {
+        cleanup:
+            // FIXME this API has extremely high memory usage, therefore external batching must be used
+            for (int i = 1; i <= TOTAL_TEST_ANCHORS; i += 100) {
+                cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, (i..i+100).collect {SCHEMA_SET_PREFIX + it})
+            }
+            cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, [SCHEMA_SET_PREFIX + '0'])
+    }
+
+    // This makes a Yang module of approximately target length in bytes by padding the description field with many '*'
+    private static def makeYangModuleOfLength(moduleName, targetLength) {
+        def padding = String.valueOf('*').repeat(targetLength - MODULE_TEMPLATE.size()) // not exact
+        return MODULE_TEMPLATE
+                .replaceAll('<MODULE_NAME>', moduleName)
+                .replaceAll('<MODULE_REVISION>', MODULE_REVISION)
+                .replaceAll('<DESCRIPTION>', padding)
+    }
+}