/*- * Public Domain 2014-2019 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "test_util.h" #ifndef _WIN32 #include #endif void (*custom_die)(void) = NULL; const char *progname = "program name not set"; /* * testutil_die -- * Report an error and abort. */ void testutil_die(int e, const char *fmt, ...) { va_list ap; /* Flush output to be sure it doesn't mix with fatal errors. */ (void)fflush(stdout); (void)fflush(stderr); /* Allow test programs to cleanup on fatal error. */ if (custom_die != NULL) (*custom_die)(); fprintf(stderr, "%s: FAILED", progname); if (fmt != NULL) { fprintf(stderr, ": "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } if (e != 0) fprintf(stderr, ": %s", wiredtiger_strerror(e)); fprintf(stderr, "\n"); fprintf(stderr, "process aborting\n"); abort(); } /* * testutil_set_progname -- * Set the global program name for error handling. */ const char * testutil_set_progname(char * const *argv) { if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; return (progname); } /* * testutil_work_dir_from_path -- * Takes a buffer, its size and the intended work directory. * Creates the full intended work directory in buffer. */ void testutil_work_dir_from_path(char *buffer, size_t len, const char *dir) { /* If no directory is provided, use the default. */ if (dir == NULL) dir = DEFAULT_DIR; if (len < strlen(dir) + 1) testutil_die(ENOMEM, "Not enough memory in buffer for directory %s", dir); strcpy(buffer, dir); } /* * testutil_clean_work_dir -- * Remove the work directory. */ void testutil_clean_work_dir(const char *dir) { size_t len; int ret; char *buf; #ifdef _WIN32 /* Additional bytes for the Windows rd command. */ len = 2 * strlen(dir) + strlen(RM_COMMAND) + strlen(DIR_EXISTS_COMMAND) + 4; if ((buf = malloc(len)) == NULL) testutil_die(ENOMEM, "Failed to allocate memory"); testutil_check(__wt_snprintf( buf, len, "%s %s %s %s", DIR_EXISTS_COMMAND, dir, RM_COMMAND, dir)); #else len = strlen(dir) + strlen(RM_COMMAND) + 1; if ((buf = malloc(len)) == NULL) testutil_die(ENOMEM, "Failed to allocate memory"); testutil_check(__wt_snprintf(buf, len, "%s%s", RM_COMMAND, dir)); #endif if ((ret = system(buf)) != 0 && ret != ENOENT) testutil_die(ret, "%s", buf); free(buf); } /* * testutil_make_work_dir -- * Delete the existing work directory, then create a new one. */ void testutil_make_work_dir(const char *dir) { size_t len; char *buf; testutil_clean_work_dir(dir); /* Additional bytes for the mkdir command */ len = strlen(dir) + strlen(MKDIR_COMMAND) + 1; if ((buf = malloc(len)) == NULL) testutil_die(ENOMEM, "Failed to allocate memory"); /* mkdir shares syntax between Windows and Linux */ testutil_check(__wt_snprintf(buf, len, "%s%s", MKDIR_COMMAND, dir)); testutil_check(system(buf)); free(buf); } /* * testutil_progress -- * Print a progress message to the progress file. */ void testutil_progress(TEST_OPTS *opts, const char *message) { FILE *fp; time_t now; if ((fp = fopen(opts->progress_file_name, "a")) == NULL) testutil_die(errno, "fopen"); (void)time(&now); fprintf(fp, "[%" PRIuMAX "] %s\n", (uintmax_t)now, message); if (fclose(fp) != 0) testutil_die(errno, "fclose"); } /* * testutil_cleanup -- * Delete the existing work directory and free the options structure. */ void testutil_cleanup(TEST_OPTS *opts) { if (opts->conn != NULL) testutil_check(opts->conn->close(opts->conn, NULL)); if (!opts->preserve) testutil_clean_work_dir(opts->home); free(opts->uri); free(opts->progress_file_name); free(opts->home); } /* * testutil_is_flag_set -- * Return if an environment variable flag is set. */ bool testutil_is_flag_set(const char *flag) { const char *res; bool flag_being_set; if (__wt_getenv(NULL, flag, &res) != 0 || res == NULL) return (false); /* * This is a boolean test. So if the environment variable is set to any * value other than 0, we return success. */ flag_being_set = res[0] != '0'; free((void *)res); return (flag_being_set); } /* * testutil_print_command_line -- * Print command line arguments for csuite tests. */ void testutil_print_command_line(int argc, char * const *argv) { int i; printf("Running test command: "); for (i = 0; i < argc; i++) printf("%s ", argv[i]); printf("\n"); } #ifndef _WIN32 /* * testutil_sleep_wait -- * Wait for a process up to a number of seconds. */ void testutil_sleep_wait(uint32_t seconds, pid_t pid) { pid_t got; int status; while (seconds > 0) { if ((got = waitpid(pid, &status, WNOHANG|WUNTRACED)) == pid) { if (WIFEXITED(status)) testutil_die(EINVAL, "Child process %" PRIu64 " exited early" " with status %d", (uint64_t)pid, WEXITSTATUS(status)); if (WIFSIGNALED(status)) testutil_die(EINVAL, "Child process %" PRIu64 " terminated " " with signal %d", (uint64_t)pid, WTERMSIG(status)); } else if (got == -1) testutil_die(errno, "waitpid"); --seconds; sleep(1); } } #endif /* * dcalloc -- * Call calloc, dying on failure. */ void * dcalloc(size_t number, size_t size) { void *p; if ((p = calloc(number, size)) != NULL) return (p); testutil_die(errno, "calloc: %" WT_SIZET_FMT "B", number * size); } /* * dmalloc -- * Call malloc, dying on failure. */ void * dmalloc(size_t len) { void *p; if ((p = malloc(len)) != NULL) return (p); testutil_die(errno, "malloc: %" WT_SIZET_FMT "B", len); } /* * drealloc -- * Call realloc, dying on failure. */ void * drealloc(void *p, size_t len) { void *t; if ((t = realloc(p, len)) != NULL) return (t); testutil_die(errno, "realloc: %" WT_SIZET_FMT "B", len); } /* * dstrdup -- * Call strdup, dying on failure. */ void * dstrdup(const void *str) { char *p; if ((p = strdup(str)) != NULL) return (p); testutil_die(errno, "strdup"); } /* * dstrndup -- * Call emulating strndup, dying on failure. Don't use actual strndup here * as it is not supported within MSVC. */ void * dstrndup(const char *str, size_t len) { char *p; p = dcalloc(len + 1, sizeof(char)); memcpy(p, str, len); return (p); } /* * example_setup -- * Set the program name, create a home directory for the example programs. */ const char * example_setup(int argc, char * const *argv) { const char *home; (void)argc; /* Unused variable */ (void)testutil_set_progname(argv); /* * Create a clean test directory for this run of the test program if the * environment variable isn't already set (as is done by make check). */ if ((home = getenv("WIREDTIGER_HOME")) == NULL) home = "WT_HOME"; testutil_make_work_dir(home); return (home); }