diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-03-14 15:52:54 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-03-14 15:52:54 -0400 |
commit | 4e1492f0fa3a48e5fa88d8623e47e50bb8527c87 (patch) | |
tree | 04198e99f40355cdd2644884bd8ca2b33f832069 | |
parent | 7656ed0e011f910b84131360cc82e335f01913db (diff) | |
download | stasis-4e1492f0fa3a48e5fa88d8623e47e50bb8527c87.tar.gz |
Pretty-print pytest xml results (if xmllint is present)
* Adds Delivery.storage.results_dir member
* Exposes storage.results_dir to templates
* This is to make the test results human-readable
* xmllint is optional. If it isn't installed it isn't a big deal.
-rw-r--r-- | include/deliverable.h | 3 | ||||
-rw-r--r-- | include/utils.h | 11 | ||||
-rw-r--r-- | src/deliverable.c | 31 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/utils.c | 58 |
5 files changed, 106 insertions, 0 deletions
diff --git a/include/deliverable.h b/include/deliverable.h index 0aad8ab..fda3c94 100644 --- a/include/deliverable.h +++ b/include/deliverable.h @@ -54,6 +54,7 @@ struct Delivery { char *tools_dir; ///< Tools storage char *mission_dir; ///< Mission data storage char *package_dir; ///< Base path to where all packages are stored + char *results_dir; ///< Base path to where test results are stored char *conda_install_prefix; ///< Path to install Conda char *conda_artifact_dir; ///< Base path to store compiled conda packages char *conda_staging_dir; ///< Base path to copy compiled conda packages @@ -362,4 +363,6 @@ int delivery_artifact_upload(struct Delivery *ctx); int delivery_mission_render_files(struct Delivery *ctx); int delivery_docker(struct Delivery *ctx); + +int delivery_fixup_test_results(struct Delivery *ctx); #endif //OMC_DELIVERABLE_H diff --git a/include/utils.h b/include/utils.h index 71d3f8b..b03d99e 100644 --- a/include/utils.h +++ b/include/utils.h @@ -22,6 +22,9 @@ #define LINE_SEP "\n" #endif +#define OMC_XML_PRETTY_PRINT_PROG "xmllint" +#define OMC_XML_PRETTY_PRINT_ARGS "--format" + typedef int (ReaderFn)(size_t line, char **); /** @@ -243,4 +246,12 @@ char *xmkstemp(FILE **fp, const char *mode); */ int isempty_dir(const char *path); +/** + * Rewrite an XML file with a pretty printer command + * @param filename path to modify + * @param pretty_print_prog program to call + * @param pretty_print_args arguments to pass to program + * @return 0 on success, -1 on error + */ +int xml_pretty_print_in_place(const char *filename, const char *pretty_print_prog, const char *pretty_print_args); #endif //OMC_UTILS_H diff --git a/src/deliverable.c b/src/deliverable.c index efcfd43..f926724 100644 --- a/src/deliverable.c +++ b/src/deliverable.c @@ -1678,4 +1678,35 @@ int delivery_docker(struct Delivery *ctx) { } return 0; +} + +int delivery_fixup_test_results(struct Delivery *ctx) { + struct dirent *rec; + DIR *dp; + + dp = opendir(ctx->storage.results_dir); + if (!dp) { + perror(ctx->storage.results_dir); + return -1; + } + + while ((rec = readdir(dp)) != NULL) { + char path[PATH_MAX]; + memset(path, 0, sizeof(path)); + + if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) { + continue; + } else if (!endswith(rec->d_name, ".xml")) { + continue; + } + + sprintf(path, "%s/%s", ctx->storage.results_dir, rec->d_name); + msg(OMC_MSG_L2, "%s\n", rec->d_name); + if (xml_pretty_print_in_place(path, OMC_XML_PRETTY_PRINT_PROG, OMC_XML_PRETTY_PRINT_ARGS)) { + msg(OMC_MSG_L3 | OMC_MSG_WARN, "Failed to rewrite file '%s'\n", rec->d_name); + } + } + + closedir(dp); + return 0; }
\ No newline at end of file @@ -244,6 +244,7 @@ int main(int argc, char *argv[], char *arge[]) { tpl_register("storage.wheel_artifact_dir", &ctx.storage.wheel_artifact_dir); tpl_register("storage.build_sources_dir", &ctx.storage.build_sources_dir); tpl_register("storage.build_docker_dir", &ctx.storage.build_docker_dir); + tpl_register("storage.results_dir", &ctx.storage.results_dir); tpl_register("conda.installer_baseurl", &ctx.conda.installer_baseurl); tpl_register("conda.installer_name", &ctx.conda.installer_name); tpl_register("conda.installer_version", &ctx.conda.installer_version); @@ -410,6 +411,8 @@ int main(int argc, char *argv[], char *arge[]) { if (globals.enable_testing) { msg(OMC_MSG_L1, "Begin test execution\n"); delivery_tests_run(&ctx); + msg(OMC_MSG_L1, "Rewriting test results\n"); + delivery_fixup_test_results(&ctx); } else { msg(OMC_MSG_L1 | OMC_MSG_WARN, "Test execution is disabled\n"); } diff --git a/src/utils.c b/src/utils.c index 62bf58a..047a266 100644 --- a/src/utils.c +++ b/src/utils.c @@ -532,4 +532,62 @@ int path_store(char **destptr, size_t maxlen, const char *base, const char *path l_path_setup_error: guard_free(path_tmp); return -1; +} + +int xml_pretty_print_in_place(const char *filename, const char *pretty_print_prog, const char *pretty_print_args) { + int status = 0; + char *tempfile = NULL; + char *result = NULL; + FILE *fp = NULL; + FILE *tmpfp = NULL; + char cmd[PATH_MAX]; + if (!find_program(pretty_print_prog)) { + // Pretty printing is optional. 99% chance the XML data will + // be passed to a report generator; not inspected by a human. + return 0; + } + memset(cmd, 0, sizeof(cmd)); + snprintf(cmd, sizeof(cmd) - 1, "%s %s %s", pretty_print_prog, pretty_print_args, filename); + result = shell_output(cmd, &status); + if (status || !result) { + goto pretty_print_failed; + } + + tempfile = xmkstemp(&tmpfp, "w+"); + if (!tmpfp || !tempfile) { + goto pretty_print_failed; + } + + fprintf(tmpfp, "%s", result); + fflush(tmpfp); + fclose(tmpfp); + + fp = fopen(filename, "w+"); + if (!fp) { + goto pretty_print_failed; + } + + if (copy2(tempfile, filename, CT_PERM)) { + goto pretty_print_failed; + } + + if (remove(tempfile)) { + goto pretty_print_failed; + } + + guard_free(tempfile); + guard_free(result); + return 0; + + pretty_print_failed: + fprintf(SYSERROR); + if (fp) { + fclose(fp); + } + if (tmpfp) { + fclose(tmpfp); + } + guard_free(tempfile); + guard_free(result); + return -1; }
\ No newline at end of file |