diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-06-23 20:51:04 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2022-06-23 20:51:04 -0400 |
commit | 52e39cffbfdd7180be359ed01ae1763c6ccf1632 (patch) | |
tree | 0b21e929f00920f4baa54198dfbe576a926cb850 /lib/qemu-wrapper.c | |
parent | 3cbb28191eafb06c4ad64bf5efb047f4d8277d67 (diff) |
Test automation improvements
Log files are now based on the name of the test being run, and
individual tests in a .ktest file now have their own log files
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'lib/qemu-wrapper.c')
-rw-r--r-- | lib/qemu-wrapper.c | 123 |
1 files changed, 119 insertions, 4 deletions
diff --git a/lib/qemu-wrapper.c b/lib/qemu-wrapper.c index 5f52d0c..eb86656 100644 --- a/lib/qemu-wrapper.c +++ b/lib/qemu-wrapper.c @@ -1,7 +1,11 @@ +#define _GNU_SOURCE + +#include <ctype.h> #include <getopt.h> #include <errno.h> #include <fcntl.h> #include <signal.h> +#include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -38,9 +42,79 @@ static void usage(void) " -S Exit on success\n" " -F Exit on failure\n" " -T TIMEOUT Timeout after TIMEOUT seconds\n" + " -b name base name for log files\n" + " -o dir output directory for log files\n" " -h Display this help and exit\n"); } +static char *mprintf(const char *fmt, ...) +{ + va_list args; + char *str; + int ret; + + va_start(args, fmt); + ret = vasprintf(&str, fmt, args); + va_end(args); + + if (ret < 0) + die("insufficient memory"); + + return str; +} + +static char *log_path(const char *logdir, const char *basename, const char *testname) +{ + if (!basename) + basename = "out"; + + return !testname + ? mprintf("%s/%s", logdir, basename) + : mprintf("%s/%s.%s", logdir, basename, testname); +} + +static FILE *log_open(const char *logdir, const char *basename, const char *testname) +{ + char *path = log_path(logdir, basename, testname); + + FILE *f = fopen(path, "w"); + if (!f) + die("error opening %s: %m", path); + + free(path); + setlinebuf(f); + return f; +} + +static void strim(char *line) +{ + char *p = line; + + while (!iscntrl(*p)) + p++; + *p = 0; +} + +static const char *str_starts_with(const char *str, const char *prefix) +{ + unsigned len = strlen(prefix); + + if (strncmp(str, prefix, len)) + return NULL; + return str + len; +} + +static const char *test_starts(const char *line) +{ + return str_starts_with(line, "========= TEST "); +} + +static bool test_ends(char *line) +{ + return str_starts_with(line, "========= FAILED ") || + str_starts_with(line, "========= PASSED "); +} + int main(int argc, char *argv[]) { bool exit_on_success = false; @@ -48,6 +122,8 @@ int main(int argc, char *argv[]) unsigned long timeout = 0; int opt, ret = EXIT_FAILURE; struct timespec start, ts; + char *logdir = NULL; + char *basename = NULL; setlinebuf(stdin); setlinebuf(stdout); @@ -55,7 +131,7 @@ int main(int argc, char *argv[]) if (clock_gettime(CLOCK_MONOTONIC, &start)) die("clock_gettime error: %m"); - while ((opt = getopt(argc, argv, "SFT:h")) != -1) { + while ((opt = getopt(argc, argv, "SFT:b:o:h")) != -1) { switch (opt) { case 'S': exit_on_success = true; @@ -69,6 +145,12 @@ int main(int argc, char *argv[]) if (errno) die("error parsing timeout: %m"); break; + case 'b': + basename = strdup(optarg); + break; + case 'o': + logdir = strdup(optarg); + break; case 'h': usage(); exit(EXIT_SUCCESS); @@ -78,6 +160,9 @@ int main(int argc, char *argv[]) } } + if (!logdir) + die("Required option -o missing"); + int pipefd[2]; if (pipe(pipefd)) die("error creating pipe: %m"); @@ -117,18 +202,48 @@ int main(int argc, char *argv[]) goto out; } - size_t n = 0, len; + FILE *logfile = log_open(logdir, basename, NULL); + FILE *test_logfile = NULL; + + size_t n = 0, output_len = 0; + ssize_t len; char *line = NULL; + char *output_line = NULL; while ((len = getline(&line, &n, childf)) >= 0) { + strim(line); + + const char *testname = test_starts(line); + + if (test_logfile && + (testname || test_ends(line))) { + fputc('\n', test_logfile); + fclose(test_logfile); + test_logfile = NULL; + } + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { fprintf(stderr, "clock_gettime error: %m\n"); break; } + if (output_len < n + 20) { + output_len = n + 20; + output_line = realloc(output_line, output_len); + } + unsigned long elapsed = ts.tv_sec - start.tv_sec; - printf("%.5lu ", elapsed); - fputs(line, stdout); + + strim(line); + sprintf(output_line, "%.5lu %s\n", elapsed, line); + + if (test_logfile) + fputs(output_line, test_logfile); + fputs(output_line, logfile); + fputs(output_line, stdout); + + if (testname) + test_logfile = log_open(logdir, basename, testname); if (exit_on_success && strstr(line, "TEST SUCCESS")) { |