test_datasrc_clients_mgr.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef TEST_DATASRC_CLIENTS_MGR_H
  15. #define TEST_DATASRC_CLIENTS_MGR_H 1
  16. #include <exceptions/exceptions.h>
  17. #include <auth/datasrc_clients_mgr.h>
  18. #include <boost/function.hpp>
  19. #include <list>
  20. // In this file we provide specialization of thread, mutex, condition variable,
  21. // and DataSrcClientsBuilder for convenience of tests. They don't use
  22. // actual threads or mutex, and allow tests to inspect some internal states
  23. // of the corresponding objects.
  24. //
  25. // In many cases, tests can use TestDataSrcClientsMgr (defined below) where
  26. // DataSrcClientsMgr is needed.
  27. // Below we extend the isc::auth::datasrc_clientmgr_internal namespace to
  28. // specialize the doNoop() method.
  29. namespace isc {
  30. namespace auth {
  31. namespace datasrc_clientmgr_internal {
  32. class TestMutex {
  33. public:
  34. // for throw_from_noop.
  35. // None: no throw from specialized doNoop()
  36. // EXCLASS: throw some exception class object
  37. // INTEGER: throw an integer
  38. enum ExceptionFromNoop { NONE, EXCLASS, INTEGER };
  39. TestMutex() : lock_count(0), unlock_count(0), noop_count(0),
  40. throw_from_noop(NONE)
  41. {}
  42. class Locker {
  43. public:
  44. Locker(TestMutex& mutex) : mutex_(mutex) {
  45. ++mutex.lock_count;
  46. if (mutex.lock_count > 100) { // 100 is an arbitrary choice
  47. isc_throw(Unexpected,
  48. "too many test mutex count, likely a bug in test");
  49. }
  50. }
  51. ~Locker() {
  52. ++mutex_.unlock_count;
  53. }
  54. private:
  55. TestMutex& mutex_;
  56. };
  57. size_t lock_count; // number of lock acquisitions; tests can check this
  58. size_t unlock_count; // number of lock releases; tests can check this
  59. size_t noop_count; // allow doNoop() to modify this
  60. ExceptionFromNoop throw_from_noop; // tests can set this to control doNoop
  61. };
  62. class TestCondVar {
  63. public:
  64. TestCondVar() : wait_count(0), signal_count(0), command_queue_(NULL),
  65. delayed_command_queue_(NULL)
  66. {}
  67. TestCondVar(std::list<Command>& command_queue,
  68. std::list<Command>& delayed_command_queue) :
  69. wait_count(0),
  70. command_queue_(&command_queue),
  71. delayed_command_queue_(&delayed_command_queue)
  72. {
  73. }
  74. void wait(TestMutex& mutex) {
  75. // bookkeeping
  76. ++mutex.unlock_count;
  77. ++wait_count;
  78. ++mutex.lock_count;
  79. if (wait_count > 100) { // 100 is an arbitrary choice
  80. isc_throw(Unexpected,
  81. "too many cond wait count, likely a bug in test");
  82. }
  83. // make the delayed commands available
  84. command_queue_->splice(command_queue_->end(), *delayed_command_queue_);
  85. }
  86. void signal() {
  87. ++signal_count;
  88. }
  89. size_t wait_count; // number of calls to wait(); tests can check this
  90. size_t signal_count; // number of calls to signal(); tests can check this
  91. private:
  92. std::list<Command>* command_queue_;
  93. std::list<Command>* delayed_command_queue_;
  94. };
  95. // Convenient shortcut
  96. typedef DataSrcClientsBuilderBase<TestMutex, TestCondVar>
  97. TestDataSrcClientsBuilder;
  98. // We specialize this command handler for the convenience of tests.
  99. // It abuses our specialized Mutex to count the number of calls of this method.
  100. template<>
  101. void
  102. TestDataSrcClientsBuilder::doNoop();
  103. // A specialization of DataSrcClientsBuilder that allows tests to inspect
  104. // its internal states via static class variables. Using static is suboptimal,
  105. // but DataSrcClientsMgr is highly encapsulated, this seems to be the best
  106. // possible compromise.
  107. class FakeDataSrcClientsBuilder {
  108. public:
  109. // true iff a builder has started.
  110. static bool started;
  111. // These three correspond to the resource shared with the manager.
  112. // xxx_copy will be set in the manager's destructor to record the
  113. // final state of the manager.
  114. static std::list<Command>* command_queue;
  115. static TestCondVar* cond;
  116. static TestMutex* queue_mutex;
  117. static std::list<Command> command_queue_copy;
  118. static TestCondVar cond_copy;
  119. static TestMutex queue_mutex_copy;
  120. // true iff the manager waited on the thread running the builder.
  121. static bool thread_waited;
  122. // If set to true by a test, TestThread::wait() throws an exception
  123. // exception.
  124. enum ExceptionFromWait { NOTHROW, THROW_UNCAUGHT_EX, THROW_OTHER };
  125. static ExceptionFromWait thread_throw_on_wait;
  126. FakeDataSrcClientsBuilder(
  127. std::list<Command>* command_queue,
  128. TestCondVar* cond,
  129. TestMutex* queue_mutex)
  130. {
  131. FakeDataSrcClientsBuilder::started = false;
  132. FakeDataSrcClientsBuilder::command_queue = command_queue;
  133. FakeDataSrcClientsBuilder::cond = cond;
  134. FakeDataSrcClientsBuilder::queue_mutex = queue_mutex;
  135. FakeDataSrcClientsBuilder::thread_waited = false;
  136. FakeDataSrcClientsBuilder::thread_throw_on_wait = NOTHROW;
  137. }
  138. void run() {
  139. FakeDataSrcClientsBuilder::started = true;
  140. }
  141. };
  142. // A fake thread class that doesn't really invoke thread but simply calls
  143. // the given main function (synchronously). Tests can tweak the wait()
  144. // behavior via some static variables so it will throw some exceptions.
  145. class TestThread {
  146. public:
  147. TestThread(const boost::function<void()>& main) {
  148. main();
  149. }
  150. void wait() {
  151. FakeDataSrcClientsBuilder::thread_waited = true;
  152. switch (FakeDataSrcClientsBuilder::thread_throw_on_wait) {
  153. case FakeDataSrcClientsBuilder::NOTHROW:
  154. break;
  155. case FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX:
  156. isc_throw(util::thread::Thread::UncaughtException,
  157. "TestThread wait() saw an exception");
  158. case FakeDataSrcClientsBuilder::THROW_OTHER:
  159. isc_throw(Unexpected,
  160. "General emulated failure in TestThread wait()");
  161. }
  162. }
  163. };
  164. } // namespace datasrc_clientmgr_internal
  165. // Convenient shortcut
  166. typedef DataSrcClientsMgrBase<
  167. datasrc_clientmgr_internal::TestThread,
  168. datasrc_clientmgr_internal::FakeDataSrcClientsBuilder,
  169. datasrc_clientmgr_internal::TestMutex,
  170. datasrc_clientmgr_internal::TestCondVar> TestDataSrcClientsMgr;
  171. // A specialization of manager's "cleanup" called at the end of the
  172. // destructor. We use this to record the final values of some of the class
  173. // member variables.
  174. template<>
  175. void
  176. TestDataSrcClientsMgr::cleanup();
  177. } // namespace auth
  178. } // namespace isc
  179. #endif // TEST_DATASRC_CLIENTS_MGR_H
  180. // Local Variables:
  181. // mode: c++
  182. // End: