From 751e342e158ae65052ce098ccd64aa54e39312db Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Thu, 16 Feb 2012 18:39:27 -0800 Subject: [PATCH] Update libtest/associated tests. --- clients/memcapable.cc | 100 +++++- clients/memcat.cc | 55 +-- clients/memerror.cc | 58 +-- configure.ac | 6 + libtest/binaries.cc | 11 +- libtest/blobslap_worker.cc | 2 +- libtest/cmdline.cc | 382 +++++++++++++++++++- libtest/cmdline.h | 113 +++++- libtest/comparison.hpp | 2 +- libtest/dream.cc | 43 +++ libtest/dream.h | 29 ++ libtest/gearmand.cc | 22 +- libtest/has.cc | 59 +++ libtest/has.hpp | 28 ++ libtest/http.cc | 157 ++++++++ libtest/http.hpp | 119 +++++++ libtest/include.am | 20 +- libtest/libtool.cc | 11 +- libtest/memcached.cc | 4 +- libtest/server.cc | 85 +++-- libtest/server.h | 6 +- libtest/server_container.cc | 1 - libtest/signal.cc | 25 +- libtest/signal.h | 4 +- libtest/skiptest.cc | 5 - libtest/string.hpp | 6 +- libtest/test.cc | 453 ++++++++++++++---------- libtest/test.h | 19 +- libtest/test.hpp | 5 + libtest/unittest.cc | 256 ++++++++++++- libtest/vchar.cc | 58 +++ libtest/vchar.hpp | 41 +++ libtest/wait.cc | 41 ++- tests/cli.am | 6 + tests/libmemcached-1.0/mem_functions.cc | 8 +- tests/memcapable.cc | 24 +- tests/memcat.cc | 16 +- tests/memcp.cc | 13 +- tests/memdump.cc | 13 +- tests/memerror.cc | 38 +- tests/memflush.cc | 13 +- tests/memrm.cc | 15 +- tests/memslap.cc | 43 ++- util/daemon.cc | 2 +- util/instance.cc | 29 +- util/operation.cc | 2 + util/signal.hpp | 4 + util/string.hpp | 2 + 48 files changed, 2017 insertions(+), 437 deletions(-) create mode 100644 libtest/dream.cc create mode 100644 libtest/dream.h create mode 100644 libtest/has.cc create mode 100644 libtest/has.hpp create mode 100644 libtest/http.cc create mode 100644 libtest/http.hpp create mode 100644 libtest/vchar.cc create mode 100644 libtest/vchar.hpp diff --git a/clients/memcapable.cc b/clients/memcapable.cc index 9bd310c5..bc3b551f 100644 --- a/clients/memcapable.cc +++ b/clients/memcapable.cc @@ -244,10 +244,14 @@ static enum test_return ensure(bool val, const char *expression, const char *fil if (!val) { if (verbose) + { fprintf(stderr, "\n%s:%d: %s", file, line, expression); + } if (do_core) + { abort(); + } return TEST_FAIL; } @@ -271,9 +275,14 @@ static enum test_return retry_write(const void* buf, size_t len) size_t num_bytes= len - offset; ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes); if (nw == -1) + { verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); + } else + { offset+= (size_t)nw; + } + } while (offset < len); return TEST_PASS; @@ -286,7 +295,7 @@ static enum test_return retry_write(const void* buf, size_t len) static enum test_return resend_packet(command *cmd) { size_t length= sizeof (protocol_binary_request_no_extras) + - ntohl(cmd->plain.message.header.request.bodylen); + ntohl(cmd->plain.message.header.request.bodylen); execute(retry_write(cmd, length)); return TEST_PASS; @@ -324,8 +333,10 @@ static enum test_return retry_read(void *buf, size_t len) fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno)); verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); break; + case 0: return TEST_FAIL; + default: offset+= (size_t)nr; } @@ -669,9 +680,13 @@ static enum test_return test_binary_set_impl(const char* key, uint8_t cc) for (int ii= 0; ii < 10; ii++) { if (ii == 0) + { execute(send_packet(&cmd)); + } else + { execute(resend_packet(&cmd)); + } if (cc == PROTOCOL_BINARY_CMD_SET) { @@ -799,17 +814,25 @@ static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) for (int ii= 0; ii < 10; ii++) { if (ii == 0) + { execute(send_packet(&cmd)); + } else + { execute(resend_packet(&cmd)); + } if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0) { uint16_t expected_result; if (ii == 0) + { expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; + } else + { expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS; + } execute(send_binary_noop()); execute(recv_packet(&rsp)); @@ -820,7 +843,9 @@ static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) execute(binary_set_item(key, key)); } else + { execute(test_binary_noop()); + } } /* verify that replace with CAS value works! */ @@ -1094,16 +1119,24 @@ static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) const char *value; if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + { value="hello"; + } else + { value=" world"; + } execute(binary_set_item(key, value)); if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + { value=" world"; + } else + { value="hello"; + } raw_command(&cmd, cc, key, strlen(key), value, strlen(value)); execute(send_packet(&cmd)); @@ -1113,7 +1146,9 @@ static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); } else + { execute(test_binary_noop()); + } raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); execute(send_packet(&cmd)); @@ -1285,7 +1320,9 @@ static enum test_return test_ascii_set_impl(const char* key, bool noreply) execute(send_string(buffer)); if (!noreply) + { execute(receive_response("STORED\r\n")); + } return test_ascii_version(); } @@ -1308,12 +1345,16 @@ static enum test_return test_ascii_add_impl(const char* key, bool noreply) execute(send_string(buffer)); if (!noreply) + { execute(receive_response("STORED\r\n")); + } execute(send_string(buffer)); if (!noreply) + { execute(receive_response("NOT_STORED\r\n")); + } return test_ascii_version(); } @@ -1408,14 +1449,18 @@ static enum test_return ascii_get_item(const char *key, const char *value, char buffer[1024]; size_t datasize= 0; if (value != NULL) + { datasize= strlen(value); + } verify(datasize < sizeof(buffer)); snprintf(buffer, sizeof(buffer), "get %s\r\n", key); execute(send_string(buffer)); if (exist) + { execute(ascii_get_value(key, value)); + } execute(retry_read(buffer, 5)); verify(memcmp(buffer, "END\r\n", 5) == 0); @@ -1471,7 +1516,9 @@ static enum test_return ascii_gets_item(const char *key, const char *value, char buffer[1024]; size_t datasize= 0; if (value != NULL) + { datasize= strlen(value); + } verify(datasize < sizeof(buffer)); snprintf(buffer, sizeof(buffer), "gets %s\r\n", key); @@ -1505,9 +1552,13 @@ static enum test_return test_ascii_replace_impl(const char* key, bool noreply) execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("NOT_STORED\r\n")); + } execute(ascii_set_item(key, "value")); execute(ascii_get_item(key, "value", true)); @@ -1545,17 +1596,25 @@ static enum test_return test_ascii_cas_impl(const char* key, bool noreply) execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("STORED\r\n")); + } /* reexecute the same command should fail due to illegal cas */ execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("EXISTS\r\n")); + } return test_ascii_version(); } @@ -1647,7 +1706,9 @@ static enum test_return test_ascii_mget(void) }; for (uint32_t x= 0; x < nkeys; ++x) + { execute(ascii_set_item(keys[x], "value")); + } /* Ask for a key that doesn't exist as well */ execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 " @@ -1686,7 +1747,9 @@ static enum test_return test_ascii_mget(void) } for (uint32_t x= 0; x < nkeys; ++x) + { free(returned[x]); + } return TEST_PASS; } @@ -1738,7 +1801,9 @@ static enum test_return test_ascii_decr_impl(const char* key, bool noreply) execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else { char buffer[80]; @@ -1753,7 +1818,9 @@ static enum test_return test_ascii_decr_impl(const char* key, bool noreply) /* verify that it doesn't wrap */ execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else { char buffer[80]; @@ -1827,9 +1894,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(ascii_set_item(key, value)); if (append) + { value=" world"; + } else + { value="hello"; + } char cmd[400]; snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n", @@ -1839,9 +1910,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("STORED\r\n")); + } execute(ascii_get_item(key, "hello world", true)); @@ -1852,9 +1927,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("NOT_STORED\r\n")); + } return TEST_PASS; } @@ -2038,7 +2117,7 @@ int main(int argc, char **argv) "\t-a\tOnly test the ascii protocol\n" "\t-b\tOnly test the binary protocol\n", argv[0]); - return EXIT_FAILURE; + return EXIT_SUCCESS; } } @@ -2054,7 +2133,9 @@ int main(int argc, char **argv) for (int ii= 0; testcases[ii].description != NULL; ++ii) { if (testname != NULL && strcmp(testcases[ii].description, testname) != 0) - continue; + { + continue; + } if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) || (testcases[ii].description[0] == 'b' && (tests.binary) == 0)) @@ -2078,7 +2159,9 @@ int main(int argc, char **argv) continue; } if (strncmp(buffer, "quit", 4) == 0) - exit(0); + { + exit(EXIT_SUCCESS); + } } fprintf(stdout, "%-40s", testcases[ii].description); @@ -2103,8 +2186,7 @@ int main(int argc, char **argv) closesocket(sock); if ((sock= connect_server(hostname, port)) == INVALID_SOCKET) { - fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", - hostname, port, strerror(get_socket_errno())); + fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname, port, strerror(get_socket_errno())); fprintf(stderr, "%d of %d tests failed\n", failed, total); return EXIT_FAILURE; } @@ -2113,9 +2195,13 @@ int main(int argc, char **argv) closesocket(sock); if (failed == 0) + { fprintf(stdout, "All tests passed\n"); + } else + { fprintf(stderr, "%d of %d tests failed\n", failed, total); + } - return (failed == 0) ? 0 : 1; + return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/clients/memcat.cc b/clients/memcat.cc index ab482e5d..86ae279c 100644 --- a/clients/memcat.cc +++ b/clients/memcat.cc @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) memcached_return_t rc; memcached_server_st *servers; - int return_code= 0; + int return_code= EXIT_SUCCESS; options_parse(argc, argv); initialize_sockets(); @@ -55,11 +55,13 @@ int main(int argc, char *argv[]) char *temp; if ((temp= getenv("MEMCACHED_SERVERS"))) + { opt_servers= strdup(temp); + } else { - fprintf(stderr, "No Servers provided\n"); - exit(1); + std::cerr << "No servers provied" << std::endl; + exit(EXIT_FAILURE); } } @@ -100,69 +102,66 @@ int main(int argc, char *argv[]) if (opt_displayflag) { if (opt_verbose) - printf("key: %s\nflags: ", argv[optind]); - printf("%x\n", flags); + { + std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << std::endl; + } } else { if (opt_verbose) { - printf("key: %s\nflags: %x\nlength: %lu\nvalue: ", - argv[optind], flags, (unsigned long)string_length); + std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << "length: " << string_length << std::endl << "value: "; } if (opt_file) { - FILE *fp; - size_t written; - - fp= fopen(opt_file, "w"); - if (!fp) + FILE *fp= fopen(opt_file, "w"); + if (fp == NULL) { perror("fopen"); - return_code= -1; + return_code= EXIT_FAILURE; break; } - written= fwrite(string, 1, string_length, fp); + size_t written= fwrite(string, 1, string_length, fp); if (written != string_length) { - fprintf(stderr, "error writing file (written %lu, should be %lu)\n", (unsigned long)written, (unsigned long)string_length); - return_code= -1; + std::cerr << "error writing file to file " << opt_file << " wrote " << written << ", should have written" << string_length << std::endl; + return_code= EXIT_FAILURE; break; } if (fclose(fp)) { - fprintf(stderr, "error closing file\n"); - return_code= -1; + std::cerr << "error closing " << opt_file << std::endl; + return_code= EXIT_FAILURE; break; } } else { - printf("%.*s\n", (int)string_length, string); + std::cout.write(string, string_length); + std::cout << std::endl; } free(string); } } else if (rc != MEMCACHED_NOTFOUND) { - fprintf(stderr, "memcat: %s: memcache error %s", - argv[optind], memcached_strerror(memc, rc)); + std::cerr << "error on " << argv[optind] << "(" << memcached_strerror(memc, rc) << ")"; if (memcached_last_error_errno(memc)) { - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + std::cerr << " system error (" << strerror(memcached_last_error_errno(memc)) << ")" << std::endl; } - fprintf(stderr, "\n"); + std::cerr << std::endl; - return_code= -1; + return_code= EXIT_FAILURE; break; } else // Unknown Issue { - fprintf(stderr, "memcat: %s not found\n", argv[optind]); - return_code= -1; + std::cerr << "error on " << argv[optind] << "("<< memcached_strerror(NULL, rc) << ")" << std::endl; + return_code= EXIT_FAILURE; } optind++; } @@ -170,9 +169,13 @@ int main(int argc, char *argv[]) memcached_free(memc); if (opt_servers) + { free(opt_servers); + } if (opt_hash) + { free(opt_hash); + } return return_code; } diff --git a/clients/memerror.cc b/clients/memerror.cc index fd4238a5..17bc531c 100644 --- a/clients/memerror.cc +++ b/clients/memerror.cc @@ -10,10 +10,12 @@ */ #include "config.h" -#include +#include #include #include #include +#include + #include #include #include @@ -29,27 +31,40 @@ /* Prototypes */ void options_parse(int argc, char *argv[]); -static int opt_verbose= 0; - int main(int argc, char *argv[]) { options_parse(argc, argv); - if (argc != 2) + if (argc < 2) { return EXIT_FAILURE; } - unsigned long value= strtoul(argv[1], (char **) NULL, 10); - - if (value < MEMCACHED_MAXIMUM_RETURN) + while (optind < argc) { - std::cout << memcached_strerror(NULL, (memcached_return_t)value) << std::endl; - } - else - { - std::cerr << memcached_strerror(NULL, MEMCACHED_MAXIMUM_RETURN) << std::endl; - return EXIT_FAILURE; + errno= 0; + char *nptr; + unsigned long value= strtoul(argv[optind], &nptr, 10); + + if ((nptr == argv[optind] and value == 0) or + (value == ULONG_MAX and errno == ERANGE) or + (value == 0 and errno == EINVAL)) + { + std::cerr << "strtoul() was unable to parse given value" << std::endl; + return EXIT_FAILURE; + } + + if (value < MEMCACHED_MAXIMUM_RETURN) + { + std::cout << memcached_strerror(NULL, (memcached_return_t)value) << std::endl; + } + else + { + std::cerr << memcached_strerror(NULL, MEMCACHED_MAXIMUM_RETURN) << std::endl; + return EXIT_FAILURE; + } + + optind++; } return EXIT_SUCCESS; @@ -62,9 +77,6 @@ void options_parse(int argc, char *argv[]) { {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, {0, 0, 0, 0}, }; @@ -84,14 +96,6 @@ void options_parse(int argc, char *argv[]) case 0: break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ opt_version= true; break; @@ -100,16 +104,12 @@ void options_parse(int argc, char *argv[]) opt_help= true; break; - case OPT_QUIET: - close_stdio(); - break; - case '?': /* getopt_long already printed an error message. */ exit(EXIT_FAILURE); default: - abort(); + exit(EXIT_FAILURE); } } diff --git a/configure.ac b/configure.ac index 217626cd..8bb9a60a 100644 --- a/configure.ac +++ b/configure.ac @@ -203,6 +203,12 @@ AS_IF([test "x$ac_cv_header_atomic_h" = "xyes"],[ [1], [Define to true if you want to use functions from atomic.h])])]) +AC_DEFINE([HAVE_LIBDRIZZLE], [0], [Support for libdrizzle]) +AC_DEFINE([HAVE_DRIZZLED_BINARY], [0], [Support for DrizzleD]) +AC_DEFINE([GEARMAND_BLOBSLAP_WORKER], [0], [Support for Gearman Blobslap worker]) +AC_DEFINE([HAVE_LIBPQ], [0], [Support for Postgres]) +AC_DEFINE([HAVE_LIBCURL], [0], [Support for libcurl]) + AC_CHECK_HEADERS_ONCE(winsock2.h poll.h sys/wait.h fnmatch.h) AM_CONDITIONAL(BUILD_POLL, test "x$ac_cv_header_poll_h" = "xno") AM_CONDITIONAL(BUILD_WIN32_WRAPPERS, test "x$ac_cv_header_winsock2_h" = "xyes") diff --git a/libtest/binaries.cc b/libtest/binaries.cc index 00a89766..33cde3b7 100644 --- a/libtest/binaries.cc +++ b/libtest/binaries.cc @@ -27,7 +27,16 @@ namespace libtest { bool has_gearmand_binary() { #if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY - if (access(GEARMAND_BINARY,R_OK|X_OK) == 0) + std::stringstream arg_buffer; + + if (getenv("PWD")) + { + arg_buffer << getenv("PWD"); + arg_buffer << "/"; + } + arg_buffer << GEARMAND_BINARY; + + if (access(arg_buffer.str().c_str() ,R_OK|X_OK) == 0) { return true; } diff --git a/libtest/blobslap_worker.cc b/libtest/blobslap_worker.cc index 7c7975ed..8bbd0738 100644 --- a/libtest/blobslap_worker.cc +++ b/libtest/blobslap_worker.cc @@ -119,7 +119,7 @@ public: const char *executable() { - return GEARMAND_BLOBSLAP_WORKER; + return "benchmark/blobslap_worker"; } const char *pid_file_option() diff --git a/libtest/cmdline.cc b/libtest/cmdline.cc index 4dc84c9d..7c2f5f44 100644 --- a/libtest/cmdline.cc +++ b/libtest/cmdline.cc @@ -24,39 +24,393 @@ using namespace libtest; #include -#include +#include +#include +#include +#include #include +#include +#include +#include + +extern "C" { + static int exited_successfully(int status) + { + if (status == 0) + { + return EXIT_SUCCESS; + } + + if (WIFEXITED(status) == true) + { + return WEXITSTATUS(status); + } + else if (WIFSIGNALED(status) == true) + { + return WTERMSIG(status); + } + + return EXIT_FAILURE; + } +} + +namespace { + + std::string print_argv(char * * & built_argv, const size_t& argc, const pid_t& pid) + { + std::stringstream arg_buffer; + + for (size_t x= 0; x < argc; x++) + { + arg_buffer << built_argv[x] << " "; + } + + return arg_buffer.str(); + } + +} namespace libtest { -bool exec_cmdline(const std::string& executable, const char *args[]) +Application::Application(const std::string& arg, const bool _use_libtool_arg) : + _use_libtool(_use_libtool_arg), + _argc(0), + _exectuble(arg), + built_argv(NULL), + _pid(-1) + { + if (_use_libtool) + { + if (libtool() == NULL) + { + throw "libtool requested, but know libtool was found"; + } + } + + if (_use_libtool and getenv("PWD")) + { + _exectuble_with_path+= getenv("PWD"); + _exectuble_with_path+= "/"; + } + _exectuble_with_path+= _exectuble; + } + +Application::~Application() +{ + delete_argv(); +} + +Application::error_t Application::run(const char *args[]) { - std::stringstream arg_buffer; + stdin_fd.reset(); + stdout_fd.reset(); + stderr_fd.reset(); + _stdout_buffer.clear(); + _stderr_buffer.clear(); - arg_buffer << libtool(); + posix_spawn_file_actions_t file_actions; + posix_spawn_file_actions_init(&file_actions); - if (getenv("PWD")) + stdin_fd.dup_for_spawn(Application::Pipe::READ, file_actions, STDIN_FILENO); + stdout_fd.dup_for_spawn(Application::Pipe::WRITE, file_actions, STDOUT_FILENO); + stderr_fd.dup_for_spawn(Application::Pipe::WRITE, file_actions, STDERR_FILENO); + + create_argv(args); + + int spawn_ret; + if (_use_libtool) { - arg_buffer << getenv("PWD"); - arg_buffer << "/"; + spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL); } + else + { + spawn_ret= posix_spawnp(&_pid, built_argv[0], &file_actions, NULL, built_argv, NULL); + } + + posix_spawn_file_actions_destroy(&file_actions); - arg_buffer << executable; - for (const char **ptr= args; *ptr; ++ptr) + stdin_fd.close(Application::Pipe::READ); + stdout_fd.close(Application::Pipe::WRITE); + stderr_fd.close(Application::Pipe::WRITE); + + if (spawn_ret) { - arg_buffer << " " << *ptr; + Error << print(); + return Application::INVALID; } + return Application::SUCCESS; +} + +Application::error_t Application::wait() +{ + if (_pid == -1) + { + Error << "wait() got an invalid pid_t"; + return Application::INVALID; + } + + { + ssize_t read_length; + char buffer[1024]= { 0 }; + bool bail= false; + while (((read_length= ::read(stdout_fd.fd()[0], buffer, sizeof(buffer))) != 0) or bail) + { + if (read_length == -1) + { + switch(errno) + { + case EAGAIN: + continue; + + default: + Error << strerror(errno); + bail= true; + } + } + _stdout_buffer.reserve(read_length +1); + for (size_t x= 0; x < read_length; x++) + { + _stdout_buffer.push_back(buffer[x]); + } + // @todo Suck up all output code here + } + } + + { + ssize_t read_length; + char buffer[1024]= { 0 }; + bool bail= false; + while (((read_length= ::read(stderr_fd.fd()[0], buffer, sizeof(buffer))) != 0) or bail) + { + if (read_length == -1) + { + switch(errno) + { + case EAGAIN: + continue; + + default: + Error << strerror(errno); + bail= true; + } + } + _stderr_buffer.reserve(read_length +1); + for (size_t x= 0; x < read_length; x++) + { + _stderr_buffer.push_back(buffer[x]); + } + // @todo Suck up all errput code here + } + } + + error_t exit_code= FAILURE; + { + int status= 0; + pid_t waited_pid; + if ((waited_pid= waitpid(_pid, &status, 0)) == -1) + { + Error << "Error occured while waitpid(" << strerror(errno) << ") on pid " << int(_pid); + } + else + { + assert(waited_pid == _pid); + exit_code= error_t(exited_successfully(status)); + } + } + + if (exit_code == Application::INVALID) + { #if 0 - arg_buffer << " > /dev/null 2>&1"; + Error << print_argv(built_argv, _argc, _pid); #endif + } + + return exit_code; +} + +void Application::add_option(const std::string& arg) +{ + _options.push_back(std::make_pair(arg, std::string())); +} + +void Application::add_option(const std::string& name, const std::string& value) +{ + _options.push_back(std::make_pair(name, value)); +} + +Application::Pipe::Pipe() +{ + _fd[0]= -1; + _fd[1]= -1; + _open[0]= false; + _open[1]= false; +} + +void Application::Pipe::reset() +{ + close(READ); + close(WRITE); + + int ret; + if ((ret= pipe(_fd)) < 0) + { + throw strerror(ret); + } + _open[0]= true; + _open[1]= true; + + { + ret= fcntl(_fd[0], F_GETFL, 0); + if (ret == -1) + { + Error << "fcntl(F_GETFL) " << strerror(ret); + throw strerror(ret); + } + + ret= fcntl(_fd[0], F_SETFL, ret | O_NONBLOCK); + if (ret == -1) + { + Error << "fcntl(F_SETFL) " << strerror(ret); + throw strerror(ret); + } + } +} + +Application::Pipe::~Pipe() +{ + close(READ); + close(WRITE); +} + +void Application::Pipe::dup_for_spawn(const close_t& arg, posix_spawn_file_actions_t& file_actions, const int newfildes) +{ + int type= int(arg); + + int ret; + if ((ret= posix_spawn_file_actions_adddup2(&file_actions, _fd[type], newfildes )) < 0) + { + Error << "posix_spawn_file_actions_adddup2(" << strerror(ret) << ")"; + throw strerror(ret); + } + + if ((ret= posix_spawn_file_actions_addclose(&file_actions, _fd[type])) < 0) + { + Error << "posix_spawn_file_actions_adddup2(" << strerror(ret) << ")"; + throw strerror(ret); + } +} + +void Application::Pipe::close(const close_t& arg) +{ + int type= int(arg); + + if (_open[type]) + { + int ret; + if ((ret= ::close(_fd[type])) < 0) + { + Error << "close(" << strerror(ret) << ")"; + } + _open[type]= false; + } +} + +void Application::create_argv(const char *args[]) +{ + _argc= 2 +_use_libtool ? 2 : 0; // +1 for the command, +2 for libtool/mode=execute, +1 for the NULL + + if (_use_libtool) + { + _argc+= 2; // +2 for libtool --mode=execute + } + + for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++) + { + _argc++; + if ((*iter).second.empty() == false) + { + _argc++; + } + } + + if (args) + { + for (const char **ptr= args; *ptr; ++ptr) + { + _argc++; + } + } + + delete_argv(); + built_argv= new char * [_argc]; + + size_t x= 0; + if (_use_libtool) + { + assert(libtool()); + built_argv[x++]= strdup(libtool()); + built_argv[x++]= strdup("--mode=execute"); + } + built_argv[x++]= strdup(_exectuble_with_path.c_str()); + + for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++) + { + built_argv[x++]= strdup((*iter).first.c_str()); + if ((*iter).second.empty() == false) + { + built_argv[x++]= strdup((*iter).second.c_str()); + } + } + + if (args) + { + for (const char **ptr= args; *ptr; ++ptr) + { + built_argv[x++]= strdup(*ptr); + } + } + built_argv[_argc -1]= NULL; +} + +std::string Application::print() +{ + return print_argv(built_argv, _argc, _pid); +} + +void Application::delete_argv() +{ + if (built_argv == NULL) + { + return; + } + + for (size_t x= 0; x < _argc; x++) + { + if (built_argv[x]) + { + ::free(built_argv[x]); + } + } + delete[] built_argv; + built_argv= NULL; + _argc= 0; +} + + +int exec_cmdline(const std::string& command, const char *args[], bool use_libtool) +{ + Application app(command, use_libtool); + + Application::error_t ret= app.run(args); - if (system(arg_buffer.str().c_str()) == -1) + if (ret != Application::SUCCESS) { - return false; + return int(ret); } + ret= app.wait(); - return true; + return int(ret); } const char *gearmand_binary() diff --git a/libtest/cmdline.h b/libtest/cmdline.h index dcb4b0ab..d1019d54 100644 --- a/libtest/cmdline.h +++ b/libtest/cmdline.h @@ -21,9 +21,120 @@ #pragma once +#include + namespace libtest { -bool exec_cmdline(const std::string& executable, const char *args[]); +class Application { +private: + typedef std::vector< std::pair > Options; + +public: + + enum error_t { + SUCCESS= EXIT_SUCCESS, + FAILURE= EXIT_FAILURE, + INVALID= 127 + }; + + class Pipe { + public: + Pipe(); + ~Pipe(); + + int* fd() + { + return _fd; + } + + enum close_t { + READ, + WRITE + }; + + void reset(); + void close(const close_t& arg); + void dup_for_spawn(const close_t& arg, + posix_spawn_file_actions_t& file_actions, + const int newfildes); + + private: + int _fd[2]; + bool _open[2]; + }; + +public: + Application(const std::string& arg, const bool _use_libtool_arg= false); + + virtual ~Application(); + + void add_option(const std::string&); + void add_option(const std::string&, const std::string&); + error_t run(const char *args[]= NULL); + error_t wait(); + + libtest::vchar_t stdout_result() const + { + return _stdout_buffer; + } + + size_t stdout_result_length() const + { + return _stdout_buffer.size(); + } + + libtest::vchar_t stderr_result() const + { + return _stderr_buffer; + } + + size_t stderr_result_length() const + { + return _stderr_buffer.size(); + } + + std::string print(); + +private: + void create_argv(const char *args[]); + void delete_argv(); + +private: + const bool _use_libtool; + size_t _argc; + std::string _exectuble; + std::string _exectuble_with_path; + Options _options; + Pipe stdin_fd; + Pipe stdout_fd; + Pipe stderr_fd; + char * * built_argv; + pid_t _pid; + libtest::vchar_t _stdout_buffer; + libtest::vchar_t _stderr_buffer; +}; + +static inline std::ostream& operator<<(std::ostream& output, const enum Application::error_t &arg) +{ + switch (arg) + { + case Application::SUCCESS: + output << "EXIT_SUCCESS"; + break; + + case Application::FAILURE: + output << "EXIT_FAILURE"; + break; + + case Application::INVALID: + output << "127"; + break; + } + + return output; +} + +int exec_cmdline(const std::string& executable, const char *args[], bool use_libtool= false); const char *gearmand_binary(); diff --git a/libtest/comparison.hpp b/libtest/comparison.hpp index 33cfa5a5..bcb7558e 100644 --- a/libtest/comparison.hpp +++ b/libtest/comparison.hpp @@ -29,7 +29,7 @@ #endif #if defined(HAVE_LIBGEARMAN) && HAVE_LIBGEARMAN -#include +#include #endif namespace libtest { diff --git a/libtest/dream.cc b/libtest/dream.cc new file mode 100644 index 00000000..32dece35 --- /dev/null +++ b/libtest/dream.cc @@ -0,0 +1,43 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include + +namespace libtest { + +void dream(time_t tv_sec, long tv_nsec) +{ +#ifdef WIN32 + if (tv_sec == 0 and tv_nsec) + { + tv_sec++; + } + sleep(tv_sec); +#else + struct timespec requested; + requested.tv_sec= tv_sec; + requested.tv_nsec= tv_nsec; + nanosleep(&requested, NULL); +#endif +} + +} diff --git a/libtest/dream.h b/libtest/dream.h new file mode 100644 index 00000000..e702aa6b --- /dev/null +++ b/libtest/dream.h @@ -0,0 +1,29 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +namespace libtest { + +void dream(time_t tv_sec, long tv_nsec= 0); + +} + diff --git a/libtest/gearmand.cc b/libtest/gearmand.cc index deac09f3..bcb7f8aa 100644 --- a/libtest/gearmand.cc +++ b/libtest/gearmand.cc @@ -96,7 +96,7 @@ public: pid_t get_pid(bool error_is_ok) { - if (not pid_file().empty()) + if (pid_file().empty() == false) { Wait wait(pid_file(), 0); @@ -124,12 +124,12 @@ public: bool ping() { gearman_client_st *client= gearman_client_create(NULL); - if (not client) + if (client == NULL) { Error << "Could not allocate memory for gearman_client_create()"; return false; } - gearman_client_set_timeout(client, 1000); + gearman_client_set_timeout(client, 3000); if (gearman_success(gearman_client_add_server(client, hostname().c_str(), port()))) { @@ -140,6 +140,13 @@ public: gearman_client_free(client); return true; } +#if 0 + Error << hostname().c_str() << ":" << port() << " was " << gearman_strerror(rc) << " extended: " << gearman_client_error(client); +#endif + } + else + { + Error << "gearman_client_add_server() " << gearman_client_error(client); } gearman_client_free(client); @@ -169,7 +176,7 @@ public: const char *log_file_option() { - return "-vvvvv --log-file="; + return "--verbose=DEBUG --log-file="; } const char *port_option() @@ -182,6 +189,11 @@ public: return true; } + bool has_syslog() const + { + return true; + } + bool build(int argc, const char *argv[]); }; @@ -194,7 +206,7 @@ bool Gearmand::build(int argc, const char *argv[]) arg_buffer << " -u root "; } - arg_buffer << " --listen=127.0.0.1 "; + arg_buffer << " --listen=localhost "; for (int x= 1 ; x < argc ; x++) { diff --git a/libtest/has.cc b/libtest/has.cc new file mode 100644 index 00000000..e7376c2b --- /dev/null +++ b/libtest/has.cc @@ -0,0 +1,59 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +bool has_memcached_support(void) +{ + if (HAVE_LIBMEMCACHED and HAVE_MEMCACHED_BINARY) + { + return true; + } + + return false; +} + +bool has_drizzle_support(void) +{ + if (HAVE_LIBDRIZZLE and HAVE_DRIZZLED_BINARY) + { + return true; + } + + return false; +} + +bool has_postgres_support(void) +{ + if (getenv("POSTGES_IS_RUNNING_AND_SETUP")) + { + + if (HAVE_LIBPQ) + { + return true; + } + } + + return false; +} diff --git a/libtest/has.hpp b/libtest/has.hpp new file mode 100644 index 00000000..e1b598fd --- /dev/null +++ b/libtest/has.hpp @@ -0,0 +1,28 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +bool has_memcached_support(void); + +bool has_drizzle_support(void); + +bool has_postgres_support(void); diff --git a/libtest/http.cc b/libtest/http.cc new file mode 100644 index 00000000..5309d504 --- /dev/null +++ b/libtest/http.cc @@ -0,0 +1,157 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H +#include +#else +class CURL; +#endif + +namespace libtest { +namespace http { + +#define YATL_USERAGENT "YATL/1.0" + +extern "C" size_t + http_get_result_callback(void *ptr, size_t size, size_t nmemb, void *data) + { + size_t body_size= size * nmemb; + + vchar_t *_body= (vchar_t*)data; + + _body->resize(size * nmemb); + memcpy(&_body[0], ptr, _body->size()); + + return _body->size(); + } + + +static void init(CURL *curl, const std::string& url) +{ + if (HAVE_LIBCURL) + { +#if defined(HAVE_LIBCURL) && HAVE_LIBCURL + assert(curl); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_USERAGENT, YATL_USERAGENT); +#endif + } +} + +bool GET::execute() +{ + if (HAVE_LIBCURL) + { +#if defined(HAVE_LIBCURL) && HAVE_LIBCURL + CURL *curl= curl_easy_init(); + + init(curl, url()); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body); + + CURLcode retref= curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response); + + curl_easy_cleanup(curl); + + return retref == CURLE_OK; +#endif + } + + return false; +} + +bool POST::execute() +{ + if (HAVE_LIBCURL) + { +#if defined(HAVE_LIBCURL) && HAVE_LIBCURL + CURL *curl= curl_easy_init();; + + init(curl, url()); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, _body.size()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void *)&_body[0]); + + CURLcode retref= curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response); + + curl_easy_cleanup(curl); +#endif + } + + return false; +} + +bool TRACE::execute() +{ + if (HAVE_LIBCURL) + { +#if defined(HAVE_LIBCURL) && HAVE_LIBCURL + CURL *curl= curl_easy_init();; + + init(curl, url()); + + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "TRACE"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body[0]); + + CURLcode retref= curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response); + + curl_easy_cleanup(curl); + + return retref == CURLE_OK; +#endif + } + + return false; +} + +bool HEAD::execute() +{ + if (HAVE_LIBCURL) + { +#if defined(HAVE_LIBCURL) && HAVE_LIBCURL + CURL *curl= curl_easy_init();; + + init(curl, url()); + + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback); + + CURLcode retref= curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response); + + curl_easy_cleanup(curl); + + return retref == CURLE_OK; +#endif + } + + return false; +} + +} // namespace http +} // namespace libtest diff --git a/libtest/http.hpp b/libtest/http.hpp new file mode 100644 index 00000000..012d7a07 --- /dev/null +++ b/libtest/http.hpp @@ -0,0 +1,119 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#pragma once + +namespace libtest { +namespace http { + +class HTTP { +public: + + HTTP(const std::string& url_arg) : + _url(url_arg), + _response(0) + { } + + virtual bool execute()= 0; + + virtual ~HTTP() + { } + + const std::string& url() const + { + return _url; + } + + long response() + { + return _response; + } + +private: + std::string _url; + +protected: + long _response; +}; + +class GET: public HTTP { +public: + + GET(const std::string& url_arg) : + HTTP(url_arg) + { + } + + bool execute(); + +private: + libtest::vchar_t _body; +}; + +class POST: public HTTP { +public: + + POST(const std::string& url_arg, + const vchar_t& post_arg) : + HTTP(url_arg), + _post(post_arg) + { + } + + bool execute(); + +private: + libtest::vchar_t _post; + libtest::vchar_t _body; +}; + +class TRACE: public HTTP { +public: + + TRACE(const std::string& url_arg, + const vchar_t& body_arg) : + HTTP(url_arg), + _body(body_arg) + { + } + + bool execute(); + +private: + libtest::vchar_t _body; +}; + +class HEAD: public HTTP { +public: + + HEAD(const std::string& url_arg) : + HTTP(url_arg) + { + } + + bool execute(); + +private: +}; + +} // namespace http +} // namespace libtest diff --git a/libtest/include.am b/libtest/include.am index a668d690..0ad8da4f 100644 --- a/libtest/include.am +++ b/libtest/include.am @@ -64,11 +64,14 @@ noinst_HEADERS+= \ libtest/common.h \ libtest/comparison.hpp \ libtest/core.h \ + libtest/dream.h \ libtest/error.h \ libtest/failed.h \ libtest/framework.h \ libtest/gearmand.h \ libtest/get.h \ + libtest/has.hpp \ + libtest/http.hpp \ libtest/is_pid.hpp \ libtest/is_local.hpp \ libtest/killpid.h \ @@ -86,6 +89,7 @@ noinst_HEADERS+= \ libtest/string.hpp \ libtest/test.h \ libtest/test.hpp \ + libtest/vchar.hpp \ libtest/visibility.h \ libtest/wait.h @@ -94,7 +98,10 @@ libtest_libtest_la_SOURCES= \ libtest/binaries.cc \ libtest/cmdline.cc \ libtest/core.cc \ + libtest/dream.cc \ libtest/framework.cc \ + libtest/has.cc \ + libtest/http.cc \ libtest/is_local.cc \ libtest/killpid.cc \ libtest/libtool.cc \ @@ -105,15 +112,18 @@ libtest_libtest_la_SOURCES= \ libtest/signal.cc \ libtest/socket.cc \ libtest/strerror.cc \ - libtest/test.cc + libtest/test.cc \ + libtest/vchar.cc -libtest_libtest_la_CXXFLAGS= ${AM_CXXFLAGS} +libtest_libtest_la_CXXFLAGS= libtest_libtest_la_CXXFLAGS+= ${NO_CONVERSION} libtest_libtest_la_CXXFLAGS+= -DBUILDING_LIBTEST libtest_libtest_la_CXXFLAGS+= $(PTHREAD_CFLAGS) libtest_libtest_la_CXXFLAGS+= -DLIBTEST_TEMP="\"tmp_chroot\"" +libtest_libtest_la_CXXFLAGS+= $(CURL_CFLAGS) libtest_libtest_la_LIBADD= libtest_libtest_la_LIBADD+= $(PTHREAD_LIBS) +libtest_libtest_la_LIBADD+= $(CURL_LIBS) libtest_libtest_la_DEPENDENCIES= libtest_tmp_dir # Declare unittest so that we can append to it @@ -152,10 +162,10 @@ libtest_libtest_la_SOURCES+= libtest/blobslap_worker.cc libtest_libtest_la_SOURCES+= libtest/gearmand.cc libtest_libtest_la_SOURCES+= util/instance.cc libtest_libtest_la_SOURCES+= util/operation.cc -libtest_libtest_la_CXXFLAGS+= -DGEARMAND_BLOBSLAP_WORKER="\"${abs_top_builddir}/benchmark/blobslap_worker\"" libtest_unittest_LDADD+= libgearman/libgearman.la libtest_unittest_DEPENDENCIES+= libgearman/libgearman.la +libtest_unittest_DEPENDENCIES+= gearmand/gearmand else if HAVE_LIBGEARMAN libtest_libtest_la_DEPENDENCIES+= libgearman/libgearman.la @@ -164,9 +174,6 @@ libtest_libtest_la_SOURCES+= libtest/blobslap_worker.cc libtest_libtest_la_SOURCES+= libtest/gearmand.cc libtest_libtest_la_SOURCES+= util/instance.cc libtest_libtest_la_SOURCES+= util/operation.cc -libtest_libtest_la_CXXFLAGS+= -DGEARMAND_BLOBSLAP_WORKER=0 -else -libtest_libtest_la_CXXFLAGS+= -DGEARMAND_BLOBSLAP_WORKER=0 endif endif @@ -188,7 +195,6 @@ tmp_chroot/var/run: tmp_chroot/var @$(mkdir_p) tmp_chroot/var/run -libtest_unittest_CXXFLAGS+= ${AM_CXXFLAGS} libtest_unittest_DEPENDENCIES+= libtest/libtest.la libtest_tmp_dir libtest_unittest_LDADD+= libtest/libtest.la libtest_unittest_SOURCES= libtest/unittest.cc diff --git a/libtest/libtool.cc b/libtest/libtool.cc index c7aa29d7..90f0035e 100644 --- a/libtest/libtool.cc +++ b/libtest/libtool.cc @@ -28,12 +28,12 @@ namespace libtest { const char *libtool(void) { - if (_libtool[0]) + if (_libtool[0] == 0) { std::string libtool_buffer; - if (getenv("srcdir")) + if (getenv("PWD")) { - libtool_buffer+= getenv("srcdir"); + libtool_buffer+= getenv("PWD"); libtool_buffer+= "/"; } else @@ -44,15 +44,14 @@ const char *libtool(void) libtool_buffer+= "libtool"; if (access(libtool_buffer.c_str(), R_OK | W_OK | X_OK)) { + Error << "Could not find libtool via access(" << libtool_buffer << ") :" << strerror(errno); return NULL; } - libtool_buffer+= " --mode=execute "; - snprintf(_libtool, sizeof(_libtool), "%s", libtool_buffer.c_str()); } return _libtool; } -} +} // namespace libtest diff --git a/libtest/memcached.cc b/libtest/memcached.cc index fc7a37c6..7d25153f 100644 --- a/libtest/memcached.cc +++ b/libtest/memcached.cc @@ -22,8 +22,8 @@ #include -#include -#include +#include +#include using namespace libtest; diff --git a/libtest/server.cc b/libtest/server.cc index 8b8b8f3e..9d492b9b 100644 --- a/libtest/server.cc +++ b/libtest/server.cc @@ -43,14 +43,37 @@ static inline std::string &rtrim(std::string &s) #include extern "C" { - static bool exited_successfully(int status) + static bool exited_successfully(int status, const std::string &command) { - if (WEXITSTATUS(status) == 0) + if (status == 0) { return true; } - return true; + if (WIFEXITED(status) == true) + { + int ret= WEXITSTATUS(status); + + if (ret == 0) + { + return true; + } + else if (ret == EXIT_FAILURE) + { + libtest::Error << "Command executed, but returned EXIT_FAILURE: " << command; + } + else + { + libtest::Error << "Command executed, but returned " << ret; + } + } + else if (WIFSIGNALED(status) == true) + { + int ret_signal= WTERMSIG(status); + libtest::Error << "Died from signal " << strsignal(ret_signal); + } + + return false; } } @@ -87,16 +110,6 @@ std::ostream& operator<<(std::ostream& output, const Server &arg) return output; // for multiple << operators } -void Server::nap(void) -{ -#ifdef WIN32 - sleep(1); -#else - struct timespec global_sleep_value= { 0, 50000 }; - nanosleep(&global_sleep_value, NULL); -#endif -} - Server::Server(const std::string& host_arg, const in_port_t port_arg, bool is_socket_arg) : _is_socket(is_socket_arg), _pid(-1), @@ -125,7 +138,7 @@ bool Server::cycle() if (kill(current_pid)) { Log << "Killed existing server," << *this << " with pid:" << current_pid; - nap(); + dream(0, 50000); continue; } } @@ -165,7 +178,7 @@ bool Server::wait_for_pidfile() const bool Server::start() { // If we find that we already have a pid then kill it. - if (has_pid() and not kill(_pid)) + if (has_pid() and kill(_pid) == false) { Error << "Could not kill() existing server during start() pid:" << _pid; return false; @@ -173,7 +186,7 @@ bool Server::start() assert(not has_pid()); _running.clear(); - if (not command(_running)) + if (command(_running) == false) { Error << "Could not build command()"; return false; @@ -185,19 +198,19 @@ bool Server::start() } int ret= system(_running.c_str()); - if (not exited_successfully(ret)) + if (exited_successfully(ret, _running) == false) { - Error << "system() failed:" << strerror(errno); + Error << "system(" << _running << ") failed: " << strerror(errno); _running.clear(); return false; } if (is_helgrind() or is_valgrind()) { - sleep(4); + dream(5, 50000); } - if (pid_file_option() and not pid_file().empty()) + if (pid_file_option() and pid_file().empty() == false) { Wait wait(pid_file(), 8); @@ -207,17 +220,20 @@ bool Server::start() } } - int count= is_helgrind() or is_valgrind() ? 20 : 5; - while (not ping() and --count) + int counter= 0; + bool pinged= false; + while ((pinged= ping()) == false and + counter < (is_helgrind() or is_valgrind() ? 20 : 5)) { - nap(); + dream(counter++, 50000); } - if (count == 0) + if (pinged == false) { // If we happen to have a pid file, lets try to kill it - if (pid_file_option() and not pid_file().empty()) + if (pid_file_option() and pid_file().empty() == false) { + Error << "We are going to kill it off"; kill_file(pid_file()); } Error << "Failed to ping() server started with:" << _running; @@ -324,6 +340,7 @@ void Server::rebuild_base_command() if (is_libtool()) { _base_command+= libtool(); + _base_command+= " --mode=execute "; } if (is_debug() and getenv("GDB_COMMAND")) @@ -342,6 +359,15 @@ void Server::rebuild_base_command() _base_command+= " "; } + if (is_libtool()) + { + if (getenv("PWD")) + { + _base_command+= getenv("PWD"); + _base_command+= "/"; + } + } + _base_command+= executable(); } @@ -365,10 +391,15 @@ bool Server::args(std::string& options) arg_buffer << " " << log_file_option() << _log_file; } + if (getenv("LIBTEST_SYSLOG") and has_syslog()) + { + arg_buffer << " --syslog"; + } + // Update pid_file if (pid_file_option()) { - if (_pid_file.empty() and not set_pid_file()) + if (_pid_file.empty() and set_pid_file() == false) { return false; } @@ -427,7 +458,7 @@ bool Server::kill(pid_t pid_arg) { if (check_pid(pid_arg) and kill_pid(pid_arg)) // If we kill it, reset { - if (broken_pid_file() and not pid_file().empty()) + if (broken_pid_file() and pid_file().empty() == false) { unlink(pid_file().c_str()); } diff --git a/libtest/server.h b/libtest/server.h index b91f55b1..b50b0b2e 100644 --- a/libtest/server.h +++ b/libtest/server.h @@ -124,6 +124,11 @@ public: return (_port != 0); } + virtual bool has_syslog() const + { + return false; + } + // Reset a server if another process has killed the server void reset() { @@ -172,7 +177,6 @@ public: bool command(std::string& command_arg); protected: - void nap(); bool set_pid_file(); private: diff --git a/libtest/server_container.cc b/libtest/server_container.cc index cd23169f..2c31796f 100644 --- a/libtest/server_container.cc +++ b/libtest/server_container.cc @@ -77,7 +77,6 @@ Server* server_startup_st::pop_server() bool server_startup_st::shutdown(uint32_t number_of_host) { - assert(servers.size() > number_of_host); if (servers.size() > number_of_host) { Server* tmp= servers[number_of_host]; diff --git a/libtest/signal.cc b/libtest/signal.cc index ed017b2b..42e6d78d 100644 --- a/libtest/signal.cc +++ b/libtest/signal.cc @@ -98,6 +98,12 @@ SignalThread::~SignalThread() } #endif sem_destroy(&lock); + + int error; + if ((error= pthread_sigmask(SIG_UNBLOCK, &set, NULL)) != 0) + { + Error << "While trying to reset signal mask to original set, pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")"; + } } extern "C" { @@ -130,6 +136,11 @@ static void *sig_thread(void *arg) context->set_shutdown(SHUTDOWN_FORCED); } break; + case SIGPIPE: + { + Error << "Ignoring SIGPIPE"; + } + break; default: Error << "Signal handling thread got unexpected signal " << strsignal(sig); @@ -154,10 +165,14 @@ SignalThread::SignalThread() : sigaddset(&set, SIGQUIT); sigaddset(&set, SIGINT); } + sigaddset(&set, SIGPIPE); sigaddset(&set, SIGUSR2); sem_init(&lock, 0, 0); + + sigemptyset(&original_set); + pthread_sigmask(SIG_BLOCK, NULL, &original_set); } @@ -165,19 +180,15 @@ bool SignalThread::setup() { set_shutdown(SHUTDOWN_RUNNING); - sigset_t old_set; - sigemptyset(&old_set); - pthread_sigmask(SIG_BLOCK, NULL, &old_set); - - if (sigismember(&old_set, SIGQUIT)) + if (sigismember(&original_set, SIGQUIT)) { Error << strsignal(SIGQUIT) << " has been previously set."; } - if (sigismember(&old_set, SIGINT)) + if (sigismember(&original_set, SIGINT)) { Error << strsignal(SIGINT) << " has been previously set."; } - if (sigismember(&old_set, SIGUSR2)) + if (sigismember(&original_set, SIGUSR2)) { Error << strsignal(SIGUSR2) << " has been previously set."; } diff --git a/libtest/signal.h b/libtest/signal.h index 25eae45c..f54633c7 100644 --- a/libtest/signal.h +++ b/libtest/signal.h @@ -42,10 +42,12 @@ class SignalThread { volatile shutdown_t __shutdown; pthread_mutex_t shutdown_mutex; pthread_t thread; + sigset_t original_set; public: SignalThread(); + ~SignalThread(); void test(); void post(); @@ -56,8 +58,6 @@ public: return sigwait(&set, &sig); } - ~SignalThread(); - void set_shutdown(shutdown_t arg); bool is_shutdown(); shutdown_t get_shutdown(); diff --git a/libtest/skiptest.cc b/libtest/skiptest.cc index 784f3a8f..ef021526 100644 --- a/libtest/skiptest.cc +++ b/libtest/skiptest.cc @@ -30,10 +30,6 @@ using namespace libtest; -collection_st collection[] ={ - {0, 0, 0, 0} -}; - static void *world_create(server_startup_st&, test_return_t& rc) { rc= TEST_SKIPPED; @@ -43,6 +39,5 @@ static void *world_create(server_startup_st&, test_return_t& rc) void get_world(Framework *world) { - world->collections= collection; world->_create= world_create; } diff --git a/libtest/string.hpp b/libtest/string.hpp index a60d328b..b5a44f5b 100644 --- a/libtest/string.hpp +++ b/libtest/string.hpp @@ -28,9 +28,5 @@ #define test_literal_compare_param util_literal_compare_param #define test_literal_param_size util_literal_param_size #define test_string_make_from_cstr util_string_make_from_cstr +#define test_string_make_from_array util_string_make_from_array #define test_array_length util_array_length - -namespace libtest { -typedef std::vector vchar_t; -typedef std::vector vchar_ptr_t; -} diff --git a/libtest/test.cc b/libtest/test.cc index 2096ad19..52dd03e7 100644 --- a/libtest/test.cc +++ b/libtest/test.cc @@ -35,6 +35,10 @@ #include +#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H +#include +#endif + #ifndef __INTEL_COMPILER #pragma GCC diagnostic ignored "-Wold-style-cast" #endif @@ -70,12 +74,86 @@ static long int timedif(struct timeval a, struct timeval b) return s + us; } -static Framework *world= NULL; +static void cleanup_curl(void) +{ +#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H + curl_global_cleanup(); +#endif +} + +#include +#include + int main(int argc, char *argv[]) { +#if defined(HAVE_CURL_CURL_H) && HAVE_CURL_CURL_H + if (curl_global_init(CURL_GLOBAL_ALL)) + { + Error << "curl_global_init(CURL_GLOBAL_ALL) failed"; + return EXIT_FAILURE; + } +#endif + + if (atexit(cleanup_curl)) + { + Error << "atexit() failed"; + return EXIT_FAILURE; + } + + bool opt_repeat= false; + std::string collection_to_run; + + // Options parsing + { + enum long_option_t { + OPT_LIBYATL_VERSION, + OPT_LIBYATL_MATCH_COLLECTION, + OPT_LIBYATL_REPEAT + }; + + static struct option long_options[]= + { + {"repeat", no_argument, NULL, OPT_LIBYATL_REPEAT}, + {"collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION}, + {0, 0, 0, 0} + }; + + int option_index= 0; + while (1) + { + int option_rv= getopt_long(argc, argv, "", long_options, &option_index); + if (option_rv == -1) + { + break; + } + + switch (option_rv) + { + case OPT_LIBYATL_VERSION: + break; + + case OPT_LIBYATL_REPEAT: + opt_repeat= true; + break; + + case OPT_LIBYATL_MATCH_COLLECTION: + collection_to_run= optarg; + break; + + case '?': + /* getopt_long already printed an error message. */ + Error << "unknown option to getopt_long()"; + exit(EXIT_FAILURE); + + default: + break; + } + } + } + srandom((unsigned int)time(NULL)); - if (getenv("LIBTEST_QUIET")) + if (getenv("LIBTEST_QUIET") and strcmp(getenv("LIBTEST_QUIET"), "0") == 0) { close(STDOUT_FILENO); } @@ -109,243 +187,258 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - world= new Framework(); - - if (world == NULL) - { - Error << "Failed to create Framework()"; - return EXIT_FAILURE; - } - - libtest::SignalThread signal; - if (not signal.setup()) - { - return EXIT_FAILURE; - } - - Stats stats; - - get_world(world); + int exit_code; + do { + exit_code= EXIT_SUCCESS; + Framework *world= new Framework(); - test_return_t error; - void *creators_ptr= world->create(error); - - switch (error) - { - case TEST_SUCCESS: - break; - - case TEST_SKIPPED: - Out << "SKIP " << argv[0]; - delete world; - return EXIT_SUCCESS; - - case TEST_FATAL: - case TEST_FAILURE: - case TEST_MEMORY_ALLOCATION_FAILURE: - delete world; - return EXIT_FAILURE; - } - - char *collection_to_run= NULL; - if (argc > 1) - { - collection_to_run= argv[1]; - } - else if (getenv("TEST_COLLECTION")) - { - if (strlen(getenv("TEST_COLLECTION"))) + if (world == NULL) { - collection_to_run= getenv("TEST_COLLECTION"); + Error << "Failed to create Framework()"; + return EXIT_FAILURE; } - } - - if (collection_to_run) - { - Out << "Only testing " << collection_to_run; - } - - char *wildcard= NULL; - if (argc == 3) - { - wildcard= argv[2]; - } - for (collection_st *next= world->collections; next->name and (not signal.is_shutdown()); next++) - { - test_return_t collection_rc= TEST_SUCCESS; - bool failed= false; - bool skipped= false; + assert(sigignore(SIGPIPE) == 0); - if (collection_to_run && fnmatch(collection_to_run, next->name, 0)) - continue; + libtest::SignalThread signal; + if (not signal.setup()) + { + Error << "Failed to setup signals"; + return EXIT_FAILURE; + } - stats.collection_total++; + Stats stats; - collection_rc= world->startup(creators_ptr); + get_world(world); - if (collection_rc == TEST_SUCCESS and next->pre) - { - collection_rc= world->runner()->pre(next->pre, creators_ptr); - } + test_return_t error; + void *creators_ptr= world->create(error); - switch (collection_rc) + switch (error) { case TEST_SUCCESS: break; + case TEST_SKIPPED: + Out << "SKIP " << argv[0]; + delete world; + return EXIT_SUCCESS; + case TEST_FATAL: case TEST_FAILURE: - Out << next->name << " [ failed ]"; - failed= true; - signal.set_shutdown(SHUTDOWN_GRACEFUL); - goto cleanup; + case TEST_MEMORY_ALLOCATION_FAILURE: + delete world; + return EXIT_FAILURE; + } - case TEST_SKIPPED: - Out << next->name << " [ skipping ]"; - skipped= true; - goto cleanup; + if (getenv("TEST_COLLECTION")) + { + if (strlen(getenv("TEST_COLLECTION"))) + { + collection_to_run= getenv("TEST_COLLECTION"); + } + } - case TEST_MEMORY_ALLOCATION_FAILURE: - test_assert(0, "Allocation failure, or unknown return"); + if (collection_to_run.empty() == false) + { + Out << "Only testing " << collection_to_run; } - Out << "Collection: " << next->name; + char *wildcard= NULL; + if (argc == 3) + { + wildcard= argv[2]; + } - for (test_st *run= next->tests; run->name; run++) + for (collection_st *next= world->collections; next and next->name and (not signal.is_shutdown()); next++) { - struct timeval start_time, end_time; - long int load_time= 0; + bool failed= false; + bool skipped= false; - if (wildcard && fnmatch(wildcard, run->name, 0)) + if (collection_to_run.empty() == false and fnmatch(collection_to_run.c_str(), next->name, 0)) { continue; } - test_return_t return_code; - if (test_success(return_code= world->item.startup(creators_ptr))) - { - if (test_success(return_code= world->item.flush(creators_ptr, run))) - { - // @note pre will fail is SKIPPED is returned - if (test_success(return_code= world->item.pre(creators_ptr))) - { - { // Runner Code - gettimeofday(&start_time, NULL); - assert(world->runner()); - assert(run->test_fn); - return_code= world->runner()->run(run->test_fn, creators_ptr); - gettimeofday(&end_time, NULL); - load_time= timedif(end_time, start_time); - } - } + stats.collection_total++; - // @todo do something if post fails - (void)world->item.post(creators_ptr); - } - else if (return_code == TEST_SKIPPED) - { } - else if (return_code == TEST_FAILURE) - { - Error << " item.flush(failure)"; - signal.set_shutdown(SHUTDOWN_GRACEFUL); - } - } - else if (return_code == TEST_SKIPPED) - { } - else if (return_code == TEST_FAILURE) + test_return_t collection_rc= world->startup(creators_ptr); + + if (collection_rc == TEST_SUCCESS and next->pre) { - Error << " item.startup(failure)"; - signal.set_shutdown(SHUTDOWN_GRACEFUL); + collection_rc= world->runner()->pre(next->pre, creators_ptr); } - stats.total++; - - switch (return_code) + switch (collection_rc) { case TEST_SUCCESS: - Out << "\tTesting " << run->name << "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]"; - stats.success++; break; case TEST_FATAL: case TEST_FAILURE: - stats.failed++; + Out << next->name << " [ failed ]"; failed= true; - Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]"; - break; + signal.set_shutdown(SHUTDOWN_GRACEFUL); + goto cleanup; case TEST_SKIPPED: - stats.skipped++; + Out << next->name << " [ skipping ]"; skipped= true; - Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]"; - break; + goto cleanup; case TEST_MEMORY_ALLOCATION_FAILURE: - test_assert(0, "Memory Allocation Error"); + test_assert(0, "Allocation failure, or unknown return"); } - if (test_failed(world->on_error(return_code, creators_ptr))) + Out << "Collection: " << next->name; + + for (test_st *run= next->tests; run->name; run++) { - Error << "Failed while running on_error()"; - signal.set_shutdown(SHUTDOWN_GRACEFUL); - break; + struct timeval start_time, end_time; + long int load_time= 0; + + if (wildcard && fnmatch(wildcard, run->name, 0)) + { + continue; + } + + test_return_t return_code; + try { + if (test_success(return_code= world->item.startup(creators_ptr))) + { + if (test_success(return_code= world->item.flush(creators_ptr, run))) + { + // @note pre will fail is SKIPPED is returned + if (test_success(return_code= world->item.pre(creators_ptr))) + { + { // Runner Code + gettimeofday(&start_time, NULL); + assert(world->runner()); + assert(run->test_fn); + return_code= world->runner()->run(run->test_fn, creators_ptr); + gettimeofday(&end_time, NULL); + load_time= timedif(end_time, start_time); + } + } + + // @todo do something if post fails + (void)world->item.post(creators_ptr); + } + else if (return_code == TEST_SKIPPED) + { } + else if (return_code == TEST_FAILURE) + { + Error << " item.flush(failure)"; + signal.set_shutdown(SHUTDOWN_GRACEFUL); + } + } + else if (return_code == TEST_SKIPPED) + { } + else if (return_code == TEST_FAILURE) + { + Error << " item.startup(failure)"; + signal.set_shutdown(SHUTDOWN_GRACEFUL); + } + } + + catch (std::exception &e) + { + Error << "Exception was thrown: " << e.what(); + return_code= TEST_FAILURE; + } + catch (...) + { + Error << "Unknown exception occurred"; + return_code= TEST_FAILURE; + } + + stats.total++; + + switch (return_code) + { + case TEST_SUCCESS: + Out << "\tTesting " << run->name << "\t\t\t\t\t" << load_time / 1000 << "." << load_time % 1000 << "[ " << test_strerror(return_code) << " ]"; + stats.success++; + break; + + case TEST_FATAL: + case TEST_FAILURE: + stats.failed++; + failed= true; + Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]"; + break; + + case TEST_SKIPPED: + stats.skipped++; + skipped= true; + Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]"; + break; + + case TEST_MEMORY_ALLOCATION_FAILURE: + test_assert(0, "Memory Allocation Error"); + } + + if (test_failed(world->on_error(return_code, creators_ptr))) + { + Error << "Failed while running on_error()"; + signal.set_shutdown(SHUTDOWN_GRACEFUL); + break; + } } - } - (void) world->runner()->post(next->post, creators_ptr); + (void) world->runner()->post(next->post, creators_ptr); cleanup: - if (failed == false and skipped == false) - { - stats.collection_success++; + if (failed == false and skipped == false) + { + stats.collection_success++; + } + + if (failed) + { + stats.collection_failed++; + } + + if (skipped) + { + stats.collection_skipped++; + } + + world->shutdown(creators_ptr); + Outn(); } - if (failed) + if (not signal.is_shutdown()) { - stats.collection_failed++; + signal.set_shutdown(SHUTDOWN_GRACEFUL); } - if (skipped) + shutdown_t status= signal.get_shutdown(); + if (status == SHUTDOWN_FORCED) { - stats.collection_skipped++; + Out << "Tests were aborted."; + exit_code= EXIT_FAILURE; + } + else if (stats.collection_failed) + { + Out << "Some test failed."; + exit_code= EXIT_FAILURE; + } + else if (stats.collection_skipped and stats.collection_failed and stats.collection_success) + { + Out << "Some tests were skipped."; + } + else if (stats.collection_success and stats.collection_failed == 0) + { + Out << "All tests completed successfully."; } - world->shutdown(creators_ptr); - Outn(); - } - - if (not signal.is_shutdown()) - { - signal.set_shutdown(SHUTDOWN_GRACEFUL); - } - - int exit_code= EXIT_SUCCESS; - shutdown_t status= signal.get_shutdown(); - if (status == SHUTDOWN_FORCED) - { - Out << "Tests were aborted."; - exit_code= EXIT_FAILURE; - } - else if (stats.collection_failed) - { - Out << "Some test failed."; - exit_code= EXIT_FAILURE; - } - else if (stats.collection_skipped and stats.collection_failed and stats.collection_success) - { - Out << "Some tests were skipped."; - } - else if (stats.collection_success and stats.collection_failed == 0) - { - Out << "All tests completed successfully."; - } - - stats_print(&stats); + stats_print(&stats); - delete world; + delete world; - Outn(); // Generate a blank to break up the messages if make check/test has been run + Outn(); // Generate a blank to break up the messages if make check/test has been run + } while (exit_code == EXIT_SUCCESS and opt_repeat); return exit_code; } diff --git a/libtest/test.h b/libtest/test.h index 74a20e05..abd4e2aa 100644 --- a/libtest/test.h +++ b/libtest/test.h @@ -87,6 +87,7 @@ do \ return TEST_FAILURE; \ } \ } while (0) +#define test_true_hint test_true_got #define test_skip(A,B) \ do \ @@ -190,9 +191,10 @@ do \ #define test_strcmp(A,B) \ do \ { \ - if (strcmp((A), (B))) \ + if ((A) == NULL or (B) == NULL or strcmp((A), (B))) \ { \ - fprintf(stderr, "\n%s:%d: Expected %s, got %s\n", __FILE__, __LINE__, (A), (B)); \ + if ((B) == NULL) fprintf(stderr, "\n%s:%d: Expected %s, got \n", __FILE__, __LINE__, (A)); \ + else fprintf(stderr, "\n%s:%d: Expected %s, got \"%s\"\n", __FILE__, __LINE__, (A), (B)); \ libtest::create_core(); \ return TEST_FAILURE; \ } \ @@ -201,7 +203,7 @@ do \ #define test_memcmp(A,B,C) \ do \ { \ - if (memcmp((A), (B), (C))) \ + if ((A) == NULL or (B) == NULL or memcmp((A), (B), (C))) \ { \ fprintf(stderr, "\n%s:%d: %.*s -> %.*s\n", __FILE__, __LINE__, (int)(C), (char *)(A), (int)(C), (char *)(B)); \ libtest::create_core(); \ @@ -209,6 +211,17 @@ do \ } \ } while (0) +#define test_memcmp_hint(A,B,C,__hint) \ +do \ +{ \ + if ((A) == NULL or (B) == NULL or memcmp((A), (B), (C))) \ + { \ + fprintf(stderr, "\n%s:%d: (hint:%s) %.*s -> %.*s\n", __FILE__, __LINE__, __hint, (int)(C), (char *)(A), (int)(C), (char *)(B)); \ + libtest::create_core(); \ + return TEST_FAILURE; \ + } \ +} while (0) + #define test_return_if(__test_return_t) \ do \ { \ diff --git a/libtest/test.hpp b/libtest/test.hpp index c30fbfc0..b86bc68e 100644 --- a/libtest/test.hpp +++ b/libtest/test.hpp @@ -32,6 +32,9 @@ #include #include +#include + +#include #include #include #include @@ -41,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -54,3 +58,4 @@ #include #include #include +#include diff --git a/libtest/unittest.cc b/libtest/unittest.cc index 87102ddd..2d171dfd 100644 --- a/libtest/unittest.cc +++ b/libtest/unittest.cc @@ -25,7 +25,7 @@ #include #if defined(LIBTEST_WITH_LIBMEMCACHED_SUPPORT) && LIBTEST_WITH_LIBMEMCACHED_SUPPORT -#include +#include #endif #if defined(LIBTEST_WITH_LIBGEARMAN_SUPPORT) && LIBTEST_WITH_LIBGEARMAN_SUPPORT @@ -230,19 +230,16 @@ static test_return_t gearmand_cycle_test(void *object) server_startup_st *servers= (server_startup_st*)object; test_true(servers); - if (GEARMAND_BINARY) - { - if (HAVE_LIBGEARMAN) - { - test_true(has_gearmand_binary()); - const char *argv[1]= { "cycle_gearmand" }; - test_true(server_startup(*servers, "gearmand", 9999, 1, argv)); +#if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY + test_true(has_gearmand_binary()); +#else + test_skip(true, has_gearmand_binary()); +#endif - return TEST_SUCCESS; - } - } + const char *argv[1]= { "cycle_gearmand" }; + test_true(server_startup(*servers, "gearmand", 9999, 1, argv)); - return TEST_SKIPPED; + return TEST_SUCCESS; } static test_return_t memcached_cycle_test(void *object) @@ -307,11 +304,152 @@ static test_return_t memcached_sasl_test(void *object) return TEST_SKIPPED; } +static test_return_t application_true_BINARY(void *) +{ + Application true_app("true"); + + test_compare(Application::SUCCESS, true_app.run()); + test_compare(Application::SUCCESS, true_app.wait()); + + return TEST_SUCCESS; +} + +static test_return_t application_true_fubar_BINARY(void *) +{ + Application true_app("true"); + + const char *args[]= { "--fubar", 0 }; + test_compare(Application::SUCCESS, true_app.run(args)); + test_compare(Application::SUCCESS, true_app.wait()); + test_compare(0, true_app.stdout_result().size()); + + return TEST_SUCCESS; +} + +static test_return_t application_true_fubar_eq_doh_BINARY(void *) +{ + Application true_app("true"); + + const char *args[]= { "--fubar=doh", 0 }; + test_compare(Application::SUCCESS, true_app.run(args)); + test_compare(Application::SUCCESS, true_app.wait()); + test_compare(0, true_app.stdout_result().size()); + + return TEST_SUCCESS; +} + +static test_return_t application_true_fubar_eq_doh_option_BINARY(void *) +{ + Application true_app("true"); + + true_app.add_option("--fubar=", "doh"); + + test_compare(Application::SUCCESS, true_app.run()); + test_compare(Application::SUCCESS, true_app.wait()); + test_compare(0, true_app.stdout_result().size()); + + return TEST_SUCCESS; +} + + +static test_return_t GET_TEST(void *) +{ + libtest::http::GET get("http://foo.example.com/"); + + test_compare(false, get.execute()); + + return TEST_SUCCESS; +} + +static test_return_t POST_TEST(void *) +{ + libtest::vchar_t body; + libtest::http::POST post("http://foo.example.com/", body); + + test_compare(false, post.execute()); + + return TEST_SUCCESS; +} + +static test_return_t TRACE_TEST(void *) +{ + libtest::vchar_t body; + libtest::http::TRACE trace("http://foo.example.com/", body); + + test_compare(false, trace.execute()); + + return TEST_SUCCESS; +} + + +static test_return_t vchar_t_TEST(void *) +{ + libtest::vchar_t response; + libtest::make_vector(response, test_literal_param("fubar\n")); + test_compare(response, response); + + return TEST_SUCCESS; +} + +static test_return_t application_echo_fubar_BINARY(void *) +{ + Application true_app("echo"); + + const char *args[]= { "fubar", 0 }; + test_compare(Application::SUCCESS, true_app.run(args)); + test_compare(Application::SUCCESS, true_app.wait()); + + libtest::vchar_t response; + make_vector(response, test_literal_param("fubar\n")); + test_compare(response, true_app.stdout_result()); + + return TEST_SUCCESS; +} + +static test_return_t application_echo_fubar_BINARY2(void *) +{ + Application true_app("echo"); + + true_app.add_option("fubar"); + + test_compare(Application::SUCCESS, true_app.run()); + test_compare(Application::SUCCESS, true_app.wait()); + libtest::vchar_t response; + make_vector(response, test_literal_param("fubar\n")); + test_compare(response, true_app.stdout_result()); + + return TEST_SUCCESS; +} + +static test_return_t true_BINARY(void *) +{ + const char *args[]= { 0 }; + test_compare(EXIT_SUCCESS, exec_cmdline("true", args)); + + return TEST_SUCCESS; +} + +static test_return_t true_fubar_BINARY(void *) +{ + const char *args[]= { "--fubar", 0 }; + test_compare(EXIT_SUCCESS, exec_cmdline("true", args)); + + return TEST_SUCCESS; +} + +static test_return_t echo_fubar_BINARY(void *) +{ + const char *args[]= { "fubar", 0 }; + test_compare(EXIT_SUCCESS, exec_cmdline("echo", args)); + + return TEST_SUCCESS; +} + static test_return_t wait_BINARY(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline("libtest/wait", args)); + test_compare(EXIT_FAILURE, exec_cmdline("libtest/wait", args, true)); return TEST_SUCCESS; } @@ -320,7 +458,7 @@ static test_return_t wait_help_BINARY(void *) { const char *args[]= { "--quiet", "--help", 0 }; - test_true(exec_cmdline("libtest/wait", args)); + test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true)); return TEST_SUCCESS; } @@ -329,23 +467,74 @@ static test_return_t wait_version_BINARY(void *) { const char *args[]= { "--quiet", "--version", 0 }; - test_true(exec_cmdline("libtest/wait", args)); + test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true)); + + return TEST_SUCCESS; +} + +static test_return_t wait_services_BINARY(void *) +{ + test_skip(0, access("/etc/services", R_OK )); + + const char *args[]= { "--quiet", "/etc/services", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true)); return TEST_SUCCESS; } +static test_return_t wait_services_BINARY2(void *) +{ + test_skip(0, access("/etc/services", R_OK )); + + const char *args[]= { "/etc/services", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true)); + + return TEST_SUCCESS; +} + +static test_return_t application_wait_services_BINARY2(void *) +{ + test_skip(0, access("/etc/services", R_OK )); + + libtest::Application("libtest/wait", true); + const char *args[]= { "/etc/services", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true)); + + return TEST_SUCCESS; +} + +static test_return_t check_for_gearman(void *) +{ + test_skip(true, HAVE_LIBGEARMAN); + test_skip(true, has_gearmand_binary()); + return TEST_SUCCESS; +} + + test_st gearmand_tests[] ={ #if 0 {"pause", 0, pause_test }, #endif {"gearmand startup-shutdown", 0, gearmand_cycle_test }, + {"_compare(gearman_return_t)", 0, _compare_gearman_return_t_test }, {0, 0, 0} }; +static test_return_t check_for_libmemcached(void *) +{ + test_skip(true, HAVE_LIBMEMCACHED); + test_skip(true, has_memcached_binary()); + return TEST_SUCCESS; +} + test_st memcached_tests[] ={ {"memcached startup-shutdown", 0, memcached_cycle_test }, {"memcached(socket file) startup-shutdown", 0, memcached_socket_cycle_test }, {"memcached_sasl() startup-shutdown", 0, memcached_sasl_test }, + {"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test }, {0, 0, 0} }; @@ -386,15 +575,42 @@ test_st directories_tests[] ={ test_st comparison_tests[] ={ {"_compare(test_return_t)", 0, _compare_test_return_t_test }, - {"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test }, - {"_compare(gearman_return_t)", 0, _compare_gearman_return_t_test }, {0, 0, 0} }; test_st cmdline_tests[] ={ + {"true", 0, true_BINARY }, + {"true --fubar", 0, true_fubar_BINARY }, + {"echo fubar", 0, echo_fubar_BINARY }, {"wait --quiet", 0, wait_BINARY }, {"wait --quiet --help", 0, wait_help_BINARY }, {"wait --quiet --version", 0, wait_version_BINARY }, + {"wait --quiet /etc/services", 0, wait_services_BINARY }, + {"wait /etc/services", 0, wait_services_BINARY2 }, + {0, 0, 0} +}; + +test_st application_tests[] ={ + {"vchar_t", 0, vchar_t_TEST }, + {"true", 0, application_true_BINARY }, + {"true --fubar", 0, application_true_fubar_BINARY }, + {"true --fubar=doh", 0, application_true_fubar_eq_doh_BINARY }, + {"true --fubar=doh add_option()", 0, application_true_fubar_eq_doh_option_BINARY }, + {"echo fubar", 0, application_echo_fubar_BINARY }, + {"echo fubar (as option)", 0, application_echo_fubar_BINARY2 }, + {0, 0, 0} +}; + +static test_return_t check_for_curl(void *) +{ + test_skip(true, HAVE_LIBCURL); + return TEST_SUCCESS; +} + +test_st http_tests[] ={ + {"GET", 0, GET_TEST }, + {"POST", 0, POST_TEST }, + {"TRACE", 0, TRACE_TEST }, {0, 0, 0} }; @@ -404,9 +620,11 @@ collection_st collection[] ={ {"local", 0, 0, local_log}, {"directories", 0, 0, directories_tests}, {"comparison", 0, 0, comparison_tests}, - {"gearmand", 0, 0, gearmand_tests}, - {"memcached", 0, 0, memcached_tests}, + {"gearmand", check_for_gearman, 0, gearmand_tests}, + {"memcached", check_for_libmemcached, 0, memcached_tests}, {"cmdline", 0, 0, cmdline_tests}, + {"application", 0, 0, application_tests}, + {"http", check_for_curl, 0, http_tests}, {0, 0, 0, 0} }; diff --git a/libtest/vchar.cc b/libtest/vchar.cc new file mode 100644 index 00000000..779cfbba --- /dev/null +++ b/libtest/vchar.cc @@ -0,0 +1,58 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +namespace libtest { + +static std::string printer(const char *str, size_t length) +{ + std::ostringstream buf; + for (size_t x= 0; x < length; x++) + { + if (isprint(str[x])) + { + buf << str[x]; + } + else + { + buf << "(" << int(str[x]) << ")"; + } + } + + return buf.str(); +} + +void make_vector(libtest::vchar_t& arg, const char *str, size_t length) +{ + arg.resize(length); + memcpy(&arg[0], str, length); +} + +std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg) +{ + std::string tmp= libtest::printer(&arg[0], arg.size()); + output << tmp << "[" << arg.size() << "]"; + + return output; +} + +} // namespace libtest diff --git a/libtest/vchar.hpp b/libtest/vchar.hpp new file mode 100644 index 00000000..7bdb5481 --- /dev/null +++ b/libtest/vchar.hpp @@ -0,0 +1,41 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * libtest + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#pragma once + +#include +#include +#include +#include +#include + +namespace libtest { + +typedef std::vector vchar_ptr_t; +typedef std::vector vchar_t; + +void make_vector(libtest::vchar_t& arg, const char *str, size_t length); + +std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg); + +} // namespace libtest + diff --git a/libtest/wait.cc b/libtest/wait.cc index cf2277e6..79659664 100644 --- a/libtest/wait.cc +++ b/libtest/wait.cc @@ -34,7 +34,6 @@ static void version_command(const char *command_name, int major_version, int minor_version) { std::cout << command_name << " " << major_version << "." << minor_version << std::endl; - exit(EXIT_SUCCESS); } static void help_command(const char *command_name, @@ -50,7 +49,6 @@ static void help_command(const char *command_name, } std::cout << std::endl; - exit(EXIT_SUCCESS); } static void close_stdio(void) @@ -102,11 +100,12 @@ static void options_parse(int argc, char *argv[]) bool opt_version= false; bool opt_help= false; + bool opt_quiet= false; int option_index= 0; while (1) { - int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + int option_rv= getopt_long(argc, argv, "", long_options, &option_index); if (option_rv == -1) { break; @@ -118,19 +117,29 @@ static void options_parse(int argc, char *argv[]) opt_help= true; break; + case OPT_VERSION: /* --version or -v */ + opt_version= true; + break; + case OPT_QUIET: - close_stdio(); + opt_quiet= true; break; case '?': /* getopt_long already printed an error message. */ - exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); default: - abort(); + help_command(argv[0], 1, 0, long_options); + exit(EXIT_FAILURE); } } + if (opt_quiet) + { + close_stdio(); + } + if (opt_version) { version_command(argv[0], 1, 0); @@ -146,15 +155,25 @@ static void options_parse(int argc, char *argv[]) int main(int argc, char *argv[]) { + if (argc == 1) + { + return EXIT_FAILURE; + } + options_parse(argc, argv); - if (argc == 2) + int ret= EXIT_FAILURE; + while (optind < argc) { - libtest::Wait wait(argv[1]); + libtest::Wait wait(argv[optind++]); + + if (wait.successful() == false) + { + return EXIT_FAILURE; + } - if (wait.successful()) - return EXIT_SUCCESS; + ret= EXIT_SUCCESS; } - return EXIT_FAILURE; + return ret; } diff --git a/tests/cli.am b/tests/cli.am index 9e47fdd7..689c5c52 100644 --- a/tests/cli.am +++ b/tests/cli.am @@ -86,6 +86,12 @@ tests_memdump_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memdump noinst_PROGRAMS+= tests/memdump +test-memerror: clients/memerror + tests/memerror + +valgrind-memerror: clients/memerror + @$(VALGRIND_COMMAND) tests/memerror + test-memcp: clients/memcp @echo "Testing memcp" @@MEMC_BINARY@ -d -u root -P `pwd`/tests/Xumemc.pid -p 12555 diff --git a/tests/libmemcached-1.0/mem_functions.cc b/tests/libmemcached-1.0/mem_functions.cc index b3f6fbe0..f2a724f8 100644 --- a/tests/libmemcached-1.0/mem_functions.cc +++ b/tests/libmemcached-1.0/mem_functions.cc @@ -2706,7 +2706,7 @@ test_return_t user_supplied_bug14(memcached_st *memc) value.push_back((char) (x % 127)); } - for (size_t current_length= 0; current_length < value.size(); current_length++) + for (size_t current_length= 1; current_length < value.size(); current_length++) { memcached_return_t rc= memcached_set(memc, test_literal_param("foo"), &value[0], current_length, @@ -2720,7 +2720,9 @@ test_return_t user_supplied_bug14(memcached_st *memc) test_compare(MEMCACHED_SUCCESS, rc); test_compare(string_length, current_length); - test_memcmp(string, &value[0], string_length); + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "%u", uint32_t(string_length)); + test_memcmp_hint(string, &value[0], string_length, buffer); free(string); } @@ -4981,5 +4983,7 @@ test_return_t kill_HUP_TEST(memcached_st *original_memc) test_literal_param(__func__), // Values 0, 0)); + memcached_free(memc); + return TEST_SUCCESS; } diff --git a/tests/memcapable.cc b/tests/memcapable.cc index c8adad18..49848188 100644 --- a/tests/memcapable.cc +++ b/tests/memcapable.cc @@ -56,41 +56,45 @@ static test_return_t quiet_test(void *) { const char *args[]= { "-q", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "-q", "--help", 0 }; + const char *args[]= { "-h", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } static test_return_t ascii_test(void *) { char buffer[1024]; - snprintf(buffer, sizeof(buffer), "-p %d", int(default_port())); - const char *args[]= { "-q", buffer, " -a ", 0 }; + snprintf(buffer, sizeof(buffer), "%d", int(default_port())); + const char *args[]= { "-p", buffer, " -a ", 0 }; + + test_true(exec_cmdline(executable, args, true) <= EXIT_FAILURE); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } static test_return_t binary_test(void *) { char buffer[1024]; - snprintf(buffer, sizeof(buffer), "-p %d", int(default_port())); - const char *args[]= { "-q", buffer, " -b ", 0 }; + snprintf(buffer, sizeof(buffer), "%d", int(default_port())); + const char *args[]= { "-p", buffer, " -b ", 0 }; + + test_true(exec_cmdline(executable, args, true) <= EXIT_FAILURE); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } test_st memcapable_tests[] ={ {"--quiet", 0, quiet_test}, - {"--help", 0, help_test}, + {"-h", 0, help_test}, {"-a, ascii", 0, ascii_test}, {"-b, binary", 0, binary_test}, {0, 0, 0} diff --git a/tests/memcat.cc b/tests/memcat.cc index ea64352e..4b1096ac 100644 --- a/tests/memcat.cc +++ b/tests/memcat.cc @@ -56,15 +56,17 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -72,7 +74,7 @@ static test_return_t cat_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "foo", 0 }; + const char *args[]= { buffer, "foo", 0 }; memcached_st *memc= memcached(buffer, strlen(buffer)); test_true(memc); @@ -84,7 +86,7 @@ static test_return_t cat_test(void *) test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_SUCCESS, rc); - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_SUCCESS, rc); @@ -98,7 +100,7 @@ static test_return_t NOT_FOUND_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "foo", 0 }; + const char *args[]= { buffer, "foo", 0 }; memcached_st *memc= memcached(buffer, strlen(buffer)); test_true(memc); @@ -109,7 +111,7 @@ static test_return_t NOT_FOUND_test(void *) test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_NOTFOUND, rc); - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_NOTFOUND, rc); diff --git a/tests/memcp.cc b/tests/memcp.cc index a929b6db..698041e6 100644 --- a/tests/memcp.cc +++ b/tests/memcp.cc @@ -56,15 +56,17 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -72,9 +74,10 @@ static test_return_t server_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, 0 }; + const char *args[]= { buffer, 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } diff --git a/tests/memdump.cc b/tests/memdump.cc index 0aeb0a99..790d1a68 100644 --- a/tests/memdump.cc +++ b/tests/memdump.cc @@ -56,7 +56,8 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } @@ -64,7 +65,8 @@ static test_return_t help_test(void *) { const char *args[]= { "--help", "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } @@ -74,7 +76,8 @@ static test_return_t server_test(void *) snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); const char *args[]= { buffer, 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } @@ -82,7 +85,7 @@ static test_return_t FOUND_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, 0 }; + const char *args[]= { buffer, 0 }; memcached_st *memc= memcached(buffer, strlen(buffer)); test_true(memc); @@ -97,7 +100,7 @@ static test_return_t FOUND_test(void *) test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_SUCCESS, rc); - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); memcached_free(memc); diff --git a/tests/memerror.cc b/tests/memerror.cc index 88ddcbad..00863475 100644 --- a/tests/memerror.cc +++ b/tests/memerror.cc @@ -52,42 +52,56 @@ using namespace libtest; static std::string executable; -static test_return_t quiet_test(void *) +static test_return_t help_TEST(void *) { - const char *args[]= { "--quiet", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } -static test_return_t help_test(void *) +static test_return_t version_TEST(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--version", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } static test_return_t error_test(void *) { - const char *args[]= { "--quiet", "MEMCACHED_SUCCESS", 0 }; + const char *args[]= { "memcached_success", 0 }; + + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + + return TEST_SUCCESS; +} + +static test_return_t SUCCESS_TEST(void *) +{ + const char *args[]= { "0", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } static test_return_t bad_input_test(void *) { - const char *args[]= { "--quiet", "bad input", 0 }; + const char *args[]= { "bad input", 0 }; + + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } test_st memerror_tests[] ={ - {"--quiet", 0, quiet_test}, - {"--help", 0, help_test}, + {"--help", 0, help_TEST}, + {"--version", 0, version_TEST}, {"", 0, error_test}, + {"0", 0, SUCCESS_TEST}, {"", 0, bad_input_test}, {0, 0, 0} }; diff --git a/tests/memflush.cc b/tests/memflush.cc index 6cafcbba..97544708 100644 --- a/tests/memflush.cc +++ b/tests/memflush.cc @@ -56,15 +56,17 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -72,9 +74,10 @@ static test_return_t server_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, 0 }; + const char *args[]= { buffer, 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } diff --git a/tests/memrm.cc b/tests/memrm.cc index f3a1f84b..382693cd 100644 --- a/tests/memrm.cc +++ b/tests/memrm.cc @@ -56,15 +56,16 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -72,7 +73,6 @@ static test_return_t rm_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "foo", 0 }; memcached_st *memc= memcached(buffer, strlen(buffer)); test_true(memc); @@ -84,7 +84,8 @@ static test_return_t rm_test(void *) test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_SUCCESS, rc); - test_true(exec_cmdline(executable, args)); + const char *args[]= { buffer, "foo", 0 }; + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_NOTFOUND, rc); @@ -98,7 +99,7 @@ static test_return_t NOT_FOUND_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "foo", 0 }; + const char *args[]= { buffer, "foo", 0 }; memcached_st *memc= memcached(buffer, strlen(buffer)); test_true(memc); @@ -107,7 +108,7 @@ static test_return_t NOT_FOUND_test(void *) test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_NOTFOUND, rc); - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); test_compare(MEMCACHED_NOTFOUND, rc); diff --git a/tests/memslap.cc b/tests/memslap.cc index 21d66c59..f353978d 100644 --- a/tests/memslap.cc +++ b/tests/memslap.cc @@ -56,15 +56,17 @@ static test_return_t quiet_test(void *) { const char *args[]= { "--quiet", 0 }; - test_true(exec_cmdline(executable, args)); + test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true)); + return TEST_SUCCESS; } static test_return_t help_test(void *) { - const char *args[]= { "--quiet", "--help", 0 }; + const char *args[]= { "--help", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -72,9 +74,10 @@ static test_return_t server_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, 0 }; + const char *args[]= { buffer, 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -82,9 +85,10 @@ static test_return_t server_concurrency_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", 0 }; + const char *args[]= { buffer, "--concurrency=10", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -92,9 +96,10 @@ static test_return_t server_concurrency_initial_load_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", "--initial-load=1000", 0 }; + const char *args[]= { buffer, "--concurrency=10", "--initial-load=1000", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -102,9 +107,10 @@ static test_return_t server_concurrency_initial_load_execute_number_test(void *) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", 0 }; + const char *args[]= { buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -112,9 +118,10 @@ static test_return_t server_concurrency_initial_load_execute_number_test_get_tes { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=get", 0 }; + const char *args[]= { buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=get", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -122,9 +129,10 @@ static test_return_t server_concurrency_initial_load_execute_number_test_set_tes { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=set", 0 }; + const char *args[]= { buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=set", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } @@ -132,9 +140,10 @@ static test_return_t server_concurrency_initial_load_execute_number_test_set_non { char buffer[1024]; snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port())); - const char *args[]= { "--quiet", buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=set", "--non-blocking", 0 }; + const char *args[]= { buffer, "--concurrency=10", "--initial-load=1000", "--execute-number=10", "--test=set", "--non-blocking", 0 }; + + test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true)); - test_true(exec_cmdline(executable, args)); return TEST_SUCCESS; } diff --git a/util/daemon.cc b/util/daemon.cc index 3b129d18..68393297 100644 --- a/util/daemon.cc +++ b/util/daemon.cc @@ -77,7 +77,7 @@ bool daemon_is_ready(bool close_io) return false; } - if (not close_io) + if (close_io == false) { return true;; } diff --git a/util/instance.cc b/util/instance.cc index 19d01fcf..e96f414f 100644 --- a/util/instance.cc +++ b/util/instance.cc @@ -41,13 +41,17 @@ #include "util/instance.hpp" #include -#include #include #include +#include #include +#include #include #include -#include + +#ifdef HAVE_UNISTD_H +#include +#endif namespace datadifferential { @@ -213,20 +217,31 @@ bool Instance::run() do { char buffer[BUFSIZ]; - read_length= recv(_sockfd, buffer, sizeof(buffer), 0); + read_length= ::recv(_sockfd, buffer, sizeof(buffer), 0); if (read_length < 0) { switch(errno) { default: - std::cerr << "Error occured while reading data from " << _host.c_str() << std::endl; + _last_error.clear(); + _last_error+= "Error occured while reading data from "; + _last_error+= _host; return false; } } + else if (read_length == 0) + { + _last_error.clear(); + _last_error+= "Socket was shutdown while reading from "; + _last_error+= _host; + + return false; + } operation->push(buffer, static_cast(read_length)); total_read+= static_cast(read_length); + } while (more_to_read()); } // end has_response @@ -276,7 +291,9 @@ bool Instance::more_to_read() const void Instance::close_socket() { if (_sockfd == INVALID_SOCKET) + { return; + } /* in case of death shutdown to avoid blocking at close() */ if (shutdown(_sockfd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN) @@ -293,8 +310,10 @@ void Instance::close_socket() void Instance::free_addrinfo() { - if (not _addrinfo) + if (_addrinfo == NULL) + { return; + } freeaddrinfo(_addrinfo); _addrinfo= NULL; diff --git a/util/operation.cc b/util/operation.cc index ad19e2b7..def31a6b 100644 --- a/util/operation.cc +++ b/util/operation.cc @@ -47,7 +47,9 @@ namespace util { bool Operation::response(std::string &arg) { if (_response.empty()) + { return false; + } if (not memcmp("OK\r\n", &_response[0], 3)) { } diff --git a/util/signal.hpp b/util/signal.hpp index 7573fe65..b15bf0e4 100644 --- a/util/signal.hpp +++ b/util/signal.hpp @@ -26,6 +26,10 @@ #include #include +#ifdef HAVE_SIGNAL_H +#include +#endif + namespace datadifferential { namespace util { diff --git a/util/string.hpp b/util/string.hpp index 873551e5..9f678698 100644 --- a/util/string.hpp +++ b/util/string.hpp @@ -51,5 +51,7 @@ #define util_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0) +#define util_string_make_from_array(__array) (__array), (strlen(__array)) + #define util_array_length(__array) sizeof(__array)/sizeof(&__array) -- 2.30.2