test_datasrc_clients_mgr.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <datasrc/datasrc_config.h>
  19. #include <asiolink/io_service.h>
  20. #include <boost/function.hpp>
  21. #include <list>
  22. // In this file we provide specialization of thread, mutex, condition variable,
  23. // and DataSrcClientsBuilder for convenience of tests. They don't use
  24. // actual threads or mutex, and allow tests to inspect some internal states
  25. // of the corresponding objects.
  26. //
  27. // In many cases, tests can use TestDataSrcClientsMgr (defined below) where
  28. // DataSrcClientsMgr is needed.
  29. // Below we extend the isc::auth::datasrc_clientmgr_internal namespace to
  30. // specialize the doNoop() method.
  31. namespace isc {
  32. namespace auth {
  33. namespace datasrc_clientmgr_internal {
  34. class TestMutex {
  35. public:
  36. // for throw_from_noop.
  37. // None: no throw from specialized doNoop()
  38. // EXCLASS: throw some exception class object
  39. // INTEGER: throw an integer
  40. // INTERNAL: internal error (shouldn't terminate the thread)
  41. enum ExceptionFromNoop { NONE, EXCLASS, INTEGER, INTERNAL };
  42. TestMutex() : lock_count(0), unlock_count(0), noop_count(0),
  43. throw_from_noop(NONE)
  44. {}
  45. class Locker {
  46. public:
  47. Locker(TestMutex& mutex) : mutex_(mutex) {
  48. if (mutex.lock_count != mutex.unlock_count) {
  49. isc_throw(Unexpected,
  50. "attempt of duplicate lock acquisition");
  51. }
  52. ++mutex.lock_count;
  53. if (mutex.lock_count > 100) { // 100 is an arbitrary choice
  54. isc_throw(Unexpected,
  55. "too many test mutex count, likely a bug in test");
  56. }
  57. }
  58. ~Locker() {
  59. ++mutex_.unlock_count;
  60. }
  61. private:
  62. TestMutex& mutex_;
  63. };
  64. size_t lock_count; // number of lock acquisitions; tests can check this
  65. size_t unlock_count; // number of lock releases; tests can check this
  66. size_t noop_count; // allow doNoop() to modify this
  67. ExceptionFromNoop throw_from_noop; // tests can set this to control doNoop
  68. };
  69. class TestCondVar {
  70. public:
  71. TestCondVar() : wait_count(0), signal_count(0), command_queue_(NULL),
  72. delayed_command_queue_(NULL)
  73. {}
  74. TestCondVar(std::list<Command>& command_queue,
  75. std::list<Command>& delayed_command_queue) :
  76. wait_count(0),
  77. signal_count(0),
  78. command_queue_(&command_queue),
  79. delayed_command_queue_(&delayed_command_queue)
  80. {
  81. }
  82. void wait(TestMutex& mutex) {
  83. // bookkeeping
  84. ++mutex.unlock_count;
  85. ++wait_count;
  86. ++mutex.lock_count;
  87. if (wait_count > 100) { // 100 is an arbitrary choice
  88. isc_throw(Unexpected,
  89. "too many cond wait count, likely a bug in test");
  90. }
  91. // make the delayed commands available
  92. command_queue_->splice(command_queue_->end(), *delayed_command_queue_);
  93. }
  94. void signal() {
  95. ++signal_count;
  96. }
  97. size_t wait_count; // number of calls to wait(); tests can check this
  98. size_t signal_count; // number of calls to signal(); tests can check this
  99. private:
  100. std::list<Command>* command_queue_;
  101. std::list<Command>* delayed_command_queue_;
  102. };
  103. // Convenient shortcut
  104. typedef DataSrcClientsBuilderBase<TestMutex, TestCondVar>
  105. TestDataSrcClientsBuilder;
  106. // We specialize this command handler for the convenience of tests.
  107. // It abuses our specialized Mutex to count the number of calls of this method.
  108. template<>
  109. void
  110. TestDataSrcClientsBuilder::doNoop();
  111. // A specialization of DataSrcClientsBuilder that allows tests to inspect
  112. // its internal states via static class variables. Using static is suboptimal,
  113. // but DataSrcClientsMgr is highly encapsulated, this seems to be the best
  114. // possible compromise.
  115. class FakeDataSrcClientsBuilder {
  116. public:
  117. // true iff a builder has started.
  118. static bool started;
  119. // These five correspond to the resource shared with the manager.
  120. // xxx_copy will be set in the manager's destructor to record the
  121. // final state of the manager.
  122. static std::list<Command>* command_queue;
  123. static std::list<FinishedCallback>* callback_queue;
  124. static TestCondVar* cond;
  125. static TestMutex* queue_mutex;
  126. static int wakeup_fd;
  127. static isc::datasrc::ClientListMapPtr* clients_map;
  128. static TestMutex* map_mutex;
  129. static std::list<Command> command_queue_copy;
  130. static std::list<FinishedCallback> callback_queue_copy;
  131. static TestCondVar cond_copy;
  132. static TestMutex queue_mutex_copy;
  133. // true iff the manager waited on the thread running the builder.
  134. static bool thread_waited;
  135. // If set to true by a test, TestThread::wait() throws an exception
  136. // exception.
  137. enum ExceptionFromWait { NOTHROW, THROW_UNCAUGHT_EX, THROW_OTHER };
  138. static ExceptionFromWait thread_throw_on_wait;
  139. FakeDataSrcClientsBuilder(
  140. std::list<Command>* command_queue,
  141. std::list<FinishedCallback>* callback_queue,
  142. TestCondVar* cond,
  143. TestMutex* queue_mutex,
  144. isc::datasrc::ClientListMapPtr* clients_map,
  145. TestMutex* map_mutex, int wakeup_fd)
  146. {
  147. FakeDataSrcClientsBuilder::started = false;
  148. FakeDataSrcClientsBuilder::command_queue = command_queue;
  149. FakeDataSrcClientsBuilder::callback_queue = callback_queue;
  150. FakeDataSrcClientsBuilder::cond = cond;
  151. FakeDataSrcClientsBuilder::queue_mutex = queue_mutex;
  152. FakeDataSrcClientsBuilder::wakeup_fd = wakeup_fd;
  153. FakeDataSrcClientsBuilder::clients_map = clients_map;
  154. FakeDataSrcClientsBuilder::map_mutex = map_mutex;
  155. FakeDataSrcClientsBuilder::thread_waited = false;
  156. FakeDataSrcClientsBuilder::thread_throw_on_wait = NOTHROW;
  157. }
  158. void run() {
  159. FakeDataSrcClientsBuilder::started = true;
  160. }
  161. };
  162. // A fake thread class that doesn't really invoke thread but simply calls
  163. // the given main function (synchronously). Tests can tweak the wait()
  164. // behavior via some static variables so it will throw some exceptions.
  165. class TestThread {
  166. public:
  167. TestThread(const boost::function<void()>& main) {
  168. main();
  169. }
  170. void wait() {
  171. FakeDataSrcClientsBuilder::thread_waited = true;
  172. switch (FakeDataSrcClientsBuilder::thread_throw_on_wait) {
  173. case FakeDataSrcClientsBuilder::NOTHROW:
  174. break;
  175. case FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX:
  176. isc_throw(util::thread::Thread::UncaughtException,
  177. "TestThread wait() saw an exception");
  178. case FakeDataSrcClientsBuilder::THROW_OTHER:
  179. isc_throw(Unexpected,
  180. "General emulated failure in TestThread wait()");
  181. }
  182. }
  183. };
  184. } // namespace datasrc_clientmgr_internal
  185. // Convenient shortcut
  186. typedef DataSrcClientsMgrBase<
  187. datasrc_clientmgr_internal::TestThread,
  188. datasrc_clientmgr_internal::FakeDataSrcClientsBuilder,
  189. datasrc_clientmgr_internal::TestMutex,
  190. datasrc_clientmgr_internal::TestCondVar> TestDataSrcClientsMgrBase;
  191. // A specialization of manager's "cleanup" called at the end of the
  192. // destructor. We use this to record the final values of some of the class
  193. // member variables.
  194. template<>
  195. void
  196. TestDataSrcClientsMgrBase::cleanup();
  197. template<>
  198. void
  199. TestDataSrcClientsMgrBase::reconfigureHook();
  200. // A (hackish) trick how to not require the IOService to be passed from the
  201. // tests. We can't create the io service as a member, because it would
  202. // get initialized too late.
  203. class TestDataSrcClientsMgr :
  204. public asiolink::IOService,
  205. public TestDataSrcClientsMgrBase {
  206. public:
  207. TestDataSrcClientsMgr() :
  208. TestDataSrcClientsMgrBase(*static_cast<asiolink::IOService*>(this))
  209. {}
  210. };
  211. } // namespace auth
  212. } // namespace isc
  213. #endif // TEST_DATASRC_CLIENTS_MGR_H
  214. // Local Variables:
  215. // mode: c++
  216. // End: