diff options
Diffstat (limited to 't/helper')
-rw-r--r-- | t/helper/.gitignore | 9 | ||||
-rw-r--r-- | t/helper/test-date.c | 27 | ||||
-rw-r--r-- | t/helper/test-hashmap.c | 50 | ||||
-rw-r--r-- | t/helper/test-lazy-init-name-hash.c | 12 | ||||
-rw-r--r-- | t/helper/test-progress.c | 81 | ||||
-rw-r--r-- | t/helper/test-read-cache.c | 5 | ||||
-rw-r--r-- | t/helper/test-read-graph.c | 53 | ||||
-rw-r--r-- | t/helper/test-run-command.c | 197 | ||||
-rw-r--r-- | t/helper/test-tool.c | 2 | ||||
-rw-r--r-- | t/helper/test-tool.h | 2 |
10 files changed, 381 insertions, 57 deletions
diff --git a/t/helper/.gitignore b/t/helper/.gitignore index 2bad28af92..48c7bb0bbb 100644 --- a/t/helper/.gitignore +++ b/t/helper/.gitignore @@ -1,5 +1,4 @@ -* -!*.sh -!*.[ch] -!*.gitignore - +/test-tool +/test-fake-ssh +/test-line-buffer +/test-svn-fe diff --git a/t/helper/test-date.c b/t/helper/test-date.c index 585347ea48..099eff4f0f 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -12,13 +12,13 @@ static const char *usage_msg = "\n" " test-tool date is64bit\n" " test-tool date time_t-is64bit\n"; -static void show_relative_dates(const char **argv, struct timeval *now) +static void show_relative_dates(const char **argv) { struct strbuf buf = STRBUF_INIT; for (; *argv; argv++) { time_t t = atoi(*argv); - show_date_relative(t, now, &buf); + show_date_relative(t, &buf); printf("%s -> %s\n", *argv, buf.buf); } strbuf_release(&buf); @@ -74,20 +74,20 @@ static void parse_dates(const char **argv) strbuf_release(&result); } -static void parse_approxidate(const char **argv, struct timeval *now) +static void parse_approxidate(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv, now); + t = approxidate_relative(*argv); printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); } } -static void parse_approx_timestamp(const char **argv, struct timeval *now) +static void parse_approx_timestamp(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv, now); + t = approxidate_relative(*argv); printf("%s -> %"PRItime"\n", *argv, t); } } @@ -103,22 +103,13 @@ static void getnanos(const char **argv) int cmd__date(int argc, const char **argv) { - struct timeval now; const char *x; - x = getenv("GIT_TEST_DATE_NOW"); - if (x) { - now.tv_sec = atoi(x); - now.tv_usec = 0; - } - else - gettimeofday(&now, NULL); - argv++; if (!*argv) usage(usage_msg); if (!strcmp(*argv, "relative")) - show_relative_dates(argv+1, &now); + show_relative_dates(argv+1); else if (!strcmp(*argv, "human")) show_human_dates(argv+1); else if (skip_prefix(*argv, "show:", &x)) @@ -126,9 +117,9 @@ int cmd__date(int argc, const char **argv) else if (!strcmp(*argv, "parse")) parse_dates(argv+1); else if (!strcmp(*argv, "approxidate")) - parse_approxidate(argv+1, &now); + parse_approxidate(argv+1); else if (!strcmp(*argv, "timestamp")) - parse_approx_timestamp(argv+1, &now); + parse_approx_timestamp(argv+1); else if (!strcmp(*argv, "getnanos")) getnanos(argv+1); else if (!strcmp(*argv, "is64bit")) diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index aaf17b0ddf..f38706216f 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -5,6 +5,7 @@ struct test_entry { + int padding; /* hashmap entry no longer needs to be the first member */ struct hashmap_entry ent; /* key and value as two \0-terminated strings */ char key[FLEX_ARRAY]; @@ -16,15 +17,17 @@ static const char *get_value(const struct test_entry *e) } static int test_entry_cmp(const void *cmp_data, - const void *entry, - const void *entry_or_key, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, const void *keydata) { const int ignore_case = cmp_data ? *((int *)cmp_data) : 0; - const struct test_entry *e1 = entry; - const struct test_entry *e2 = entry_or_key; + const struct test_entry *e1, *e2; const char *key = keydata; + e1 = container_of(eptr, const struct test_entry, ent); + e2 = container_of(entry_or_key, const struct test_entry, ent); + if (ignore_case) return strcasecmp(e1->key, key ? key : e2->key); else @@ -37,7 +40,7 @@ static struct test_entry *alloc_test_entry(unsigned int hash, size_t klen = strlen(key); size_t vlen = strlen(value); struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2)); - hashmap_entry_init(entry, hash); + hashmap_entry_init(&entry->ent, hash); memcpy(entry->key, key, klen + 1); memcpy(entry->key + klen + 1, value, vlen + 1); return entry; @@ -103,11 +106,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) /* add entries */ for (i = 0; i < TEST_SIZE; i++) { - hashmap_entry_init(entries[i], hashes[i]); - hashmap_add(&map, entries[i]); + hashmap_entry_init(&entries[i]->ent, hashes[i]); + hashmap_add(&map, &entries[i]->ent); } - hashmap_free(&map, 0); + hashmap_free(&map); } } else { /* test map lookups */ @@ -116,8 +119,8 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) /* fill the map (sparsely if specified) */ j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE; for (i = 0; i < j; i++) { - hashmap_entry_init(entries[i], hashes[i]); - hashmap_add(&map, entries[i]); + hashmap_entry_init(&entries[i]->ent, hashes[i]); + hashmap_add(&map, &entries[i]->ent); } for (j = 0; j < rounds; j++) { @@ -127,7 +130,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) } } - hashmap_free(&map, 0); + hashmap_free(&map); } } @@ -179,7 +182,7 @@ int cmd__hashmap(int argc, const char **argv) entry = alloc_test_entry(hash, p1, p2); /* add to hashmap */ - hashmap_add(&map, entry); + hashmap_add(&map, &entry->ent); } else if (!strcmp("put", cmd) && p1 && p2) { @@ -187,43 +190,44 @@ int cmd__hashmap(int argc, const char **argv) entry = alloc_test_entry(hash, p1, p2); /* add / replace entry */ - entry = hashmap_put(&map, entry); + entry = hashmap_put_entry(&map, entry, ent); /* print and free replaced entry, if any */ puts(entry ? get_value(entry) : "NULL"); free(entry); } else if (!strcmp("get", cmd) && p1) { - /* lookup entry in hashmap */ - entry = hashmap_get_from_hash(&map, hash, p1); + entry = hashmap_get_entry_from_hash(&map, hash, p1, + struct test_entry, ent); /* print result */ if (!entry) puts("NULL"); - while (entry) { + hashmap_for_each_entry_from(&map, entry, ent) puts(get_value(entry)); - entry = hashmap_get_next(&map, entry); - } } else if (!strcmp("remove", cmd) && p1) { /* setup static key */ struct hashmap_entry key; + struct hashmap_entry *rm; hashmap_entry_init(&key, hash); /* remove entry from hashmap */ - entry = hashmap_remove(&map, &key, p1); + rm = hashmap_remove(&map, &key, p1); + entry = rm ? container_of(rm, struct test_entry, ent) + : NULL; /* print result and free entry*/ puts(entry ? get_value(entry) : "NULL"); free(entry); } else if (!strcmp("iterate", cmd)) { - struct hashmap_iter iter; - hashmap_iter_init(&map, &iter); - while ((entry = hashmap_iter_next(&iter))) + + hashmap_for_each_entry(&map, &iter, entry, + ent /* member name */) printf("%s %s\n", entry->key, get_value(entry)); } else if (!strcmp("size", cmd)) { @@ -258,6 +262,6 @@ int cmd__hashmap(int argc, const char **argv) } strbuf_release(&line); - hashmap_free(&map, 1); + hashmap_free_entries(&map, struct test_entry, ent); return 0; } diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index b99a37080d..cd1b4c9736 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -41,17 +41,13 @@ static void dump_run(void) die("non-threaded code path used"); } - dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir); - while (dir) { + hashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir, + ent /* member name */) printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); - dir = hashmap_iter_next(&iter_dir); - } - ce = hashmap_iter_first(&the_index.name_hash, &iter_cache); - while (ce) { + hashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce, + ent /* member name */) printf("name %08x %s\n", ce->ent.hash, ce->name); - ce = hashmap_iter_next(&iter_cache); - } discard_cache(); } diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c new file mode 100644 index 0000000000..42b96cb103 --- /dev/null +++ b/t/helper/test-progress.c @@ -0,0 +1,81 @@ +/* + * A test helper to exercise the progress display. + * + * Reads instructions from standard input, one instruction per line: + * + * "progress <items>" - Call display_progress() with the given item count + * as parameter. + * "throughput <bytes> <millis> - Call display_throughput() with the given + * byte count as parameter. The 'millis' + * specify the time elapsed since the + * start_progress() call. + * "update" - Set the 'progress_update' flag. + * + * See 't0500-progress-display.sh' for examples. + */ +#include "test-tool.h" +#include "gettext.h" +#include "parse-options.h" +#include "progress.h" +#include "strbuf.h" + +/* + * These are defined in 'progress.c', but are not exposed in 'progress.h', + * because they are exclusively for testing. + */ +extern int progress_testing; +extern uint64_t progress_test_ns; +void progress_test_force_update(void); + +int cmd__progress(int argc, const char **argv) +{ + int total = 0; + const char *title; + struct strbuf line = STRBUF_INIT; + struct progress *progress; + + const char *usage[] = { + "test-tool progress [--total=<n>] <progress-title>", + NULL + }; + struct option options[] = { + OPT_INTEGER(0, "total", &total, "total number of items"), + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, options, usage, 0); + if (argc != 1) + die("need a title for the progress output"); + title = argv[0]; + + progress_testing = 1; + progress = start_progress(title, total); + while (strbuf_getline(&line, stdin) != EOF) { + char *end; + + if (skip_prefix(line.buf, "progress ", (const char **) &end)) { + uint64_t item_count = strtoull(end, &end, 10); + if (*end != '\0') + die("invalid input: '%s'\n", line.buf); + display_progress(progress, item_count); + } else if (skip_prefix(line.buf, "throughput ", + (const char **) &end)) { + uint64_t byte_count, test_ms; + + byte_count = strtoull(end, &end, 10); + if (*end != ' ') + die("invalid input: '%s'\n", line.buf); + test_ms = strtoull(end + 1, &end, 10); + if (*end != '\0') + die("invalid input: '%s'\n", line.buf); + progress_test_ns = test_ms * 1000 * 1000; + display_throughput(progress, byte_count); + } else if (!strcmp(line.buf, "update")) + progress_test_force_update(); + else + die("invalid input: '%s'\n", line.buf); + } + stop_progress(&progress); + + return 0; +} diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index 7e79b555de..244977a29b 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -4,11 +4,10 @@ int cmd__read_cache(int argc, const char **argv) { - int i, cnt = 1, namelen; + int i, cnt = 1; const char *name = NULL; if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) { - namelen = strlen(name); argc--; argv++; } @@ -24,7 +23,7 @@ int cmd__read_cache(int argc, const char **argv) refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); - pos = index_name_pos(&the_index, name, namelen); + pos = index_name_pos(&the_index, name, strlen(name)); if (pos < 0) die("%s not in index", name); printf("%s is%s up to date\n", name, diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c new file mode 100644 index 0000000000..d2884efe0a --- /dev/null +++ b/t/helper/test-read-graph.c @@ -0,0 +1,53 @@ +#include "test-tool.h" +#include "cache.h" +#include "commit-graph.h" +#include "repository.h" +#include "object-store.h" + +int cmd__read_graph(int argc, const char **argv) +{ + struct commit_graph *graph = NULL; + char *graph_name; + int open_ok; + int fd; + struct stat st; + const char *object_dir; + + setup_git_directory(); + object_dir = get_object_directory(); + + graph_name = get_commit_graph_filename(object_dir); + + open_ok = open_commit_graph(graph_name, &fd, &st); + if (!open_ok) + die_errno(_("Could not open commit-graph '%s'"), graph_name); + + graph = load_commit_graph_one_fd_st(fd, &st); + if (!graph) + return 1; + + FREE_AND_NULL(graph_name); + + printf("header: %08x %d %d %d %d\n", + ntohl(*(uint32_t*)graph->data), + *(unsigned char*)(graph->data + 4), + *(unsigned char*)(graph->data + 5), + *(unsigned char*)(graph->data + 6), + *(unsigned char*)(graph->data + 7)); + printf("num_commits: %u\n", graph->num_commits); + printf("chunks:"); + + if (graph->chunk_oid_fanout) + printf(" oid_fanout"); + if (graph->chunk_oid_lookup) + printf(" oid_lookup"); + if (graph->chunk_commit_data) + printf(" commit_metadata"); + if (graph->chunk_extra_edges) + printf(" extra_edges"); + printf("\n"); + + UNLEAK(graph); + + return 0; +} diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index 8579b1f7d1..1646aa25d8 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -10,9 +10,14 @@ #include "test-tool.h" #include "git-compat-util.h" +#include "cache.h" #include "run-command.h" #include "argv-array.h" #include "strbuf.h" +#include "parse-options.h" +#include "string-list.h" +#include "thread-utils.h" +#include "wildmatch.h" #include "gettext.h" #include "parse-options.h" @@ -50,6 +55,151 @@ static int task_finished(int result, return 1; } +struct testsuite { + struct string_list tests, failed; + int next; + int quiet, immediate, verbose, verbose_log, trace, write_junit_xml; +}; +#define TESTSUITE_INIT \ + { STRING_LIST_INIT_DUP, STRING_LIST_INIT_DUP, -1, 0, 0, 0, 0, 0, 0 } + +static int next_test(struct child_process *cp, struct strbuf *err, void *cb, + void **task_cb) +{ + struct testsuite *suite = cb; + const char *test; + if (suite->next >= suite->tests.nr) + return 0; + + test = suite->tests.items[suite->next++].string; + argv_array_pushl(&cp->args, "sh", test, NULL); + if (suite->quiet) + argv_array_push(&cp->args, "--quiet"); + if (suite->immediate) + argv_array_push(&cp->args, "-i"); + if (suite->verbose) + argv_array_push(&cp->args, "-v"); + if (suite->verbose_log) + argv_array_push(&cp->args, "-V"); + if (suite->trace) + argv_array_push(&cp->args, "-x"); + if (suite->write_junit_xml) + argv_array_push(&cp->args, "--write-junit-xml"); + + strbuf_addf(err, "Output of '%s':\n", test); + *task_cb = (void *)test; + + return 1; +} + +static int test_finished(int result, struct strbuf *err, void *cb, + void *task_cb) +{ + struct testsuite *suite = cb; + const char *name = (const char *)task_cb; + + if (result) + string_list_append(&suite->failed, name); + + strbuf_addf(err, "%s: '%s'\n", result ? "FAIL" : "SUCCESS", name); + + return 0; +} + +static int test_failed(struct strbuf *out, void *cb, void *task_cb) +{ + struct testsuite *suite = cb; + const char *name = (const char *)task_cb; + + string_list_append(&suite->failed, name); + strbuf_addf(out, "FAILED TO START: '%s'\n", name); + + return 0; +} + +static const char * const testsuite_usage[] = { + "test-run-command testsuite [<options>] [<pattern>...]", + NULL +}; + +static int testsuite(int argc, const char **argv) +{ + struct testsuite suite = TESTSUITE_INIT; + int max_jobs = 1, i, ret; + DIR *dir; + struct dirent *d; + struct option options[] = { + OPT_BOOL('i', "immediate", &suite.immediate, + "stop at first failed test case(s)"), + OPT_INTEGER('j', "jobs", &max_jobs, "run <N> jobs in parallel"), + OPT_BOOL('q', "quiet", &suite.quiet, "be terse"), + OPT_BOOL('v', "verbose", &suite.verbose, "be verbose"), + OPT_BOOL('V', "verbose-log", &suite.verbose_log, + "be verbose, redirected to a file"), + OPT_BOOL('x', "trace", &suite.trace, "trace shell commands"), + OPT_BOOL(0, "write-junit-xml", &suite.write_junit_xml, + "write JUnit-style XML files"), + OPT_END() + }; + + memset(&suite, 0, sizeof(suite)); + suite.tests.strdup_strings = suite.failed.strdup_strings = 1; + + argc = parse_options(argc, argv, NULL, options, + testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION); + + if (max_jobs <= 0) + max_jobs = online_cpus(); + + dir = opendir("."); + if (!dir) + die("Could not open the current directory"); + while ((d = readdir(dir))) { + const char *p = d->d_name; + + if (*p != 't' || !isdigit(p[1]) || !isdigit(p[2]) || + !isdigit(p[3]) || !isdigit(p[4]) || p[5] != '-' || + !ends_with(p, ".sh")) + continue; + + /* No pattern: match all */ + if (!argc) { + string_list_append(&suite.tests, p); + continue; + } + + for (i = 0; i < argc; i++) + if (!wildmatch(argv[i], p, 0)) { + string_list_append(&suite.tests, p); + break; + } + } + closedir(dir); + + if (!suite.tests.nr) + die("No tests match!"); + if (max_jobs > suite.tests.nr) + max_jobs = suite.tests.nr; + + fprintf(stderr, "Running %d tests (%d at a time)\n", + suite.tests.nr, max_jobs); + + ret = run_processes_parallel(max_jobs, next_test, test_failed, + test_finished, &suite); + + if (suite.failed.nr > 0) { + ret = 1; + fprintf(stderr, "%d tests failed:\n\n", suite.failed.nr); + for (i = 0; i < suite.failed.nr; i++) + fprintf(stderr, "\t%s\n", suite.failed.items[i].string); + } + + string_list_clear(&suite.tests, 0); + string_list_clear(&suite.failed, 0); + + return !!ret; +} + static uint64_t my_random_next = 1234; static uint64_t my_random(void) @@ -178,11 +328,58 @@ static int quote_echo(int argc, const char **argv) return 0; } +static int inherit_handle(const char *argv0) +{ + struct child_process cp = CHILD_PROCESS_INIT; + char path[PATH_MAX]; + int tmp; + + /* First, open an inheritable handle */ + xsnprintf(path, sizeof(path), "out-XXXXXX"); + tmp = xmkstemp(path); + + argv_array_pushl(&cp.args, + "test-tool", argv0, "inherited-handle-child", NULL); + cp.in = -1; + cp.no_stdout = cp.no_stderr = 1; + if (start_command(&cp) < 0) + die("Could not start child process"); + + /* Then close it, and try to delete it. */ + close(tmp); + if (unlink(path)) + die("Could not delete '%s'", path); + + if (close(cp.in) < 0 || finish_command(&cp) < 0) + die("Child did not finish"); + + return 0; +} + +static int inherit_handle_child(void) +{ + struct strbuf buf = STRBUF_INIT; + + if (strbuf_read(&buf, 0, 0) < 0) + die("Could not read stdin"); + printf("Received %s\n", buf.buf); + strbuf_release(&buf); + + return 0; +} + int cmd__run_command(int argc, const char **argv) { struct child_process proc = CHILD_PROCESS_INIT; int jobs; + if (argc > 1 && !strcmp(argv[1], "testsuite")) + exit(testsuite(argc - 1, argv + 1)); + if (!strcmp(argv[1], "inherited-handle")) + exit(inherit_handle(argv[0])); + if (!strcmp(argv[1], "inherited-handle-child")) + exit(inherit_handle_child()); + if (argc >= 2 && !strcmp(argv[1], "quote-stress-test")) return !!quote_stress_test(argc - 1, argv + 1); diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index ce7e89028c..f20989d449 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -42,8 +42,10 @@ static struct test_cmd cmds[] = { { "path-utils", cmd__path_utils }, { "pkt-line", cmd__pkt_line }, { "prio-queue", cmd__prio_queue }, + { "progress", cmd__progress }, { "reach", cmd__reach }, { "read-cache", cmd__read_cache }, + { "read-graph", cmd__read_graph }, { "read-midx", cmd__read_midx }, { "ref-store", cmd__ref_store }, { "regex", cmd__regex }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index f805bb39ae..8ed2af71d1 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -32,8 +32,10 @@ int cmd__parse_options(int argc, const char **argv); int cmd__path_utils(int argc, const char **argv); int cmd__pkt_line(int argc, const char **argv); int cmd__prio_queue(int argc, const char **argv); +int cmd__progress(int argc, const char **argv); int cmd__reach(int argc, const char **argv); int cmd__read_cache(int argc, const char **argv); +int cmd__read_graph(int argc, const char **argv); int cmd__read_midx(int argc, const char **argv); int cmd__ref_store(int argc, const char **argv); int cmd__regex(int argc, const char **argv); |