1 #include <cppunit/extensions/HelperMacros.h> 2 3 #include "torrent/utils/thread_base.h" 4 5 class utils_thread_base_test : public CppUnit::TestFixture { 6 CPPUNIT_TEST_SUITE(utils_thread_base_test); 7 CPPUNIT_TEST(test_basic); 8 CPPUNIT_TEST(test_lifecycle); 9 10 CPPUNIT_TEST(test_global_lock_basic); 11 CPPUNIT_TEST(test_interrupt); 12 CPPUNIT_TEST(test_stop); 13 CPPUNIT_TEST_SUITE_END(); 14 15 public: 16 void setUp(); 17 void tearDown(); 18 19 void test_basic(); 20 void test_lifecycle(); 21 22 void test_global_lock_basic(); 23 void test_interrupt(); 24 void test_interrupt_legacy(); 25 void test_stop(); 26 }; 27 28 struct thread_management_type { thread_management_typethread_management_type29 thread_management_type() { CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock()); } ~thread_management_typethread_management_type30 ~thread_management_type() { torrent::thread_base::release_global_lock(); } 31 }; 32 33 #define SETUP_THREAD() \ 34 thread_management_type thread_management; \ 35 torrent::thread_disk* thread_disk = new torrent::thread_disk(); \ 36 thread_disk->init_thread(); 37 38 #define CLEANUP_THREAD() \ 39 CPPUNIT_ASSERT(wait_for_true(std::bind(&torrent::thread_base::is_inactive, thread_disk))); \ 40 delete thread_disk; 41 42 bool wait_for_true(std::function<bool ()> test_function); 43 44 class thread_test : public torrent::thread_base { 45 public: 46 enum test_state { 47 TEST_NONE, 48 TEST_PRE_START, 49 TEST_PRE_STOP, 50 TEST_STOP 51 }; 52 53 static const int test_flag_pre_stop = 0x1; 54 static const int test_flag_long_timeout = 0x2; 55 56 static const int test_flag_acquire_global = 0x10; 57 static const int test_flag_has_global = 0x20; 58 59 static const int test_flag_do_work = 0x100; 60 static const int test_flag_pre_poke = 0x200; 61 static const int test_flag_post_poke = 0x400; 62 63 thread_test(); 64 test_state()65 int test_state() const { return m_test_state; } is_state(int state)66 bool is_state(int state) const { return m_state == state; } is_test_state(int state)67 bool is_test_state(int state) const { return m_test_state == state; } is_test_flags(int flags)68 bool is_test_flags(int flags) const { return (m_test_flags & flags) == flags; } is_not_test_flags(int flags)69 bool is_not_test_flags(int flags) const { return !(m_test_flags & flags); } 70 name()71 const char* name() const { return "test_thread"; } 72 73 void init_thread(); 74 set_pre_stop()75 void set_pre_stop() { __sync_or_and_fetch(&m_test_flags, test_flag_pre_stop); } set_acquire_global()76 void set_acquire_global() { __sync_or_and_fetch(&m_test_flags, test_flag_acquire_global); } 77 set_test_flag(int flags)78 void set_test_flag(int flags) { __sync_or_and_fetch(&m_test_flags, flags); } 79 80 private: 81 void call_events(); next_timeout_usec()82 int64_t next_timeout_usec() { return (m_test_flags & test_flag_long_timeout) ? (10000 * 1000) : (100 * 1000); } 83 84 int m_test_state lt_cacheline_aligned; 85 int m_test_flags lt_cacheline_aligned; 86 }; 87