diff options
Diffstat (limited to 'lib/get-test-job.c')
-rw-r--r-- | lib/get-test-job.c | 236 |
1 files changed, 175 insertions, 61 deletions
diff --git a/lib/get-test-job.c b/lib/get-test-job.c index 193544b..665249f 100644 --- a/lib/get-test-job.c +++ b/lib/get-test-job.c @@ -13,8 +13,12 @@ #include <sys/types.h> #include <unistd.h> +#define HAVE_STATEMENT_EXPR 1 +#include "darray/darray.h" + static char *outdir = NULL; static char *branches_to_test = NULL; +static bool verbose = false; #define die(msg, ...) \ do { \ @@ -47,7 +51,7 @@ static void strim(char *line) *p = 0; } -static char *test_basename(char *str) +static char *test_basename(const char *str) { char *p = strrchr(str, '/'); char *ret = strdup(p ? p + 1 : str); @@ -58,105 +62,216 @@ static char *test_basename(char *str) return ret; } -static void branch_get_next_commit_and_test(char *branch, - char **ret_commit, - char *test, - unsigned *age) +typedef darray(char *) strings; + +static void strings_free(strings *strs) +{ + char **s; + + darray_foreach(s, *strs) + free(*s); + darray_free(*strs); + + memset(strs, 0, sizeof(*strs)); +} + +typedef struct { + char *branch; + char *commit; + unsigned age; + char *test; + strings subtests; +} test_job; + +static void test_job_free(test_job *job) +{ + free(job->branch); + free(job->commit); + free(job->test); + strings_free(&job->subtests); + memset(job, 0, sizeof(*job)); +} + +static strings get_subtests(char *test_path) +{ + darray_char output; + strings ret; + size_t bytes_read; + + darray_init(output); + darray_init(ret); + + char *cmd = mprintf("%s list-tests", test_path); + FILE *f = popen(cmd, "r"); + free(cmd); + + if (!f) + die("error executing %s", test_path); + + do { + darray_make_room(output, 4096); + + bytes_read = fread(output.item + output.size, + 1, 4096, f); + output.size += bytes_read; + } while (bytes_read); + + pclose(f); + + char *subtest, *p = output.item; + while ((subtest = strtok(p, " \t\n"))) { + darray_push(ret, strdup(subtest)); + p = NULL; + } + + darray_free(output); + + if (darray_empty(ret)) + die("error getting subtests from %s", test_path); + + return ret; +} + +static bool lockfile_exists(const char *commit, + const char *test_path, + const char *subtest, + bool create) +{ + char *test_name = test_basename(test_path); + char *commitdir = mprintf("%s/%s", outdir, commit); + char *testdir = mprintf("%s/%s.%s", commitdir, test_name, subtest); + char *lockfile = mprintf("%s/status", + testdir, subtest); + bool exists; + + if (!create) { + exists = access(lockfile, F_OK) == 0; + } else { + mkdir(commitdir, 0755); + mkdir(testdir, 0755); + int fd = open(lockfile, O_RDWR|O_CREAT|O_EXCL, 0644); + exists = fd < 0; + if (!exists) + close(fd); + } + + free(lockfile); + free(testdir); + free(commitdir); + free(test_name); + + return exists; +} + +static test_job branch_get_next_test_job(char *branch, + char *test_path, + strings subtests) { char *cmd = mprintf("git log --pretty=format:%H %s", branch); FILE *commits = popen(cmd, "r"); char *commit = NULL; size_t n = 0; ssize_t len; + test_job ret; - *age = 0; + memset(&ret, 0, sizeof(ret)); while ((len = getline(&commit, &n, commits)) >= 0) { strim(commit); - char *lockfile = mprintf("%s/%s/%s", outdir, commit, test); - bool exists = access(lockfile, F_OK) == 0; - free(lockfile); - - if (!exists) { - *ret_commit = strdup(commit); + char **subtest; + darray_foreach(subtest, subtests) + if (!lockfile_exists(commit, test_path, *subtest, false)) { + darray_push(ret.subtests, strdup(*subtest)); + if (darray_size(ret.subtests) > 20) + break; + } + + if (!darray_empty(ret.subtests)) { + ret.branch = strdup(branch); + ret.commit = strdup(commit); + ret.test = strdup(test_path); goto success; } - (*age)++; + ret.age++; } fprintf(stderr, "error looking up commits on branch %s\n", branch); success: fclose(commits); free(commit); free(cmd); + return ret; } -static void get_best_branch_commit_test(char **ret_branch, - char **ret_commit, - char **ret_test) +static test_job get_best_test_job() { FILE *branches = fopen(branches_to_test, "r"); char *line = NULL; size_t n = 0; ssize_t len; - unsigned best_age = 0; + test_job best; + + memset(&best, 0, sizeof(best)); if (!branches) die("error opening %s: %m", branches_to_test); - *ret_branch = NULL; - *ret_commit = NULL; - *ret_test = NULL; - while ((len = getline(&line, &n, branches)) >= 0) { - char *commit = NULL; char *branch = strtok(line, " \t\n"); - char *test = strtok(NULL, " \t\n"); - char *testname; - unsigned age; + char *test_path = strtok(NULL, " \t\n"); - if (!branch || !test) + if (!branch || !test_path) continue; - testname = test_basename(test); - //fprintf(stderr, "branch %s test %s\n", branch, test); + strings subtests = get_subtests(test_path); - branch_get_next_commit_and_test(branch, &commit, testname, &age); - free(testname); + if (verbose) + fprintf(stderr, "branch %s test %s\n", branch, test_path); - if (!*ret_branch || age < best_age) { - free(*ret_branch); - free(*ret_commit); - free(*ret_test); + test_job job = branch_get_next_test_job(branch, test_path, subtests); - *ret_branch = strdup(branch); - *ret_test = strdup(test); - *ret_commit = commit; - best_age = age; + strings_free(&subtests); + + if (!best.branch || job.age < best.age) { + test_job_free(&best); + best = job; + } else { + test_job_free(&job); } } - if (!*ret_branch) + if (!best.branch) die("Nothing found"); fclose(branches); free(line); + return best; } void usage(void) { - puts("get-test-job: get a test job and create lockfile"); + puts("get-test-job: get a test job and create lockfile\n" + "Usage: get-test-job [OPTIONS]\n" + "\n" + "Options\n" + " -b file List of branches to test and tests to run\n" + " -o dir Directory for tests results\n" + " -v Verbose\n" + " -h Display this help and exit"); exit(EXIT_SUCCESS); } int main(int argc, char *argv[]) { - char *branch, *commit, *test, *testname; - bool created; int opt; + test_job job; + strings subtests; + char **subtest; + + memset(&job, 0, sizeof(job)); - while ((opt = getopt(argc, argv, "b:o:")) != -1) { + while ((opt = getopt(argc, argv, "b:o:vh")) != -1) { switch (opt) { case 'b': branches_to_test = strdup(optarg); @@ -164,6 +279,9 @@ int main(int argc, char *argv[]) case 'o': outdir = strdup(optarg); break; + case 'v': + verbose = true; + break; case 'h': usage(); exit(EXIT_SUCCESS); @@ -177,26 +295,22 @@ int main(int argc, char *argv[]) die("required argument missing"); do { - get_best_branch_commit_test(&branch, &commit, &test); + test_job_free(&job); + job = get_best_test_job(); - //fprintf(stderr, "got %s %s %s\n", branch, commit, test); + if (verbose) + fprintf(stderr, "got %s %s %s age %u\n", + job.branch, job.commit, job.test, job.age); - char *commitdir = mprintf("%s/%s", outdir, commit); - mkdir(commitdir, 0755); - - testname = test_basename(test); - - char *lockfile = mprintf("%s/%s", commitdir, testname); - - //fprintf(stderr, "lockfile %s\n", lockfile); - - int fd = open(lockfile, O_RDWR|O_CREAT|O_EXCL, 0644); - fprintf(stderr, "fd %i\n", fd); - created = fd >= 0; + darray_init(subtests); - free(commitdir); - free(lockfile); - } while (!created); + darray_foreach(subtest, job.subtests) + if (!lockfile_exists(job.commit, job.test, *subtest, true)) + darray_push(subtests, *subtest); + } while (darray_empty(subtests)); - printf("%s %s %s\n", branch, commit, test); + printf("%s %s %s", job.branch, job.commit, job.test); + darray_foreach(subtest, subtests) + printf(" %s", *subtest); + printf("\n"); } |