--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <libtest/common.h>
+
+static test_return_t runner_code(Framework* frame,
+ test_st* run,
+ libtest::Timer& _timer)
+{ // Runner Code
+
+ assert(frame->runner());
+ assert(run->test_fn);
+
+ test_return_t return_code;
+ try
+ {
+ _timer.reset();
+ return_code= frame->runner()->run(run->test_fn, frame->creators_ptr());
+ }
+ // Special case where check for the testing of the exception
+ // system.
+ catch (libtest::fatal &e)
+ {
+ if (libtest::fatal::is_disabled())
+ {
+ libtest::fatal::increment_disabled_counter();
+ return_code= TEST_SUCCESS;
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ _timer.sample();
+
+ return return_code;
+}
+
+namespace libtest {
+
+Collection::Collection(Framework* frame_arg,
+ collection_st* arg) :
+ _name(arg->name),
+ _pre(arg->pre),
+ _post(arg->post),
+ _tests(arg->tests),
+ _frame(frame_arg),
+ _success(0),
+ _skipped(0),
+ _failed(0),
+ _total(0)
+{
+ fatal_assert(arg);
+}
+
+test_return_t Collection::exec()
+{
+ Out << "Collection: " << _name;
+
+ if (test_success(_frame->runner()->pre(_pre, _frame->creators_ptr())))
+ {
+ for (test_st *run= _tests; run->name; run++)
+ {
+ long int load_time= 0;
+
+ if (_frame->match(run->name))
+ {
+ continue;
+ }
+ _total++;
+
+ test_return_t return_code;
+ try
+ {
+ if (run->requires_flush)
+ {
+ if (test_failed(_frame->runner()->flush(_frame->creators_ptr())))
+ {
+ Error << "frame->runner()->flush(creators_ptr)";
+ _skipped++;
+ continue;
+ }
+ }
+
+ return_code= runner_code(_frame, run, _timer);
+ }
+ catch (libtest::fatal &e)
+ {
+ Error << "Fatal exception was thrown: " << e.what();
+ return_code= TEST_FAILURE;
+ _failed++;
+ throw;
+ }
+
+ switch (return_code)
+ {
+ case TEST_SUCCESS:
+ Out << "\tTesting "
+ << run->name
+ << "\t\t\t\t\t"
+ << _timer
+ << " [ " << test_strerror(return_code) << " ]";
+ _success++;
+ break;
+
+ case TEST_FAILURE:
+ _failed++;
+ Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+ break;
+
+ case TEST_SKIPPED:
+ _skipped++;
+ Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
+ break;
+
+ default:
+ fatal_message("invalid return code");
+ }
+#if 0
+ @TODO add code here to allow for a collection to define a method to reset to allow tests to continue.
+#endif
+ }
+
+ (void) _frame->runner()->post(_post, _frame->creators_ptr());
+ }
+
+ if (_failed == 0 and _skipped == 0 and _success)
+ {
+ return TEST_SUCCESS;
+ }
+
+ if (_failed)
+ {
+ return TEST_FAILURE;
+ }
+
+ fatal_assert(_skipped or _success == 0);
+
+ return TEST_SKIPPED;
+}
+
+} // namespace libtest
+
#pragma once
+#include <libtest/timer.hpp>
+
+class Framework;
+
/**
A structure which describes a collection of test cases.
*/
struct test_st *tests;
};
+namespace libtest {
+
+class Collection {
+public:
+ Collection(Framework*, collection_st*);
+
+ test_return_t exec();
+
+ const char* name()
+ {
+ return _name;
+ }
+
+ uint32_t success()
+ {
+ return _success;
+ }
+
+ uint32_t skipped()
+ {
+ return _skipped;
+ }
+
+ uint32_t failed()
+ {
+ return _failed;
+ }
+
+ uint32_t total()
+ {
+ return _total;
+ }
+
+private:
+ const char *_name;
+ test_callback_fn *_pre;
+ test_callback_fn *_post;
+ struct test_st *_tests;
+ Framework* _frame;
+ uint32_t _success;
+ uint32_t _skipped;
+ uint32_t _failed;
+ uint32_t _total;
+ libtest::Timer _timer;
+};
+} // namespace libtest
#include <libtest/libtool.hpp>
#include <libtest/killpid.h>
-#include <libtest/stats.h>
#include <libtest/signal.h>
namespace libtest {
-fatal::fatal(const char *file, int line, const char *func, const char *format, ...) :
- std::runtime_error(func)
+fatal::fatal(const char *file_arg, int line_arg, const char *func_arg, const char *format, ...) :
+ std::runtime_error(func_arg),
+ _file(file_arg),
+ _line(line_arg),
+ _func(func_arg)
{
va_list args;
va_start(args, format);
char last_error[BUFSIZ];
- (void)vsnprintf(last_error, sizeof(last_error), format, args);
+ int last_error_length= vsnprintf(last_error, sizeof(last_error), format, args);
va_end(args);
- snprintf(_error_message, sizeof(_error_message), "%s:%d FATAL:%s (%s)", file, int(line), last_error, func);
+ strncpy(_mesg, last_error, sizeof(_mesg));
+
+ snprintf(_error_message, sizeof(_error_message), "%s:%d FATAL:%s (%s)", _file, int(_line), last_error, _func);
}
static bool _disabled= false;
return _error_message;
}
+ const char* mesg() const throw()
+ {
+ return _error_message;
+ }
+
// The following are just for unittesting the exception class
static bool is_disabled();
static void disable();
static uint32_t disabled_counter();
static void increment_disabled_counter();
+ int line()
+ {
+ return _line;
+ }
+
+ const char* file()
+ {
+ return _file;
+ }
+
+ const char* func()
+ {
+ return _func;
+ }
+
private:
char _error_message[BUFSIZ];
+ char _mesg[BUFSIZ];
+ int _line;
+ const char* _file;
+ const char* _func;
};
class disconnected : std::runtime_error
*/
#include <config.h>
+
#include <libtest/common.h>
+#include <libtest/collection.h>
+#include <libtest/signal.h>
+
#include <iostream>
using namespace libtest;
-Framework::Framework() :
+Framework::Framework(libtest::SignalThread& signal,
+ const std::string& only_run_arg,
+ const std::string& wildcard_arg) :
collections(NULL),
+ _total(0),
+ _success(0),
+ _skipped(0),
+ _failed(0),
_create(NULL),
_destroy(NULL),
_runner(NULL),
_socket(false),
- _creators_ptr(NULL)
+ _creators_ptr(NULL),
+ _signal(signal),
+ _only_run(only_run_arg),
+ _wildcard(wildcard_arg)
{
+ get_world(this);
+
+ for (collection_st *next= collections; next and next->name; next++)
+ {
+ _collection.push_back(new Collection(this, next));
+ }
}
Framework::~Framework()
_servers.shutdown();
delete _runner;
+
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ iter++)
+ {
+ delete *iter;
+ }
+}
+
+bool Framework::match(const char* arg)
+{
+ if (_wildcard.empty() == false and fnmatch(_wildcard.c_str(), arg, 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void Framework::exec()
+{
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end() and (_signal.is_shutdown() == false);
+ iter++)
+ {
+ if (_only_run.empty() == false and
+ fnmatch(_only_run.c_str(), (*iter)->name(), 0))
+ {
+ continue;
+ }
+
+ _total++;
+
+ try {
+ switch ((*iter)->exec())
+ {
+ case TEST_FAILURE:
+ _failed++;
+ break;
+
+ case TEST_SKIPPED:
+ _skipped++;
+ break;
+
+ // exec() can return SUCCESS, but that doesn't mean that some tests did
+ // not fail or get skipped.
+ case TEST_SUCCESS:
+ _success++;
+ break;
+ }
+ }
+ catch (libtest::fatal& e)
+ {
+ stream::cerr(e.file(), e.line(), e.func()) << e.mesg();
+ }
+ catch (libtest::disconnected& e)
+ {
+ Error << "Unhandled disconnection occurred:" << e.what();
+ throw;
+ }
+
+ Outn();
+ }
+}
+
+uint32_t Framework::sum_total()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ iter++)
+ {
+ count+= (*iter)->total();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_success()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ iter++)
+ {
+ count+= (*iter)->success();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_skipped()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ iter++)
+ {
+ count+= (*iter)->skipped();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_failed()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ iter++)
+ {
+ count+= (*iter)->failed();
+ }
+
+ return count;
}
libtest::Runner *Framework::runner()
return _runner;
}
-void* Framework::create(test_return_t& arg)
+test_return_t Framework::create()
{
- arg= TEST_SUCCESS;
+ test_return_t rc= TEST_SUCCESS;
if (_create)
{
- return _creators_ptr= _create(_servers, arg);
+ _creators_ptr= _create(_servers, rc);
}
- return NULL;
+ return rc;
}
#pragma once
+#include <libtest/signal.h>
+
/**
Framework is the structure which is passed to the test implementation to be filled.
This must be implemented in order for the test framework to load the tests. We call
get_world() in order to fill this structure.
*/
+#include <vector>
+
class Framework {
public:
collection_st *collections;
test_callback_destroy_fn *_destroy;
public:
- void* create(test_return_t& arg);
+ test_return_t create();
/**
If an error occurs during the test, this is called.
libtest::Runner *runner();
+ void exec();
- Framework();
+ libtest::Collection& collection();
+
+ Framework(libtest::SignalThread&, const std::string&);
virtual ~Framework();
- Framework(const Framework&);
+ Framework(libtest::SignalThread&,
+ const std::string&,
+ const std::string&);
+
+ bool match(const char* arg);
+
+ void *creators_ptr()
+ {
+ return _creators_ptr;
+ }
+
+ libtest::SignalThread& signal()
+ {
+ return _signal;
+ }
+
+ uint32_t sum_total();
+ uint32_t sum_success();
+ uint32_t sum_skipped();
+ uint32_t sum_failed();
+
+ size_t size()
+ {
+ return _collection.size();
+ }
+
+ uint32_t total() const
+ {
+ return _total;
+ }
+
+ uint32_t success() const
+ {
+ return _success;
+ }
+
+ uint32_t skipped() const
+ {
+ return _skipped;
+ }
+
+ uint32_t failed() const
+ {
+ return _failed;
+ }
private:
Framework& operator=(const Framework&);
+
+ uint32_t _total;
+ uint32_t _success;
+ uint32_t _skipped;
+ uint32_t _failed;
+
libtest::server_startup_st _servers;
bool _socket;
void *_creators_ptr;
unsigned long int _servers_to_run;
+ std::vector<libtest::Collection*> _collection;
+ libtest::SignalThread& _signal;
+ std::string _only_run;
+ std::string _wildcard;
};
distclean-libtest-check:
-rm -rf tmp_chroot
+noinst_HEADERS+= libtest/timer.hpp
noinst_HEADERS+= \
libtest/binaries.h \
libtest/cpu.hpp \
libtest/server_container.h \
libtest/signal.h \
libtest/socket.hpp \
- libtest/stats.h \
libtest/stream.h \
libtest/strerror.h \
libtest/string.hpp \
libtest_libtest_la_SOURCES+= libtest/binaries.cc
libtest_libtest_la_SOURCES+= libtest/cmdline.cc
libtest_libtest_la_SOURCES+= libtest/comparison.cc
+libtest_libtest_la_SOURCES+= libtest/collection.cc
libtest_libtest_la_SOURCES+= libtest/core.cc
libtest_libtest_la_SOURCES+= libtest/cpu.cc
libtest_libtest_la_SOURCES+= libtest/dream.cc
libtest_libtest_la_SOURCES+= libtest/server_container.cc
libtest_libtest_la_SOURCES+= libtest/signal.cc
libtest_libtest_la_SOURCES+= libtest/socket.cc
+libtest_libtest_la_SOURCES+= libtest/stream.cc
libtest_libtest_la_SOURCES+= libtest/strerror.cc
+libtest_libtest_la_SOURCES+= libtest/timer.cc
libtest_libtest_la_SOURCES+= libtest/tmpfile.cc
libtest_libtest_la_SOURCES+= libtest/vchar.cc
using namespace libtest;
-static void stats_print(Stats *stats)
+static void stats_print(Framework *frame)
{
- if (stats->collection_failed == 0 and stats->collection_success == 0)
+ if (frame->failed() == 0 and frame->success() == 0)
{
return;
}
- Out << "\tTotal Collections\t\t\t\t" << stats->collection_total;
- Out << "\tFailed Collections\t\t\t\t" << stats->collection_failed;
- Out << "\tSkipped Collections\t\t\t\t" << stats->collection_skipped;
- Out << "\tSucceeded Collections\t\t\t\t" << stats->collection_success;
Outn();
- Out << "Total\t\t\t\t" << stats->total;
- Out << "\tFailed\t\t\t" << stats->failed;
- Out << "\tSkipped\t\t\t" << stats->skipped;
- Out << "\tSucceeded\t\t" << stats->success;
-}
-
-static long int timedif(struct timeval a, struct timeval b)
-{
- long us, s;
-
- us = (long)(a.tv_usec - b.tv_usec);
- us /= 1000;
- s = (long)(a.tv_sec - b.tv_sec);
- s *= 1000;
- return s + us;
-}
-
-static test_return_t runner_code(Framework* frame,
- test_st* run,
- void* creators_ptr,
- long int& load_time)
-{ // Runner Code
-
- struct timeval start_time, end_time;
-
- gettimeofday(&start_time, NULL);
- assert(frame->runner());
- assert(run->test_fn);
-
- test_return_t return_code;
- try
- {
- return_code= frame->runner()->run(run->test_fn, creators_ptr);
- }
- // Special case where check for the testing of the exception
- // system.
- catch (libtest::fatal &e)
- {
- if (fatal::is_disabled())
- {
- fatal::increment_disabled_counter();
- return_code= TEST_SUCCESS;
- }
- else
- {
- throw;
- }
- }
-
- gettimeofday(&end_time, NULL);
- load_time= timedif(end_time, start_time);
-
- return return_code;
+ Out << "Collections\t\t\t\t\t" << frame->total();
+ Out << "\tFailed\t\t\t\t\t" << frame->failed();
+ Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
+ Out << "\tSucceeded\t\t\t\t" << frame->success();
+ Outn();
+ Out << "Tests\t\t\t\t\t" << frame->sum_total();
+ Out << "\tFailed\t\t\t\t" << frame->sum_failed();
+ Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
+ Out << "\tSucceeded\t\t\t" << frame->sum_success();
}
#include <getopt.h>
unsigned long int opt_repeat= 1; // Run all tests once
bool opt_quiet= false;
std::string collection_to_run;
+ std::string wildcard;
// Options parsing
{
OPT_LIBYATL_MATCH_COLLECTION,
OPT_LIBYATL_MASSIVE,
OPT_LIBYATL_QUIET,
+ OPT_LIBYATL_MATCH_WILDCARD,
OPT_LIBYATL_REPEAT
};
{ "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
{ "repeat", no_argument, NULL, OPT_LIBYATL_REPEAT },
{ "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
+ { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
{ "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
{ 0, 0, 0, 0 }
};
collection_to_run= optarg;
break;
+ case OPT_LIBYATL_MATCH_WILDCARD:
+ wildcard= optarg;
+ break;
+
case OPT_LIBYATL_MASSIVE:
opt_massive= true;
break;
return EXIT_FAILURE;
}
+ if (getenv("YATL_COLLECTION_TO_RUN"))
+ {
+ if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
+ {
+ collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
+ }
+ }
+
+ if (collection_to_run.compare("none") == 0)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ if (collection_to_run.empty() == false)
+ {
+ Out << "Only testing " << collection_to_run;
+ }
+
int exit_code;
try
do
{
exit_code= EXIT_SUCCESS;
- std::auto_ptr<Framework> frame(new Framework);
-
fatal_assert(sigignore(SIGPIPE) == 0);
libtest::SignalThread signal;
return EXIT_FAILURE;
}
- Stats stats;
-
- get_world(frame.get());
-
- test_return_t error;
- void *creators_ptr= frame->create(error);
-
- switch (error)
- {
- case TEST_SUCCESS:
- break;
-
- case TEST_SKIPPED:
- Out << "SKIP " << argv[0];
- return EXIT_SUCCESS;
-
- case TEST_FAILURE:
- return EXIT_FAILURE;
- }
-
- if (getenv("YATL_COLLECTION_TO_RUN"))
- {
- if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
- {
- collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
- }
- }
-
- if (collection_to_run.compare("none") == 0)
- {
- return EXIT_SUCCESS;
- }
-
- if (collection_to_run.empty() == false)
- {
- Out << "Only testing " << collection_to_run;
- }
-
- char *wildcard= NULL;
- if (argc == 3)
- {
- wildcard= argv[2];
- }
+ std::auto_ptr<Framework> frame(new Framework(signal, collection_to_run, wildcard));
- for (collection_st *next= frame->collections; next and next->name and (not signal.is_shutdown()); next++)
+ // Run create(), bail on error.
{
- if (collection_to_run.empty() == false and fnmatch(collection_to_run.c_str(), next->name, 0))
- {
- continue;
- }
-
- stats.collection_total++;
-
- bool failed= false;
- bool skipped= false;
- test_return_t collection_rc;
- if (test_success(collection_rc= frame->runner()->pre(next->pre, creators_ptr)))
- {
- Out << "Collection: " << next->name;
-
- for (test_st *run= next->tests; run->name; run++)
- {
- long int load_time= 0;
-
- if (wildcard && fnmatch(wildcard, run->name, 0))
- {
- continue;
- }
-
- test_return_t return_code;
- try
- {
- if (run->requires_flush)
- {
- if (test_failed(frame->runner()->flush(creators_ptr)))
- {
- Error << "frame->runner()->flush(creators_ptr)";
- continue;
- }
- }
-
- return_code= runner_code(frame.get(), run, creators_ptr, load_time);
-
- if (return_code == TEST_SKIPPED)
- { }
- else if (return_code == TEST_FAILURE)
- {
-#if 0
- Error << " frame->runner()->run(failure)";
- signal.set_shutdown(SHUTDOWN_GRACEFUL);
-#endif
- }
-
- }
- catch (libtest::fatal &e)
- {
- Error << "Fatal exception was thrown: " << e.what();
- return_code= TEST_FAILURE;
- throw;
- }
- catch (std::exception &e)
- {
- Error << "Exception was thrown: " << e.what();
- return_code= TEST_FAILURE;
- throw;
- }
- catch (...)
- {
- Error << "Unknown exception occurred";
- return_code= TEST_FAILURE;
- throw;
- }
-
- 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_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;
-
- default:
- fatal_message("invalid return code");
- }
-#if 0
- @TODO add code here to allow for a collection to define a method to reset to allow tests to continue.
-#endif
- }
-
- (void) frame->runner()->post(next->post, creators_ptr);
- }
- else if (collection_rc == TEST_FAILURE)
- {
- Out << next->name << " [ failed ]";
- failed= true;
-#if 0
- signal.set_shutdown(SHUTDOWN_GRACEFUL);
-#endif
- }
- else if (collection_rc == TEST_SKIPPED)
+ switch (frame->create())
{
- Out << next->name << " [ skipping ]";
- skipped= true;
- }
-
- if (failed == false and skipped == false)
- {
- stats.collection_success++;
- }
+ case TEST_SUCCESS:
+ break;
- if (failed)
- {
- stats.collection_failed++;
- }
+ case TEST_SKIPPED:
+ Out << "SKIP " << argv[0];
+ return EXIT_SUCCESS;
- if (skipped)
- {
- stats.collection_skipped++;
+ case TEST_FAILURE:
+ return EXIT_FAILURE;
}
-
- Outn();
}
+ frame->exec();
+
if (signal.is_shutdown() == false)
{
signal.set_shutdown(SHUTDOWN_GRACEFUL);
Out << "Tests were aborted.";
exit_code= EXIT_FAILURE;
}
- else if (stats.collection_failed)
+ else if (frame->failed())
{
Out << "Some test failed.";
exit_code= EXIT_FAILURE;
}
- else if (stats.collection_skipped and stats.collection_failed and stats.collection_success)
+ else if (frame->skipped() and frame->failed() and frame->success())
{
Out << "Some tests were skipped.";
}
- else if (stats.collection_success and (stats.collection_failed == 0))
+ else if (frame->success() and (frame->failed() == 0))
{
Out << "All tests completed successfully.";
}
- stats_print(&stats);
+ stats_print(frame.get());
Outn(); // Generate a blank to break up the messages if make check/test has been run
} while (exit_code == EXIT_SUCCESS and --opt_repeat);
catch (libtest::fatal& e)
{
std::cerr << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
}
catch (libtest::disconnected& e)
{
std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
}
catch (...)
{
std::cerr << "Unknown exception halted execution." << std::endl;
+ exit_code= EXIT_FAILURE;
}
return exit_code;
#include <signal.h>
-#include <libtest/stats.h>
#include <libtest/signal.h>
#ifndef __INTEL_COMPILER
// If we find that we already have a pid then kill it.
if (has_pid() == true)
{
+#if 0
fatal_message("has_pid() failed, programer error");
+#endif
}
// This needs more work.
if (kill_file(pid_file()) == false)
{
throw libtest::fatal(LIBYATL_DEFAULT_PARAM,
- "Failed to kill off server, waited: %u after startup occurred, when pinging failed: %s stderr:%s",
+ "Failed to kill off server, waited: %u after startup occurred, when pinging failed: %.*s stderr:%.*s",
this_wait,
- pid_file().c_str(),
- _app.stderr_c_str());
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
}
throw libtest::fatal(LIBYATL_DEFAULT_PARAM,
- "Failed native ping(), pid: %d is alive: %s waited: %u server started, having pid_file. exec: %s stderr:%s",
+ "Failed native ping(), pid: %d is alive: %s waited: %u server started, having pid_file. exec: %.*s stderr:%.*s",
int(_app.pid()),
_app.check() ? "true" : "false",
- this_wait, _running.c_str(),
- _app.stderr_c_str());
+ this_wait,
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
}
else
{
throw libtest::fatal(LIBYATL_DEFAULT_PARAM,
- "Failed native ping(), pid: %d is alive: %s waited: %u server started. exec: %s stderr:%s",
+ "Failed native ping(), pid: %d is alive: %s waited: %u server started. exec: %.*s stderr:%.*s",
int(_app.pid()),
_app.check() ? "true" : "false",
this_wait,
- _running.c_str(),
- _app.stderr_c_str());
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
}
_running.clear();
return false;
return tmp;
}
-bool server_startup_st::shutdown(uint32_t number_of_host)
+// host_to_shutdown => host number to shutdown in array
+bool server_startup_st::shutdown(uint32_t host_to_shutdown)
{
- if (servers.size() > number_of_host)
+ if (servers.size() > host_to_shutdown)
{
- Server* tmp= servers[number_of_host];
+ Server* tmp= servers[host_to_shutdown];
- if (tmp and tmp->has_pid() and tmp->kill() == false)
+ if (tmp and tmp->kill() == false)
{ }
else
{
return false;
}
-void server_startup_st::shutdown_and_remove()
+void server_startup_st::clear()
{
for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
{
server_startup_st::~server_startup_st()
{
- shutdown_and_remove();
+ clear();
}
bool server_startup_st::validate()
}
- void shutdown_and_remove();
+ // Just remove everything after shutdown
+ void clear();
+
bool shutdown();
bool shutdown(uint32_t number_of_host);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct Stats {
- int32_t collection_success;
- int32_t collection_skipped;
- int32_t collection_failed;
- int32_t collection_total;
-
- uint32_t success;
- uint32_t skipped;
- uint32_t failed;
- uint32_t total;
-
- Stats() :
- collection_success(0),
- collection_skipped(0),
- collection_failed(0),
- collection_total(0),
- success(0),
- skipped(0),
- failed(0),
- total(0)
- { }
-};
-
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <libtest/stream.h>
+
+namespace libtest {
+namespace stream {
+
+namespace detail {
+
+} // namespace detail
+
+make_cerr::make_cerr(const char* filename, int line_number, const char* func) :
+ log(std::cerr, filename, line_number, func)
+{ }
+
+cerr::cerr(const char* filename, int line_number, const char* func) :
+ log(std::cout, filename, line_number, func)
+ { }
+
+clog::clog(const char* filename, int line_number, const char* func) :
+ log(std::clog, filename, line_number, func)
+ { }
+
+cout::cout(const char* filename, int line_number, const char* func) :
+ log(std::cout, filename, line_number, func)
+ { }
+
+} // namespace stream
+} // namespace libtest
namespace detail {
template<class Ch, class Tr, class A>
- class cerr {
+ class channel {
private:
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
- void operator()(const stream_buffer &s)
+ void operator()(const stream_buffer& s, std::ostream& _out,
+ const char* filename, int line_number, const char* func)
{
- std::cerr << s.str() << std::endl;
- }
- };
-
-template<class Ch, class Tr, class A>
- class make_cerr {
- private:
-
- public:
- typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
-
- public:
- void operator()(const stream_buffer &s)
- {
- std::cerr << std::endl << s.str() << std::endl;
- }
- };
-
-template<class Ch, class Tr, class A>
- class cout {
- private:
-
- public:
- typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
-
- public:
- void operator()(const stream_buffer &s)
- {
- std::cout << s.str() << std::endl;
+ if (filename)
+ {
+ _out
+ << filename
+ << ":"
+ << line_number
+ << ": in "
+ << func << "() "
+ << s.str()
+ << std::endl;
+ }
+ else
+ {
+ _out
+ << s.str()
+ << std::endl;
+ }
}
};
template<class Ch, class Tr, class A>
- class clog {
+ class channelln {
private:
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
- void operator()(const stream_buffer &s)
+ void operator()(const stream_buffer& s, std::ostream& _out,
+ const char* filename, int line_number, const char* func)
{
- std::cerr<< s.str() << std::endl;
+ if (filename)
+ {
+ _out
+ << std::endl
+ << filename
+ << ":"
+ << line_number
+ << ": in "
+ << func << "() "
+ << s.str()
+ << std::endl;
+ }
+ else
+ {
+ _out
+ << std::endl
+ << s.str()
+ << std::endl;
+ }
}
};
class log {
private:
typedef OutputPolicy<Ch, Tr, A> output_policy;
+
+ private:
+ std::ostream& _out;
const char *_filename;
int _line_number;
const char *_func;
public:
- log() :
- _filename(NULL),
- _line_number(0)
+ log(std::ostream& out_arg, const char* filename, int line_number, const char* func) :
+ _out(out_arg),
+ _filename(filename),
+ _line_number(line_number),
+ _func(func)
{ }
- void set_filename(const char *filename, int line_number, const char *func)
- {
- _filename= filename;
- _line_number= line_number;
- _func= func;
- }
-
~log()
{
- output_policy()(arg);
+ output_policy()(arg, _out, _filename, _line_number, _func);
}
public:
template<class T>
log &operator<<(const T &x)
{
- if (_filename)
- {
- arg << _filename << ":" << _line_number << ": in " << _func << "() ";
- _filename= NULL;
- }
arg << x;
return *this;
}
private:
typename output_policy::stream_buffer arg;
};
-}
+} // namespace detail
-class make_cerr : public detail::log<detail::make_cerr> {
+class make_cerr : public detail::log<detail::channelln> {
public:
- make_cerr(const char *filename, int line_number, const char *func)
- {
- set_filename(filename, line_number, func);
- }
+ make_cerr(const char* filename, int line_number, const char* func);
};
-class cerr : public detail::log<detail::cerr> {
+class cerr : public detail::log<detail::channel> {
public:
- cerr(const char *filename, int line_number, const char *func)
- {
- set_filename(filename, line_number, func);
- }
+ cerr(const char* filename, int line_number, const char* func);
};
-class clog : public detail::log<detail::clog> {
+class clog : public detail::log<detail::channel> {
public:
- clog(const char *, int, const char*)
- { }
+ clog(const char* filename, int line_number, const char* func);
};
-class cout : public detail::log<detail::cout> {
+class cout : public detail::log<detail::channel> {
public:
- cout(const char *, int, const char *)
- { }
+ cout(const char* filename, int line_number, const char* func);
};
#include <libtest/has.hpp>
#include <libtest/error.h>
#include <libtest/strerror.h>
+#include <libtest/timer.hpp>
#include <libtest/stream.h>
#include <libtest/comparison.hpp>
#include <libtest/server.h>
#include <libtest/port.h>
#include <libtest/is_local.hpp>
#include <libtest/socket.hpp>
-#include <libtest/stats.h>
#include <libtest/collection.h>
#include <libtest/framework.h>
#include <libtest/get.h>
-#include <libtest/stream.h>
#include <libtest/cmdline.h>
#include <libtest/string.hpp>
#include <libtest/binaries.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <libtest/timer.hpp>
+#include <ctime>
+
+namespace libtest {
+
+std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg)
+{
+ struct timespec temp;
+ arg.difference(temp);
+
+ output << temp.tv_sec;
+ output << ":";
+ output << temp.tv_nsec;
+
+ return output;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <ctime>
+#include <ostream>
+
+#ifdef __MACH__
+# include <mach/clock.h>
+# include <mach/mach.h>
+#else
+# include <sys/time.h>
+#endif
+
+
+namespace libtest {
+
+class Timer {
+public:
+
+ Timer()
+ {
+ _begin.tv_sec= 0;
+ _begin.tv_nsec= 0;
+ _end.tv_sec= 0;
+ _end.tv_nsec= 0;
+ }
+
+ void reset()
+ {
+ _end.tv_sec= 0;
+ _end.tv_nsec= 0;
+ _time(_begin);
+ }
+
+ void sample()
+ {
+ _time(_end);
+ }
+
+ void difference(struct timespec& arg) const
+ {
+ if ((_end.tv_nsec -_begin.tv_nsec) < 0)
+ {
+ arg.tv_sec= _end.tv_sec -_begin.tv_sec-1;
+ arg.tv_nsec= 1000000000 +_end.tv_nsec -_begin.tv_nsec;
+
+ }
+ else
+ {
+ arg.tv_sec= _end.tv_sec -_begin.tv_sec;
+ arg.tv_nsec= _end.tv_nsec -_begin.tv_nsec;
+ }
+ }
+
+private:
+ void _time(struct timespec& ts)
+ {
+#ifdef __MACH__ // OSX lacks clock_gettime()
+ clock_serv_t _clock_serv;
+ mach_timespec_t _mach_timespec;
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &_clock_serv);
+ clock_get_time(_clock_serv, &_mach_timespec);
+ mach_port_deallocate(mach_task_self(), _clock_serv);
+ ts.tv_sec= _mach_timespec.tv_sec;
+ ts.tv_nsec= _mach_timespec.tv_nsec;
+#else
+ clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+ }
+
+private:
+ struct timespec _begin;
+ struct timespec _end;
+};
+
+std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg);
+
+} // namespace libtest
static test_return_t shutdown_and_remove_TEST(void *obj)
{
server_startup_st *servers= (server_startup_st*)obj;
- servers->shutdown_and_remove();
+ servers->clear();
return TEST_SUCCESS;
}
static test_return_t collection_FINAL(void *object)
{
server_startup_st *servers= (server_startup_st*)object;
- servers->shutdown_and_remove();
+ servers->clear();
return TEST_SUCCESS;
}
memcached_return_t ret;
do {
- sleep(3);
+ libtest::dream(3, 0);
ret= memcached_set(memc, test_literal_param("foo"), NULL, 0, time_t(0), uint32_t(0));
} while (ret == MEMCACHED_SERVER_TEMPORARILY_DISABLED);
test_compare(MEMCACHED_SERVER_TEMPORARILY_DISABLED, ret);
do {
- sleep(3);
+ libtest::dream(3, 0);
ret= memcached_set(memc, test_literal_param("foo"), NULL, 0, time_t(0), uint32_t(0));
} while (ret == MEMCACHED_SERVER_TEMPORARILY_DISABLED or ret == MEMCACHED_SUCCESS);
{ 0, 0, 0, 0 }
};
-#include "libmemcached_world.h"
+#include "tests/libmemcached_world.h"
void get_world(Framework *world)
{
check_PROGRAMS+= tests/failure
noinst_PROGRAMS+= tests/failure
-tests_testhashkit_SOURCES = tests/hashkit_functions.cc
-tests_testhashkit_DEPENDENCIES = libtest/libtest.la libhashkit/libhashkit.la $(TESTS_LDADDS)
-tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES)
+test-failure: tests/failure
+ @tests/failure
+
+gdb-failure: tests/failure
+ @$(DEBUG_COMMAND) tests/failure
+
+
+tests_testhashkit_SOURCES= tests/hashkit_functions.cc
+tests_testhashkit_DEPENDENCIES= libtest/libtest.la libhashkit/libhashkit.la $(TESTS_LDADDS)
+tests_testhashkit_LDADD= $(tests_testhashkit_DEPENDENCIES)
check_PROGRAMS+= tests/testhashkit
noinst_PROGRAMS+= tests/testhashkit
+test-hash: tests/testhashkit
+ @tests/testhashkit
+
+
tests_hash_plus_SOURCES= tests/hash_plus.cc
tests_hash_plus_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
tests_hash_plus_DEPENDENCIES= $(tests_testhashkit_DEPENDENCIES)
test-plus: tests/testplus
@tests/testplus
-test-hash: tests/testhashkit
- @tests/testhashkit
-
test-hashplus: tests/hash_plus
@tests/hash_plus
gdb-cycle: tests/cycle
@$(DEBUG_COMMAND) tests/cycle
-gdb-failure: tests/failure
- @$(DEBUG_COMMAND) tests/failure
-
valgrind-cycle: tests/cycle
$(VALGRIND_COMMAND) tests/cycle
test_null(container->parent());
container->parent(memcached(container->construct.option_string().c_str(), container->construct.option_string().size()));
test_true(container->parent());
+#if 0
test_compare(MEMCACHED_SUCCESS, memcached_version(container->parent()));
+#endif
if (container->construct.sasl())
{