From 2c137288a3088a30099ee0b388494984401fb5d3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 1 Mar 2011 23:24:29 +1030 Subject: [PATCH] tdb2: failtest on tdb_expand Increase from: 1962 of 2553 lines covered to: 1985 of 2553 lines covered --- ccan/tdb2/test/failtest_helper.c | 118 +++++++++++++++++++++++++++ ccan/tdb2/test/failtest_helper.h | 18 ++++ ccan/tdb2/test/run-01-new_database.c | 109 +------------------------ ccan/tdb2/test/run-02-expand.c | 43 ++++++++-- 4 files changed, 175 insertions(+), 113 deletions(-) create mode 100644 ccan/tdb2/test/failtest_helper.c create mode 100644 ccan/tdb2/test/failtest_helper.h diff --git a/ccan/tdb2/test/failtest_helper.c b/ccan/tdb2/test/failtest_helper.c new file mode 100644 index 00000000..a9ba4b47 --- /dev/null +++ b/ccan/tdb2/test/failtest_helper.c @@ -0,0 +1,118 @@ +#include "failtest_helper.h" +#include "logging.h" +#include +#include + +/* FIXME: From ccan/str */ +static inline bool strends(const char *str, const char *postfix) +{ + if (strlen(str) < strlen(postfix)) + return false; + + return !strcmp(str + strlen(str) - strlen(postfix), postfix); +} + +bool failmatch(const struct failtest_call *call, + const char *file, int line, enum failtest_call_type type) +{ + return call->type == type + && call->line == line + && ((strcmp(call->file, file) == 0) + || (strends(call->file, file) + && (call->file[strlen(call->file) - strlen(file) - 1] + == '/'))); +} + +static const struct failtest_call * +find_repeat(const struct failtest_call *start, const struct failtest_call *end, + const struct failtest_call *call) +{ + const struct failtest_call *i; + + for (i = start; i < end; i++) { + if (failmatch(i, call->file, call->line, call->type)) + return i; + } + return NULL; +} + +static bool is_nonblocking_lock(const struct failtest_call *call) +{ + return call->type == FAILTEST_FCNTL && call->u.fcntl.cmd == F_SETLK; +} + +static bool is_unlock(const struct failtest_call *call) +{ + return call->type == FAILTEST_FCNTL + && call->u.fcntl.arg.fl.l_type == F_UNLCK; +} + +bool exit_check_log(struct failtest_call *history, unsigned num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (!history[i].fail) + continue; + /* Failing the /dev/urandom open doesn't count: we fall back. */ + if (failmatch(&history[i], URANDOM_OPEN)) + continue; + + /* Similarly with read fail. */ + if (failmatch(&history[i], URANDOM_READ)) + continue; + + /* Initial allocation of tdb doesn't log. */ + if (failmatch(&history[i], INITIAL_TDB_MALLOC)) + continue; + + /* We don't block "failures" on non-blocking locks. */ + if (is_nonblocking_lock(&history[i])) + continue; + + if (!tap_log_messages) + diag("We didn't log for %u (%s:%u)", + i, history[i].file, history[i].line); + return tap_log_messages != 0; + } + return true; +} + +/* Some places we soldier on despite errors: only fail them once. */ +enum failtest_result +block_repeat_failures(struct failtest_call *history, unsigned num) +{ + const struct failtest_call *i, *last = &history[num-1]; + + if (failmatch(last, INITIAL_TDB_MALLOC) + || failmatch(last, LOGGING_MALLOC) + || failmatch(last, URANDOM_OPEN) + || failmatch(last, URANDOM_READ)) { + if (find_repeat(history, last, last)) + return FAIL_DONT_FAIL; + return FAIL_PROBE; + } + + /* Unlock or non-blocking lock is fail-once. */ + if (is_unlock(last)) { + /* Find a previous unlock at this point? */ + for (i = find_repeat(history, last, last); + i; + i = find_repeat(history, i, last)) { + if (is_unlock(i)) + return FAIL_DONT_FAIL; + } + return FAIL_PROBE; + } else if (is_nonblocking_lock(last)) { + /* Find a previous non-blocking lock at this point? */ + for (i = find_repeat(history, last, last); + i; + i = find_repeat(history, i, last)) { + if (is_nonblocking_lock(i)) + return FAIL_DONT_FAIL; + } + return FAIL_PROBE; + } + + return FAIL_OK; +} diff --git a/ccan/tdb2/test/failtest_helper.h b/ccan/tdb2/test/failtest_helper.h new file mode 100644 index 00000000..656f7cd7 --- /dev/null +++ b/ccan/tdb2/test/failtest_helper.h @@ -0,0 +1,18 @@ +#ifndef TDB2_TEST_FAILTEST_HELPER_H +#define TDB2_TEST_FAILTEST_HELPER_H +#include +#include + +/* FIXME: Check these! */ +#define INITIAL_TDB_MALLOC "tdb.c", 189, FAILTEST_MALLOC +#define LOGGING_MALLOC "tdb.c", 766, FAILTEST_MALLOC +#define URANDOM_OPEN "tdb.c", 49, FAILTEST_OPEN +#define URANDOM_READ "tdb.c", 29, FAILTEST_READ + +bool exit_check_log(struct failtest_call *history, unsigned num); +bool failmatch(const struct failtest_call *call, + const char *file, int line, enum failtest_call_type type); +enum failtest_result +block_repeat_failures(struct failtest_call *history, unsigned num); + +#endif /* TDB2_TEST_LOGGING_H */ diff --git a/ccan/tdb2/test/run-01-new_database.c b/ccan/tdb2/test/run-01-new_database.c index a2f5e8fc..2d1cfc83 100644 --- a/ccan/tdb2/test/run-01-new_database.c +++ b/ccan/tdb2/test/run-01-new_database.c @@ -9,112 +9,7 @@ #include #include #include "logging.h" - -/* FIXME: Check these! */ -#define INITIAL_TDB_MALLOC "tdb.c", 189, FAILTEST_MALLOC -#define LOGGING_MALLOC "tdb.c", 766, FAILTEST_MALLOC -#define URANDOM_OPEN "tdb.c", 49, FAILTEST_OPEN -#define URANDOM_READ "tdb.c", 29, FAILTEST_READ - -static bool failmatch(const struct failtest_call *call, - const char *file, int line, enum failtest_call_type type) -{ - return call->type == type - && call->line == line - && ((strcmp(call->file, file) == 0) - || (strends(call->file, file) - && (call->file[strlen(call->file) - strlen(file) - 1] - == '/'))); -} - -static const struct failtest_call * -find_repeat(const struct failtest_call *start, const struct failtest_call *end, - const struct failtest_call *call) -{ - const struct failtest_call *i; - - for (i = start; i < end; i++) { - if (failmatch(i, call->file, call->line, call->type)) - return i; - } - return NULL; -} - -static bool is_nonblocking_lock(const struct failtest_call *call) -{ - return call->type == FAILTEST_FCNTL && call->u.fcntl.cmd == F_SETLK; -} - -/* Some places we soldier on despite errors: only fail them once. */ -static enum failtest_result -block_repeat_failures(struct failtest_call *history, unsigned num) -{ - const struct failtest_call *i, *last = &history[num-1]; - - if (failmatch(last, INITIAL_TDB_MALLOC) - || failmatch(last, LOGGING_MALLOC) - || failmatch(last, URANDOM_OPEN) - || failmatch(last, URANDOM_READ)) { - if (find_repeat(history, last, last)) - return FAIL_DONT_FAIL; - return FAIL_PROBE; - } - - /* Unlock or non-blocking lock is fail-once. */ - if (last->type == FAILTEST_FCNTL - && last->u.fcntl.arg.fl.l_type == F_UNLCK) { - /* Find a previous unlock at this point? */ - for (i = find_repeat(history, last, last); - i; - i = find_repeat(history, i, last)) { - if (i->u.fcntl.arg.fl.l_type == F_UNLCK) - return FAIL_DONT_FAIL; - } - return FAIL_PROBE; - } else if (is_nonblocking_lock(last)) { - /* Find a previous non-blocking lock at this point? */ - for (i = find_repeat(history, last, last); - i; - i = find_repeat(history, i, last)) { - if (is_nonblocking_lock(i)) - return FAIL_DONT_FAIL; - } - return FAIL_PROBE; - } - - return FAIL_OK; -} - -static bool exit_check(struct failtest_call *history, unsigned num) -{ - unsigned int i; - - for (i = 0; i < num; i++) { - if (!history[i].fail) - continue; - /* Failing the /dev/urandom open doesn't count: we fall back. */ - if (failmatch(&history[i], URANDOM_OPEN)) - continue; - - /* Similarly with read fail. */ - if (failmatch(&history[i], URANDOM_READ)) - continue; - - /* Initial allocation of tdb doesn't log. */ - if (failmatch(&history[i], INITIAL_TDB_MALLOC)) - continue; - - /* We don't block "failures" on non-blocking locks. */ - if (is_nonblocking_lock(&history[i])) - continue; - - if (!tap_log_messages) - diag("We didn't log for %u (%s:%u)", - i, history[i].file, history[i].line); - return tap_log_messages != 0; - } - return true; -} +#include "failtest_helper.h" int main(int argc, char *argv[]) { @@ -126,7 +21,7 @@ int main(int argc, char *argv[]) failtest_init(argc, argv); failtest_hook = block_repeat_failures; - failtest_exit_check = exit_check; + failtest_exit_check = exit_check_log; plan_tests(sizeof(flags) / sizeof(flags[0]) * 3); for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { tdb = tdb_open("run-new_database.tdb", flags[i], diff --git a/ccan/tdb2/test/run-02-expand.c b/ccan/tdb2/test/run-02-expand.c index 130daa8c..0a1bc991 100644 --- a/ccan/tdb2/test/run-02-expand.c +++ b/ccan/tdb2/test/run-02-expand.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,20 @@ #include #include #include +#include #include "logging.h" +#include "failtest_helper.h" + +static bool failtest_suppress = false; + +/* Don't need to test everything here, just want expand testing. */ +static enum failtest_result +suppress_failure(struct failtest_call *history, unsigned num) +{ + if (failtest_suppress) + return FAIL_DONT_FAIL; + return block_repeat_failures(history, num); +} int main(int argc, char *argv[]) { @@ -19,24 +33,41 @@ int main(int argc, char *argv[]) plan_tests(sizeof(flags) / sizeof(flags[0]) * 11 + 1); + failtest_init(argc, argv); + failtest_hook = suppress_failure; + failtest_exit_check = exit_check_log; + for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { + failtest_suppress = true; tdb = tdb_open("run-expand.tdb", flags[i], O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr); - ok1(tdb); - if (!tdb) - continue; + if (!ok1(tdb)) + break; val = tdb->map_size; /* Need some hash lock for expand. */ ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0); - ok1(tdb_expand(tdb, 1) == 0); + failtest_suppress = false; + if (!ok1(tdb_expand(tdb, 1) == 0)) { + failtest_suppress = true; + tdb_close(tdb); + break; + } + failtest_suppress = true; + ok1(tdb->map_size >= val + 1 * TDB_EXTENSION_FACTOR); ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0); val = tdb->map_size; ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0); - ok1(tdb_expand(tdb, 1024) == 0); + failtest_suppress = false; + if (!ok1(tdb_expand(tdb, 1024) == 0)) { + failtest_suppress = true; + tdb_close(tdb); + break; + } + failtest_suppress = true; ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0); ok1(tdb->map_size >= val + 1024 * TDB_EXTENSION_FACTOR); ok1(tdb_check(tdb, NULL, NULL) == 0); @@ -44,5 +75,5 @@ int main(int argc, char *argv[]) } ok1(tap_log_messages == 0); - return exit_status(); + failtest_exit(exit_status()); } -- 2.39.2