static void readlink_file(void) { char buf[128]; int fd, rv; fd = open_testfile("the question contains an invalid assumption"); if (fd<0) { return; } close(fd); rv = readlink(TESTFILE, buf, sizeof(buf)); report_test(rv, errno, EINVAL, "readlink on file"); remove(TESTFILE); }
static void ftruncate_fd_device(void) { int rv, fd; fd = open("null:", O_RDWR); if (fd<0) { warn("UH-OH: opening null: failed"); return; } rv = ftruncate(fd, 6); report_test(rv, errno, EINVAL, "ftruncate on device"); close(fd); }
static void ftruncate_size_neg(void) { int rv, fd; fd = open_testfile(0); if (fd<0) { return; } rv = ftruncate(fd, -60); report_test(rv, errno, EINVAL, "ftruncate to negative size"); close(fd); remove(TESTFILE); }
static void lseek_whence_inval(void) { int fd, rv; fd = open_testfile(NULL); if (fd<0) { return; } rv = lseek(fd, 0, 3594); report_test(rv, errno, EINVAL, "lseek with invalid whence code"); close(fd); remove(TESTFILE); }
static void lseek_fd_device(void) { int fd, rv; fd = open("null:", O_RDONLY); if (fd<0) { warn("UH-OH: opening null: failed"); return; } rv = lseek(fd, 309, SEEK_SET); report_test(rv, errno, ESPIPE, "lseek on device"); close(fd); }
static void lseek_loc_negative(void) { int fd, rv; fd = open_testfile(NULL); if (fd<0) { return; } rv = lseek(fd, -309, SEEK_SET); report_test(rv, errno, EINVAL, "lseek to negative offset"); close(fd); remove(TESTFILE); }
static void wait_badstatus(void *ptr, const char *desc) { int rv, pid, x; pid = fork(); if (pid<0) { warn("UH-OH: fork failed"); return; } if (pid==0) { exit(0); } rv = waitpid(pid, ptr, 0); report_test(rv, errno, EFAULT, desc); waitpid(pid, &x, 0); }
static void wait_badflags(void) { int rv, x, pid; pid = fork(); if (pid<0) { warn("UH-OH: fork failed"); return; } if (pid==0) { exit(0); } rv = waitpid(pid, &x, 309429); report_test(rv, errno, EINVAL, "wait with bad flags"); waitpid(pid, &x, 0); }
static void wait_nullstatus(void) { pid_t pid, rv; int x; pid = fork(); if (pid<0) { warn("UH-OH: fork failed"); return; } if (pid==0) { exit(0); } /* POSIX explicitly says passing NULL for status is allowed */ rv = waitpid(pid, NULL, 0); report_test(rv, errno, 0, "wait with NULL status"); waitpid(pid, &x, 0); }
static void common_badpath(int (*func)(const char *path), int mk, int rm, const char *path, const char *call, const char *pathdesc) { char mydesc[128]; int rv; if (mk) { if (create_testfile()<0) { return; } } snprintf(mydesc, sizeof(mydesc), "%s with %s path", call, pathdesc); rv = func(path); report_test(rv, errno, EFAULT, mydesc); if (mk || rm) { remove(TESTFILE); } }
int main(int argc, char **argv) { int c, exitcode = 0, num_cases = 0; const char *engine = NULL; const char *engine_args = NULL; const char *test_suite = NULL; engine_test_t *testcases = NULL; logger_descriptor = get_null_logger(); /* Hack to remove the warning from C99 */ union { GET_TESTS get_tests; void* voidptr; } my_get_test = {.get_tests = NULL }; /* Hack to remove the warning from C99 */ union { SETUP_SUITE setup_suite; void* voidptr; } my_setup_suite = {.setup_suite = NULL }; /* Hack to remove the warning from C99 */ union { TEARDOWN_SUITE teardown_suite; void* voidptr; } my_teardown_suite = {.teardown_suite = NULL }; /* Use unbuffered stdio */ setbuf(stdout, NULL); setbuf(stderr, NULL); /* process arguments */ while (-1 != (c = getopt(argc, argv, "h" /* usage */ "E:" /* Engine to load */ "e:" /* Engine options */ "T:" /* Library with tests to load */ ))) { switch (c) { case 'E': engine = optarg; break; case 'e': engine_args = optarg; break; case 'h': usage(); return 0; case 'T': test_suite = optarg; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } //validate args if (engine == NULL) { fprintf(stderr, "You must provide a path to the storage engine library.\n"); return 1; } if (test_suite == NULL) { fprintf(stderr, "You must provide a path to the testsuite library.\n"); return 1; } //load test_suite void* handle = dlopen(test_suite, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { const char *msg = dlerror(); fprintf(stderr, "Failed to load testsuite %s: %s\n", test_suite, msg ? msg : "unknown error"); return 1; } //get the test cases void *symbol = dlsym(handle, "get_tests"); if (symbol == NULL) { const char *msg = dlerror(); fprintf(stderr, "Could not find get_tests function in testsuite %s: %s\n", test_suite, msg ? msg : "unknown error"); return 1; } my_get_test.voidptr = symbol; testcases = (*my_get_test.get_tests)(); //set up the suite if needed struct test_harness harness = { .default_engine_cfg = engine_args, .engine_path = engine, .reload_engine = reload_engine, .start_engine = start_your_engines, .create_cookie = create_mock_cookie, .destroy_cookie = destroy_mock_cookie, .set_ewouldblock_handling = mock_set_ewouldblock_handling, .lock_cookie = lock_mock_cookie, .unlock_cookie = unlock_mock_cookie, .waitfor_cookie = waitfor_mock_cookie}; symbol = dlsym(handle, "setup_suite"); if (symbol != NULL) { my_setup_suite.voidptr = symbol; if (!(*my_setup_suite.setup_suite)(&harness)) { fprintf(stderr, "Failed to set up test suite %s \n", test_suite); return 1; } } for (num_cases = 0; testcases[num_cases].name; num_cases++) { /* Just counting */ } printf("1..%d\n", num_cases); int i; for (i = 0; testcases[i].name; i++) { printf("Running %s... ", testcases[i].name); fflush(stdout); exitcode += report_test(run_test(testcases[i], engine, engine_args)); } //tear down the suite if needed symbol = dlsym(handle, "teardown_suite"); if (symbol != NULL) { my_teardown_suite.voidptr = symbol; if (!(*my_teardown_suite.teardown_suite)()) { fprintf(stderr, "Failed to teardown up test suite %s \n", test_suite); } } return exitcode; }
static void lseek_file_stdin(void) { int fd, fd2, rv, status; const char slogan[] = "There ain't no such thing as a free lunch"; size_t len = strlen(slogan); pid_t pid; /* fork so we don't affect our own stdin */ pid = fork(); if (pid<0) { warn("UH-OH: fork failed"); return; } else if (pid!=0) { /* parent */ rv = waitpid(pid, &status, 0); if (rv<0) { warn("UH-OH: waitpid failed"); } if (WIFSIGNALED(status)) { warn("UH-OH: subprocess exited with signal %d", WTERMSIG(status)); } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { warn("UH-OH: subprocess exited with code %d", WEXITSTATUS(status)); } return; } /* child */ fd = open_testfile(NULL); if (fd<0) { _exit(0); } /* * Move file to stdin. * Use stdin (rather than stdout or stderr) to maximize the * chances of detecting any special-case handling of fds 0-2. * (Writing to stdin is fine as long as it's open for write, * and it will be.) */ fd2 = dup2(fd, STDIN_FILENO); if (fd2<0) { warn("UH-OH: dup2 to stdin failed"); close(fd); remove(TESTFILE); _exit(0); } if (fd2 != STDIN_FILENO) { warn("UH-OH: dup2 returned wrong file handle"); close(fd); remove(TESTFILE); _exit(0); } close(fd); rv = write(STDIN_FILENO, slogan, len); if (rv<0) { warn("UH-OH: write to %s (via stdin) failed", TESTFILE); remove(TESTFILE); _exit(0); } if ((unsigned)rv != len) { warnx("UH-OH: write to %s (via stdin) got short count", TESTFILE); remove(TESTFILE); _exit(0); } rv = lseek(STDIN_FILENO, 0, SEEK_SET); report_test(rv, errno, 0, "lseek stdin when open on file (try 1)"); rv = lseek(STDIN_FILENO, 0, SEEK_END); report_test(rv, errno, 0, "lseek stdin when open on file (try 2)"); remove(TESTFILE); _exit(0); }
int main(int argc, char **argv) { int c, exitcode = 0, num_cases = 0, timeout = 0, loop_count = 0; bool verbose = false; bool quiet = false; bool dot = false; bool loop = false; bool terminate_on_error = false; const char *engine = NULL; const char *engine_args = NULL; const char *test_suite = NULL; const char *test_case = NULL; engine_test_t *testcases = NULL; logger_descriptor = get_null_logger(); /* Hack to remove the warning from C99 */ union { GET_TESTS get_tests; void* voidptr; } my_get_test = {.get_tests = NULL }; /* Hack to remove the warning from C99 */ union { SETUP_SUITE setup_suite; void* voidptr; } my_setup_suite = {.setup_suite = NULL }; /* Hack to remove the warning from C99 */ union { TEARDOWN_SUITE teardown_suite; void* voidptr; } my_teardown_suite = {.teardown_suite = NULL }; color_enabled = getenv("TESTAPP_ENABLE_COLOR") != NULL; /* Use unbuffered stdio */ setbuf(stdout, NULL); setbuf(stderr, NULL); setup_alarm_handler(); /* process arguments */ while (-1 != (c = getopt(argc, argv, "h" /* usage */ "E:" /* Engine to load */ "e:" /* Engine options */ "T:" /* Library with tests to load */ "t:" /* Timeout */ "L" /* Loop until failure */ "q" /* Be more quiet (only report failures) */ "." /* dot mode. */ "n:" /* test case to run */ "v" /* verbose output */ "Z" /* Terminate on first error */ ))) { switch (c) { case 'E': engine = optarg; break; case 'e': engine_args = optarg; break; case 'h': usage(); return 0; case 'T': test_suite = optarg; break; case 't': timeout = atoi(optarg); break; case 'L': loop = true; break; case 'n': test_case = optarg; break; case 'v' : verbose = true; break; case 'q': quiet = true; break; case '.': dot = true; break; case 'Z' : terminate_on_error = true; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } //validate args if (engine == NULL) { fprintf(stderr, "You must provide a path to the storage engine library.\n"); return 1; } if (test_suite == NULL) { fprintf(stderr, "You must provide a path to the testsuite library.\n"); return 1; } //load test_suite void* handle = dlopen(test_suite, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { const char *msg = dlerror(); fprintf(stderr, "Failed to load testsuite %s: %s\n", test_suite, msg ? msg : "unknown error"); return 1; } //get the test cases void *symbol = dlsym(handle, "get_tests"); if (symbol == NULL) { const char *msg = dlerror(); fprintf(stderr, "Could not find get_tests function in testsuite %s: %s\n", test_suite, msg ? msg : "unknown error"); return 1; } my_get_test.voidptr = symbol; testcases = (*my_get_test.get_tests)(); //set up the suite if needed struct test_harness harness = { .default_engine_cfg = engine_args, .engine_path = engine, .reload_engine = reload_engine, .start_engine = start_your_engines, .create_cookie = create_mock_cookie, .destroy_cookie = destroy_mock_cookie, .set_ewouldblock_handling = mock_set_ewouldblock_handling, .lock_cookie = lock_mock_cookie, .unlock_cookie = unlock_mock_cookie, .waitfor_cookie = waitfor_mock_cookie, .time_travel = mock_time_travel, .get_current_testcase = get_current_testcase }; symbol = dlsym(handle, "setup_suite"); if (symbol != NULL) { my_setup_suite.voidptr = symbol; if (!(*my_setup_suite.setup_suite)(&harness)) { fprintf(stderr, "Failed to set up test suite %s \n", test_suite); return 1; } } for (num_cases = 0; testcases[num_cases].name; num_cases++) { /* Just counting */ } if (!quiet) { printf("1..%d\n", num_cases); } do { int i; bool need_newline = false; for (i = 0; testcases[i].name; i++) { int error; if (test_case != NULL && strcmp(test_case, testcases[i].name) != 0) continue; if (!quiet) { printf("Running [%04d/%04d]: %s...", i + num_cases * loop_count, num_cases * (loop_count + 1), testcases[i].name); fflush(stdout); } else if(dot) { printf("."); need_newline = true; /* Add a newline every few tests */ if ((i+1) % 70 == 0) { printf("\n"); need_newline = false; } } set_test_timeout(timeout); error = report_test(testcases[i].name, run_test(testcases[i], engine, engine_args), quiet, !verbose); clear_test_timeout(); if (error != 0) { ++exitcode; if (terminate_on_error) { exit(EXIT_FAILURE); } } } if (need_newline) { printf("\n"); } ++loop_count; } while (loop && exitcode == 0); //tear down the suite if needed symbol = dlsym(handle, "teardown_suite"); if (symbol != NULL) { my_teardown_suite.voidptr = symbol; if (!(*my_teardown_suite.teardown_suite)()) { fprintf(stderr, "Failed to teardown up test suite %s \n", test_suite); } } printf("# Passed %d of %d tests\n", num_cases - exitcode, num_cases); return exitcode; }