size_t loop_max= 5;
while (--loop_max) // While loop is for ERESTART or EINTR
{
-
int error= poll(&fds, 1, ptr->root->poll_timeout);
switch (error)
{
private:
public:
BlobslapWorker(in_port_t port_arg) :
- Server("localhost", port_arg)
+ Server("localhost", port_arg, "benchmark/blobslap_worker", true)
{
set_pid_file();
}
return "blobslap_worker";
};
- const char *executable()
- {
- return "benchmark/blobslap_worker";
- }
-
- const char *daemon_file_option()
- {
- return "--daemon";
- }
-
bool has_port_option() const
{
return true;
#include <fcntl.h>
#include <fstream>
#include <memory>
+#include <poll.h>
#include <spawn.h>
#include <sstream>
#include <string>
return Application::SUCCESS;
}
-Application::error_t Application::wait()
+bool Application::check() const
{
- if (_pid == -1)
+ Error << "Testing " << _exectuble;
+ if (kill(_pid, 0) == 0)
{
- Error << "wait() got an invalid pid_t";
- return Application::INVALID;
+ return true;
}
+ return false;
+}
+
+void Application::murder()
+{
+ slurp();
+ kill(_pid, SIGTERM);
+}
+
+// false means that no data was returned
+bool Application::slurp()
+{
+ struct pollfd fds[2];
+ fds[0].fd= stdout_fd.fd()[0];
+ fds[0].events= POLLIN;
+ fds[0].revents= 0;
+ fds[1].fd= stderr_fd.fd()[0];
+ fds[1].events= POLLIN;
+ fds[1].revents= 0;
+
+ int active_fd;
+ if ((active_fd= poll(fds, 2, 400)) == -1)
+ {
+ int error;
+ switch ((error= errno))
+ {
+#ifdef TARGET_OS_LINUX
+ case ERESTART:
+#endif
+ case EINTR:
+ break;
+
+ case EFAULT:
+ case ENOMEM:
+ fatal_message(strerror(error));
+ break;
+
+ case EINVAL:
+ fatal_message("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid");
+ break;
+
+ default:
+ fatal_message(strerror(error));
+ break;
+ }
+ }
+
+ if (active_fd == 0)
+ {
+ return false;
+ }
+
+ if (fds[0].revents == POLLIN)
{
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)
+ while ((read_length= ::read(stdout_fd.fd()[0], buffer, sizeof(buffer))))
{
if (read_length == -1)
{
default:
Error << strerror(errno);
- bail= true;
+ break;
}
+
+ break;
}
_stdout_buffer.reserve(read_length +1);
for (size_t x= 0; x < read_length; x++)
}
}
+ if (fds[1].revents == POLLIN)
{
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)
+ while ((read_length= ::read(stderr_fd.fd()[0], buffer, sizeof(buffer))))
{
if (read_length == -1)
{
default:
Error << strerror(errno);
- bail= true;
+ break;
}
+
+ break;
}
_stderr_buffer.reserve(read_length +1);
for (size_t x= 0; x < read_length; x++)
}
}
+ return true;
+}
+
+Application::error_t Application::wait()
+{
+ fatal_assert(_pid != -1);
+
+ slurp();
+
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);
+ switch (errno)
+ {
+ case ECHILD:
+ exit_code= Application::SUCCESS;
+ break;
+
+ default:
+ Error << "Error occured while waitpid(" << strerror(errno) << ") on pid " << int(_pid);
+ }
}
else
{
return exit_code;
}
+void Application::add_long_option(const std::string& name, const std::string& option_value)
+{
+ std::string arg(name);
+ arg+= option_value;
+ _options.push_back(std::make_pair(arg, std::string()));
+}
+
void Application::add_option(const std::string& arg)
{
_options.push_back(std::make_pair(arg, std::string()));
_open[1]= false;
}
+void Application::Pipe::nonblock()
+{
+ int ret;
+ if ((ret= fcntl(_fd[0], F_GETFL, 0)) == -1)
+ {
+ Error << "fcntl(F_GETFL) " << strerror(errno);
+ throw strerror(errno);
+ }
+
+ if ((ret= fcntl(_fd[0], F_SETFL, ret | O_NONBLOCK)) == -1)
+ {
+ Error << "fcntl(F_SETFL) " << strerror(errno);
+ throw strerror(errno);
+ }
+}
+
void Application::Pipe::reset()
{
close(READ);
close(WRITE);
- int ret;
if (pipe(_fd) == -1)
{
throw strerror(errno);
_open[0]= true;
_open[1]= true;
+ if (0)
{
- if ((ret= fcntl(_fd[0], F_GETFL, 0)) == -1)
- {
- Error << "fcntl(F_GETFL) " << strerror(errno);
- throw strerror(errno);
- }
-
- if ((ret= fcntl(_fd[0], F_SETFL, ret | O_NONBLOCK)) == -1)
- {
- Error << "fcntl(F_SETFL) " << strerror(errno);
- throw strerror(errno);
- }
+ nonblock();
}
}
posix_spawn_file_actions_t& file_actions,
const int newfildes);
+ void nonblock();
+
private:
int _fd[2];
bool _open[2];
void add_option(const std::string&);
void add_option(const std::string&, const std::string&);
+ void add_long_option(const std::string& option_name, const std::string& option_value);
error_t run(const char *args[]= NULL);
error_t wait();
_use_valgrind= arg;
}
+ bool check() const;
+
+ bool slurp();
+ void murder();
+
void use_gdb(bool arg= true)
{
_use_gdb= arg;
namespace libtest {
-bool _in_valgrind(const char*, int, const char*)
+bool valgrind_is_caller(void)
{
if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "valgrind"))
{
return true;
}
- return TEST_SUCCESS;
+ return false;
+}
+
+bool gdb_is_caller(void)
+{
+ if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "gdb"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool helgrind_is_caller(void)
+{
+ if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "helgrind"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool _in_valgrind(const char*, int, const char*)
+{
+ if (valgrind_is_caller())
+ {
+ return true;
+ }
+
+ return false;
}
} // namespace libtest
namespace libtest {
+LIBTEST_API
+bool gdb_is_caller(void);
+
+LIBTEST_API
+bool valgrind_is_caller(void);
+
+LIBTEST_API
bool _in_valgrind(const char *file, int line, const char *func);
template <class T_comparable, class T_hint>
libtest::Runner *Framework::runner()
{
- return _runner ? _runner : &defualt_runners;
+ if (_runner == NULL)
+ {
+ _runner= &defualt_runners;
+ }
+ _runner->set_servers(_servers);
+
+ return _runner;
}
void* Framework::create(test_return_t& arg)
private:
public:
Gearmand(const std::string& host_arg, in_port_t port_arg) :
- libtest::Server(host_arg, port_arg)
+ libtest::Server(host_arg, port_arg, GEARMAND_BINARY, true)
{
set_pid_file();
}
return "gearmand";
};
- const char *executable()
- {
- return GEARMAND_BINARY;
- }
-
- const char *daemon_file_option()
- {
- return "--daemon";
- }
-
void log_file_option(Application& app, const std::string& arg)
{
if (arg.empty() == false)
using namespace libtest;
+namespace {
+ bool is_memcached_libtool()
+ {
+ if (MEMCACHED_BINARY and strcmp(MEMCACHED_BINARY, "memcached/memcached") == 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
+
class Memcached : public libtest::Server
{
std::string _username;
const bool is_socket_arg,
const std::string& username_arg,
const std::string& password_arg) :
- libtest::Server(host_arg, port_arg, is_socket_arg),
+ libtest::Server(host_arg, port_arg,
+ MEMCACHED_BINARY, is_memcached_libtool(), is_socket_arg),
_username(username_arg),
_password(password_arg)
{ }
Memcached(const std::string& host_arg, const in_port_t port_arg, const bool is_socket_arg) :
- libtest::Server(host_arg, port_arg, is_socket_arg)
+ libtest::Server(host_arg, port_arg,
+ MEMCACHED_BINARY, is_memcached_libtool(), is_socket_arg)
{
set_pid_file();
}
bool is_libtool()
{
- if (MEMCACHED_BINARY and strcmp(MEMCACHED_BINARY, "memcached/memcached") == 0)
- {
- return true;
- }
-
- return false;
+ return is_memcached_libtool();
}
virtual void pid_file_option(Application& app, const std::string& arg)
return "-s ";
}
- const char *daemon_file_option()
- {
- return "-d";
- }
-
virtual void port_option(Application& app, in_port_t arg)
{
char buffer[30];
{
public:
- MemcachedLight(const std::string& host_arg, const in_port_t port_arg):
- libtest::Server(host_arg, port_arg)
+ MemcachedLight(const std::string& host_arg, const in_port_t port_arg) :
+ libtest::Server(host_arg, port_arg, MEMCACHED_LIGHT_BINARY, true)
{
set_pid_file();
}
return MEMCACHED_LIGHT_BINARY;
}
- const char *daemon_file_option()
- {
- return "--daemon";
- }
-
virtual void port_option(Application& app, in_port_t arg)
{
char buffer[1024];
bool ping()
{
// Memcached is slow to start, so we need to do this
- if (not pid_file().empty())
+ if (pid_file().empty() == false)
{
- if (not wait_for_pidfile())
+ if (wait_for_pidfile() == false)
{
Error << "Pidfile was not found:" << pid_file();
return -1;
ret= libmemcached_util_ping2(hostname().c_str(), port(), username().c_str(), password().c_str(), &rc);
}
- if (memcached_failed(rc) or not ret)
+ if (memcached_failed(rc) or ret == false)
{
Error << "libmemcached_util_ping2(" << hostname() << ", " << port() << ", " << username() << ", " << password() << ") error: " << memcached_strerror(NULL, rc);
}
set environment LIBTEST_IN_GDB=1
run
thread apply all bt
-quit
Runner();
+ void set_servers(libtest::server_startup_st& arg)
+ {
+ _servers= &arg;
+ }
+
+ bool check()
+ {
+ return _servers ? _servers->check() : true;
+ }
+
virtual ~Runner() { }
+
+private:
+ libtest::server_startup_st* _servers;
};
} // namespace Runner
#define MAGIC_MEMORY 123570
-Server::Server(const std::string& host_arg, const in_port_t port_arg, bool is_socket_arg) :
+Server::Server(const std::string& host_arg, const in_port_t port_arg,
+ const std::string& executable, const bool _is_libtool,
+ bool is_socket_arg) :
_magic(MAGIC_MEMORY),
_is_socket(is_socket_arg),
_pid(-1),
_port(port_arg),
- _hostname(host_arg)
+ _hostname(host_arg),
+ _app(executable, _is_libtool)
{
}
{
Error << "Unable to kill:" << *this;
}
+
+ Application::error_t ret;
+ if (Application::SUCCESS != (ret= _app.wait()))
+ {
+ Error << "Application::wait() " << _running << " " << ret << ": " << _app.stderr_result();
+ }
+}
+
+bool Server::check()
+{
+ _app.slurp();
+ return _app.check();
}
bool Server::validate()
fatal_message("has_pid() failed, programer error");
}
- Application app(executable(), is_libtool());
-
- if (is_debug())
+ // This needs more work.
+#if 0
+ if (gdb_is_caller())
{
- app.use_gdb();
- }
- else if (getenv("TESTS_ENVIRONMENT"))
- {
- if (strstr(getenv("TESTS_ENVIRONMENT"), "gdb"))
- {
- app.use_gdb();
- }
+ _app.use_gdb();
}
+#endif
- if (args(app) == false)
+ if (args(_app) == false)
{
Error << "Could not build command()";
return false;
}
Application::error_t ret;
- if (Application::SUCCESS != (ret= app.run()))
+ if (Application::SUCCESS != (ret= _app.run()))
{
Error << "Application::run() " << ret;
return false;
}
- _running= app.print();
-
- if (Application::SUCCESS != (ret= app.wait()))
- {
- Error << "Application::wait() " << _running << " " << ret;
- return false;
- }
+ _running= _app.print();
- if (is_valgrind())
+ if (valgrind_is_caller())
{
dream(5, 50000);
}
}
}
+ uint32_t this_wait;
bool pinged= false;
{
uint32_t timeout= 20; // This number should be high enough for valgrind startup (which is slow)
uint32_t waited;
- uint32_t this_wait;
uint32_t retry;
for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
{
fatal_message("Failed to kill off server after startup occurred, when pinging failed");
}
- Error << "Failed to ping() server started, having pid_file. exec:" << _running;
+ Error << "Failed to ping(), waited:" << this_wait
+ << " server started, having pid_file. exec:" << _running
+ << " error:" << _app.stderr_result();
}
else
{
pid_file_option(app, pid_file());
}
- assert(daemon_file_option());
- if (daemon_file_option() and not is_valgrind() and not is_helgrind())
- {
- app.add_option(daemon_file_option());
- }
-
if (has_socket_file_option())
{
if (set_socket_file() == false)
return true;
}
-bool Server::is_debug() const
-{
- return bool(getenv("LIBTEST_MANUAL_GDB"));
-}
-
-bool Server::is_valgrind() const
-{
- return bool(getenv("LIBTEST_MANUAL_VALGRIND"));
-}
-
-bool Server::is_helgrind() const
-{
- return bool(getenv("LIBTEST_MANUAL_HELGRIND"));
-}
-
bool Server::kill(pid_t pid_arg)
{
if (check_pid(pid_arg) and kill_pid(pid_arg)) // If we kill it, reset
std::string _extra_args;
public:
- Server(const std::string& hostname, const in_port_t port_arg, const bool is_socket_arg= false);
+ Server(const std::string& hostname, const in_port_t port_arg,
+ const std::string& executable, const bool _is_libtool,
+ const bool is_socket_arg= false);
virtual ~Server();
virtual const char *name()= 0;
- virtual const char *executable()= 0;
- virtual const char *daemon_file_option()= 0;
virtual bool is_libtool()= 0;
virtual bool has_socket_file_option() const
return _running;
}
+ bool check();
+
std::string log_and_pid();
bool kill(pid_t pid_arg);
protected:
bool set_pid_file();
Options _options;
+ Application _app;
private:
bool is_helgrind() const;
servers.clear();
}
+bool server_startup_st::check() const
+{
+ for (std::vector<Server *>::const_iterator iter= servers.begin(); iter != servers.end(); iter++)
+ {
+ if ((*iter)->check() == false)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void server_startup_st::shutdown()
{
for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
void shutdown();
bool shutdown(uint32_t number_of_host);
+ bool check() const;
+
void push_server(Server *);
Server *pop_server();
};
{
pthread_mutex_init(&shutdown_mutex, NULL);
sigemptyset(&set);
- if (not getenv("LIBTEST_IN_GDB"))
+ if (bool(getenv("LIBTEST_IN_GDB")) == false)
{
sigaddset(&set, SIGABRT);
sigaddset(&set, SIGQUIT);
int main(int argc, char *argv[])
{
bool opt_repeat= false;
+ bool opt_quiet= false;
std::string collection_to_run;
// Options parsing
enum long_option_t {
OPT_LIBYATL_VERSION,
OPT_LIBYATL_MATCH_COLLECTION,
+ OPT_LIBYATL_QUIET,
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}
+ { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
+ { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
+ { "repeat", no_argument, NULL, OPT_LIBYATL_REPEAT },
+ { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
+ { 0, 0, 0, 0 }
};
int option_index= 0;
case OPT_LIBYATL_VERSION:
break;
+ case OPT_LIBYATL_QUIET:
+ opt_quiet= true;
+ break;
+
case OPT_LIBYATL_REPEAT:
opt_repeat= true;
break;
srandom((unsigned int)time(NULL));
- if (getenv("LIBTEST_QUIET") and strcmp(getenv("LIBTEST_QUIET"), "0") == 0)
+ int repeat;
+ if (bool(getenv("YATL_REPEAT")) and (repeat= atoi(getenv("YATL_REPEAT"))))
{
- close(STDOUT_FILENO);
+ opt_repeat= true;
+ }
+
+ if ((getenv("YATL_QUIET") and strcmp(getenv("YATL_QUIET"), "0") == 0) or opt_quiet)
+ {
+ opt_quiet= true;
}
else if (getenv("JENKINS_URL"))
+ {
+ if (getenv("YATL_QUIET") and strcmp(getenv("YATL_QUIET"), "1") == 0)
+ { }
+ else
+ {
+ opt_quiet= true;
+ }
+ }
+
+ if (opt_quiet)
{
close(STDOUT_FILENO);
}
fatal_assert(sigignore(SIGPIPE) == 0);
libtest::SignalThread signal;
- if (not signal.setup())
+ if (signal.setup() == false)
{
Error << "Failed to setup signals";
return EXIT_FAILURE;
typedef test_return_t (*libmemcached_test_callback_fn)(memcached_st *);
-static test_return_t _runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
-{
- if (func)
+class LibmemcachedRunner : public libtest::Runner {
+public:
+ test_return_t run(test_callback_fn* func, void *object)
{
- test_true(container);
- test_true(container->memc);
- test_return_t ret;
- try {
- ret= func(container->memc);
- }
- catch (std::exception& e)
- {
- libtest::Error << e.what();
- return TEST_FAILURE;
- }
-
- return ret;
+ return _runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
}
- return TEST_SUCCESS;
-}
-
-static test_return_t _pre_runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
-{
- if (func)
+ test_return_t pre(test_callback_fn* func, void *object)
{
- return func(container->parent);
+ return _pre_runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
}
- return TEST_SUCCESS;
-}
-
-static test_return_t _post_runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
-{
- if (func)
+ test_return_t post(test_callback_fn* func, void *object)
{
- return func(container->parent);
+ return _post_runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
}
- return TEST_SUCCESS;
-}
-
-class LibmemcachedRunner : public libtest::Runner {
-public:
- test_return_t run(test_callback_fn* func, void *object)
+private:
+ test_return_t _runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
{
- return _runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
+ test_compare(true, check());
+
+ if (func)
+ {
+ test_true(container);
+ test_true(container->memc);
+ test_return_t ret;
+ try {
+ ret= func(container->memc);
+ }
+ catch (std::exception& e)
+ {
+ libtest::Error << e.what();
+ return TEST_FAILURE;
+ }
+
+ return ret;
+ }
+
+ return TEST_SUCCESS;
}
- test_return_t pre(test_callback_fn* func, void *object)
+ test_return_t _pre_runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
{
- return _pre_runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
+ if (func)
+ {
+ return func(container->parent);
+ }
+
+ return TEST_SUCCESS;
}
- test_return_t post(test_callback_fn* func, void *object)
+ test_return_t _post_runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
{
- return _post_runner_default(libmemcached_test_callback_fn(func), (libmemcached_test_container_st*)object);
+ if (func)
+ {
+ return func(container->parent);
+ }
+
+ return TEST_SUCCESS;
}
};