From 44c6a30265dcdc71edccc666bd3ff4ba47cdb895 Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Wed, 3 Sep 2025 23:20:01 -0400 Subject: [PATCH 1/5] DAOS-17960 test: Support generating a functional test summary Stash details.json files generated by launch.py in functional test stages and support running a script that will summarize all these files. Signed-off-by: Phil Henderson --- vars/functionalTest.groovy | 4 ++ vars/getFunctionalTestStage.groovy | 4 +- vars/runScriptWithStashes.groovy | 76 ++++++++++++++++++++++++++++++ vars/runTestFunctionalV2.groovy | 8 ++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 vars/runScriptWithStashes.groovy diff --git a/vars/functionalTest.groovy b/vars/functionalTest.groovy index aa7b949d3..a3e58e9f9 100755 --- a/vars/functionalTest.groovy +++ b/vars/functionalTest.groovy @@ -59,6 +59,8 @@ * * config['ftest_arg'] Functional test launch.py arguments. * Default determined by parseStageInfo(). + * + * config['details_stash'] Stash name for functional test details. */ Map call(Map config = [:]) { @@ -113,6 +115,8 @@ Map call(Map config = [:]) { run_test_config['ftest_arg'] = config.get('ftest_arg', stage_info['ftest_arg']) run_test_config['context'] = context run_test_config['description'] = description + run_test_config['details_stash'] = config.get( + 'details_stash', 'func' + stage_info['pragma_suffix'] + '-details') String script = 'if ! pip3 install' script += ''' --upgrade --upgrade-strategy only-if-needed launchable; then diff --git a/vars/getFunctionalTestStage.groovy b/vars/getFunctionalTestStage.groovy index 47055feef..a2a336fbb 100644 --- a/vars/getFunctionalTestStage.groovy +++ b/vars/getFunctionalTestStage.groovy @@ -42,6 +42,7 @@ Map call(Map kwargs = [:]) { Boolean run_if_pr = kwargs.get('run_if_pr', false) Boolean run_if_landing = kwargs.get('run_if_landing', false) Map job_status = kwargs.get('job_status', [:]) + String details_stash = kwargs.get('details_stash', '') return { stage("${name}") { @@ -89,7 +90,8 @@ Map call(Map kwargs = [:]) { nvme: nvme, default_nvme: default_nvme, provider: provider)['ftest_arg'], - test_function: 'runTestFunctionalV2')) + test_function: 'runTestFunctionalV2', + details_stash: details_stash)) } finally { println("[${name}] Running functionalTestPostV2()") functionalTestPostV2() diff --git a/vars/runScriptWithStashes.groovy b/vars/runScriptWithStashes.groovy new file mode 100644 index 000000000..b95f2752f --- /dev/null +++ b/vars/runScriptWithStashes.groovy @@ -0,0 +1,76 @@ +// vars/runScriptWithStashes.groovy + +/** + * // vars/runScriptWithStashes.groovy + * + * Run a shell script with access to specified stashes. + * + * @param kwargs Map containing the following optional arguments (empty strings yield defaults): + * stashes list of stash names to access during script execution + * script shell script to run + * label label to use when running the script + */ + Map call(Map kwargs = [:]) { + Date startDate = new Date() + List stashes = kwargs.get('stashes', []) + String script = kwargs.get('script', '') + String label = kwargs.get('label', "Run ${script} with stashes") + + Integer stash_count = 0 + stashes.each { stash -> + try { + unstash stash + println("Successfully unstashed ${stash}.") + stash_count++ + /* groovylint-disable-next-line CatchException */ + } catch (Exception ex) { + println("Ignoring failure to unstash ${stash}. Perhaps the stage was skipped?") + } + } + + Integer return_code = 255 + if (!script) { + // Nothing to do if no stash exist + println('No script provided, skipping execution') + return_code = 0 + } else if (stash_count < 1) { + // Nothing to do if no stash exist + println('No code coverage stashes found, skipping merged code coverage report') + return_code = 0 + } else { + // Run the script + try { + sh(script: script, label: label) + return_code = 0 + } catch (hudson.AbortException e) { + // groovylint-disable UnnecessaryGetter + // groovylint-disable-next-line NoDef, VariableTypeRequired + def rc_val = (e.getMessage() =~ /\d+$/) + if (rc_val) { + return_code = rc_val[0] as Integer + } + } + } + + // Generate a result for the stage + Date endDate = new Date() + Integer runTime = durationSeconds(startDate, endDate) + String status = 'SUCCESS' + if (return_code != 0) { + status = 'FAILURE' + } + Map results = ['result_code': return_code, + 'result': status, + 'start_date': startDate, + 'end_date': endDate, + 'runtest_time': runTime] + + String results_map = 'results_map_' + sanitizedStageName() + writeYaml file: results_map, + data: results, + overwrite: true + stash name: results_map, + includes: results_map + + return results + } \ No newline at end of file diff --git a/vars/runTestFunctionalV2.groovy b/vars/runTestFunctionalV2.groovy index 3acfb43bf..b89d588e6 100644 --- a/vars/runTestFunctionalV2.groovy +++ b/vars/runTestFunctionalV2.groovy @@ -97,5 +97,13 @@ Map call(Map config = [:]) { String name = 'func' + stage_info['pragma_suffix'] + '-cov' stash name: config.get('coverage_stash', name), includes: covfile + + if (config['details_stash']) { + // Stash the launch.py generated details.json for the functional test stage + stash name: config['details_stash'], + includes: '**/launch/functional_*/details.json', + allowEmptyArchive: true + } + return runData } From c95bdd02ebf8f4562a161f6d812e09f03cfd7d60 Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Thu, 4 Sep 2025 00:16:24 -0400 Subject: [PATCH 2/5] Adding vars/getSummaryStage.groovy Signed-off-by: Phil Henderson --- vars/getSummaryStage.groovy | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 vars/getSummaryStage.groovy diff --git a/vars/getSummaryStage.groovy b/vars/getSummaryStage.groovy new file mode 100644 index 000000000..fba3ce58c --- /dev/null +++ b/vars/getSummaryStage.groovy @@ -0,0 +1,56 @@ +// vars/getSummaryStage.groovy + +/** + * getSummaryStage.groovy + * + * Get a functional test stage in scripted syntax. + * + * @param kwargs Map containing the following optional arguments (empty strings yield defaults): + * name name of the stage + * docker_filename docker filename + * script_stashes list of stash names to access with runScriptWithStashes + * script_name shell script to run with runScriptWithStashes + * script_label label to use when running the script in runScriptWithStashes + * artifacts artifacts to archive + * job_status Map of status for each stage in the job/build + * @return a scripted stage to run in a pipeline + */ + +List call(Map kwargs = [:]) { + String name = kwargs.get('name', 'Unknown Summary Stage') + String docker_filename = kwargs.get('docker_filename', 'utils/docker/Dockerfile.el.8') + List script_stashes = kwargs.get('script_stashes', []) + String script_name = kwargs.get('script_name', 'ci/functional_test_summary.sh') + String script_label = kwargs.get('script_label', 'Generate Functional Test Summary') + String artifacts = kwargs.get('artifacts', 'unknown_test_summary/*') + Map job_status = kwargs.get('job_status', [:]) + + return { + stage("${name}") { + agent { + dockerfile { + filename docker_filename + label 'docker_runner' + additionalBuildArgs dockerBuildArgs(add_repos: false) + } + try { + job_step_update( + job_status, + name, + runScriptWithStashes( + stashes: script_stashes, + script: script_name, + label: script_label + ) + ) + } + finally { + always { + archiveArtifacts(artifacts: artifacts, allowEmptyArchive: false) + job_status_update(job_status, name) + } + } + } + } + } +} From b5bcce33c9806e30f96a9e5fbf4c32eb089121b1 Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Tue, 9 Sep 2025 22:10:47 -0400 Subject: [PATCH 3/5] Small fixes. Signed-off-by: Phil Henderson --- vars/runScriptWithStashes.groovy | 2 +- vars/runTestFunctionalV2.groovy | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/vars/runScriptWithStashes.groovy b/vars/runScriptWithStashes.groovy index b95f2752f..097b0275c 100644 --- a/vars/runScriptWithStashes.groovy +++ b/vars/runScriptWithStashes.groovy @@ -73,4 +73,4 @@ includes: results_map return results - } \ No newline at end of file +} diff --git a/vars/runTestFunctionalV2.groovy b/vars/runTestFunctionalV2.groovy index b89d588e6..f44eb64d8 100644 --- a/vars/runTestFunctionalV2.groovy +++ b/vars/runTestFunctionalV2.groovy @@ -101,8 +101,7 @@ Map call(Map config = [:]) { if (config['details_stash']) { // Stash the launch.py generated details.json for the functional test stage stash name: config['details_stash'], - includes: '**/launch/functional_*/details.json', - allowEmptyArchive: true + includes: '**/launch/functional_*/details.json' } return runData From 808abc62df65988c0408c0ed53bb84f737905208 Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Tue, 16 Sep 2025 18:45:20 -0400 Subject: [PATCH 4/5] Fix stash. Signed-off-by: Phil Henderson --- vars/runTestFunctionalV2.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars/runTestFunctionalV2.groovy b/vars/runTestFunctionalV2.groovy index f44eb64d8..28136f9bf 100644 --- a/vars/runTestFunctionalV2.groovy +++ b/vars/runTestFunctionalV2.groovy @@ -101,7 +101,7 @@ Map call(Map config = [:]) { if (config['details_stash']) { // Stash the launch.py generated details.json for the functional test stage stash name: config['details_stash'], - includes: '**/launch/functional_*/details.json' + includes: '**/details.json' } return runData From 0488bafbb94659759c9b2d4329db7c6639c951cb Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Mon, 6 Oct 2025 15:59:47 +0000 Subject: [PATCH 5/5] Move details.json stash to runTest.groovy Signed-off-by: Phil Henderson --- vars/functionalTest.groovy | 2 +- vars/getFunctionalTestStage.groovy | 1 + vars/runTest.groovy | 8 ++++++++ vars/runTestFunctionalV2.groovy | 8 ++------ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/vars/functionalTest.groovy b/vars/functionalTest.groovy index a3e58e9f9..e50f9508a 100755 --- a/vars/functionalTest.groovy +++ b/vars/functionalTest.groovy @@ -60,7 +60,7 @@ * config['ftest_arg'] Functional test launch.py arguments. * Default determined by parseStageInfo(). * - * config['details_stash'] Stash name for functional test details. + * config['details_stash'] Stash name for functional test details. */ Map call(Map config = [:]) { diff --git a/vars/getFunctionalTestStage.groovy b/vars/getFunctionalTestStage.groovy index a2a336fbb..839b28a31 100644 --- a/vars/getFunctionalTestStage.groovy +++ b/vars/getFunctionalTestStage.groovy @@ -23,6 +23,7 @@ import org.jenkinsci.plugins.pipeline.modeldefinition.Utils * run_if_pr whether or not the stage should run for PR builds * run_if_landing whether or not the stage should run for landing builds * job_status Map of status for each stage in the job/build + * details_stash Stash name for functional test details. * @return a scripted stage to run in a pipeline */ Map call(Map kwargs = [:]) { diff --git a/vars/runTest.groovy b/vars/runTest.groovy index 91b590b65..24b9668e5 100644 --- a/vars/runTest.groovy +++ b/vars/runTest.groovy @@ -38,6 +38,8 @@ Map call(Map config = [:]) { * * config['description'] Description to report for SCM status. * Default env.STAGE_NAME. + * + * config['details_stash'] Stash name for functional test details. */ // Todo @@ -140,6 +142,12 @@ Map call(Map config = [:]) { Date endDate = new Date() int runTime = durationSeconds(startDate, endDate) + if (config['details_stash']) { + // Stash the launch.py generated details.json for the functional test stage + stash name: config['details_stash'], + includes: '**/details.json' + } + // We need to pass the rc to the post step. Map results = ['result_code': rc, 'result': status, diff --git a/vars/runTestFunctionalV2.groovy b/vars/runTestFunctionalV2.groovy index 28136f9bf..3818952e4 100644 --- a/vars/runTestFunctionalV2.groovy +++ b/vars/runTestFunctionalV2.groovy @@ -39,6 +39,8 @@ Map call(Map config = [:]) { * * config['description'] Description to report for SCM status. * Default env.STAGE_NAME. + * + * config['details_stash'] Stash name for functional test details. */ Map stage_info = parseStageInfo(config) @@ -98,11 +100,5 @@ Map call(Map config = [:]) { stash name: config.get('coverage_stash', name), includes: covfile - if (config['details_stash']) { - // Stash the launch.py generated details.json for the functional test stage - stash name: config['details_stash'], - includes: '**/details.json' - } - return runData }