2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-05 16:35:23 +00:00
Files
kea/src/bin/auth/tests/test_datasrc_clients_mgr.h
JINMEI Tatuya c2608e7b39 [2205] avoid referencing post-destructor member variables.
by a bit ugly hack: we specialize some part of the destructor and make
a local copy of these variables so the tests can inspect them later.
2012-10-17 15:56:27 -07:00

205 lines
7.0 KiB
C++

// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef TEST_DATASRC_CLIENTS_MGR_H
#define TEST_DATASRC_CLIENTS_MGR_H 1
#include <exceptions/exceptions.h>
#include <auth/datasrc_clients_mgr.h>
#include <boost/function.hpp>
#include <list>
// In this file we provide specialization of thread, mutex, condition variable,
// and DataSrcClientsBuilder for convenience of tests. They don't use
// actual threads or mutex, and allow tests to inspect some internal states
// of the corresponding objects.
//
// In many cases, tests can use TestDataSrcClientsMgr (defined below) where
// DataSrcClientsMgr is needed.
// Below we extend the isc::auth::datasrc_clientmgr_internal namespace to
// specialize the doNoop() method.
namespace isc {
namespace auth {
namespace datasrc_clientmgr_internal {
class TestMutex {
public:
// for throw_from_noop.
// None: no throw from specialized doNoop()
// EXCLASS: throw some exception class object
// INTEGER: throw an integer
enum ExceptionFromNoop { NONE, EXCLASS, INTEGER };
TestMutex() : lock_count(0), unlock_count(0), noop_count(0),
throw_from_noop(NONE)
{}
class Locker {
public:
Locker(TestMutex& mutex) : mutex_(mutex) {
++mutex.lock_count;
if (mutex.lock_count > 100) { // 100 is an arbitrary choice
isc_throw(Unexpected,
"too many test mutex count, likely a bug in test");
}
}
~Locker() {
++mutex_.unlock_count;
}
private:
TestMutex& mutex_;
};
size_t lock_count; // number of lock acquisitions; tests can check this
size_t unlock_count; // number of lock releases; tests can check this
size_t noop_count; // allow doNoop() to modify this
ExceptionFromNoop throw_from_noop; // tests can set this to control doNoop
};
class TestCondVar {
public:
TestCondVar() : wait_count(0), signal_count(0), command_queue_(NULL),
delayed_command_queue_(NULL)
{}
TestCondVar(std::list<Command>& command_queue,
std::list<Command>& delayed_command_queue) :
wait_count(0),
command_queue_(&command_queue),
delayed_command_queue_(&delayed_command_queue)
{
}
void wait(TestMutex& mutex) {
// bookkeeping
++mutex.unlock_count;
++wait_count;
++mutex.lock_count;
if (wait_count > 100) { // 100 is an arbitrary choice
isc_throw(Unexpected,
"too many cond wait count, likely a bug in test");
}
// make the delayed commands available
command_queue_->splice(command_queue_->end(), *delayed_command_queue_);
}
void signal() {
++signal_count;
}
size_t wait_count; // number of calls to wait(); tests can check this
size_t signal_count; // number of calls to signal(); tests can check this
private:
std::list<Command>* command_queue_;
std::list<Command>* delayed_command_queue_;
};
// Convenient shortcut
typedef DataSrcClientsBuilderBase<TestMutex, TestCondVar>
TestDataSrcClientsBuilder;
// We specialize this command handler for the convenience of tests.
// It abuses our specialized Mutex to count the number of calls of this method.
template<>
void
TestDataSrcClientsBuilder::doNoop();
// A specialization of DataSrcClientsBuilder that allows tests to inspect
// its internal states via static class variables. Using static is suboptimal,
// but DataSrcClientsMgr is highly encapsulated, this seems to be the best
// possible compromise.
class FakeDataSrcClientsBuilder {
public:
// true iff a builder has started.
static bool started;
// These three correspond to the resource shared with the manager.
// xxx_copy will be set in the manager's destructor to record the
// final state of the manager.
static std::list<Command>* command_queue;
static TestCondVar* cond;
static TestMutex* queue_mutex;
static std::list<Command> command_queue_copy;
static TestCondVar cond_copy;
static TestMutex queue_mutex_copy;
// true iff the manager waited on the thread running the builder.
static bool thread_waited;
// If set to true by a test, TestThread::wait() throws an exception
// exception.
enum ExceptionFromWait { NOTHROW, THROW_UNCAUGHT_EX, THROW_OTHER };
static ExceptionFromWait thread_throw_on_wait;
FakeDataSrcClientsBuilder(
std::list<Command>* command_queue,
TestCondVar* cond,
TestMutex* queue_mutex)
{
FakeDataSrcClientsBuilder::started = false;
FakeDataSrcClientsBuilder::command_queue = command_queue;
FakeDataSrcClientsBuilder::cond = cond;
FakeDataSrcClientsBuilder::queue_mutex = queue_mutex;
FakeDataSrcClientsBuilder::thread_waited = false;
FakeDataSrcClientsBuilder::thread_throw_on_wait = NOTHROW;
}
void run() {
FakeDataSrcClientsBuilder::started = true;
}
};
// A fake thread class that doesn't really invoke thread but simply calls
// the given main function (synchronously). Tests can tweak the wait()
// behavior via some static variables so it will throw some exceptions.
class TestThread {
public:
TestThread(const boost::function<void()>& main) {
main();
}
void wait() {
FakeDataSrcClientsBuilder::thread_waited = true;
switch (FakeDataSrcClientsBuilder::thread_throw_on_wait) {
case FakeDataSrcClientsBuilder::NOTHROW:
break;
case FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX:
isc_throw(util::thread::Thread::UncaughtException, "for test");
case FakeDataSrcClientsBuilder::THROW_OTHER:
isc_throw(Unexpected, "for test");
}
}
};
} // namespace datasrc_clientmgr_internal
// Convenient shortcut
typedef DataSrcClientsMgrBase<
datasrc_clientmgr_internal::TestThread,
datasrc_clientmgr_internal::FakeDataSrcClientsBuilder,
datasrc_clientmgr_internal::TestMutex,
datasrc_clientmgr_internal::TestCondVar> TestDataSrcClientsMgr;
// A specialization of manager's "cleanup" called at the end of the
// destructor. We use this to record the final values of some of the class
// member variables.
template<>
void
TestDataSrcClientsMgr::cleanup();
} // namespace auth
} // namespace isc
#endif // TEST_DATASRC_CLIENTS_MGR_H
// Local Variables:
// mode: c++
// End: