00001
00016
00017 #ifndef NET_INSTAWEB_UTIL_PUBLIC_CONDVAR_TEST_BASE_H_
00018 #define NET_INSTAWEB_UTIL_PUBLIC_CONDVAR_TEST_BASE_H_
00019
00020 #include "net/instaweb/util/public/condvar.h"
00021
00022 #include "base/logging.h"
00023 #include "net/instaweb/util/public/abstract_mutex.h"
00024 #include "net/instaweb/util/public/basictypes.h"
00025 #include "net/instaweb/util/public/gtest.h"
00026 #include "net/instaweb/util/public/timer.h"
00027 #include "net/instaweb/util/public/thread_system.h"
00028
00029 namespace net_instaweb {
00030
00031 class CondvarTestBase : public testing::Test {
00032 protected:
00033 typedef void (ThreadSystem::Condvar::*SignalMethod)();
00034
00035 CondvarTestBase()
00036 : mutex_(NULL),
00037 startup_condvar_(NULL),
00038 condvar_(NULL),
00039 ready_to_start_(false),
00040 iters_(0),
00041 current_iter_(0),
00042 signal_method_(&ThreadSystem::Condvar::Signal),
00043 wait_after_signal_(false),
00044 helper_increments_(0),
00045 init_called_(false) {
00046 }
00047
00050 void Init(ThreadSystem::CondvarCapableMutex* mutex,
00051 ThreadSystem::Condvar* startup_condvar,
00052 ThreadSystem::Condvar* condvar) {
00053 CHECK(!init_called_);
00054 mutex_ = mutex;
00055 startup_condvar_ = startup_condvar;
00056 condvar_ = condvar;
00057 init_called_ = true;
00058 }
00059
00060 static void* HelperThread(void* data) {
00061 CondvarTestBase* test = static_cast<CondvarTestBase*>(data);
00062 test->HelperThreadMethod();
00063 return NULL;
00064 }
00065
00069 virtual void CreateHelper() = 0;
00070
00073 virtual void FinishHelper() = 0;
00074
00075 void StartHelper() {
00076 CHECK(init_called_);
00077 CreateHelper();
00078 {
00079 ScopedMutex lock(mutex_);
00080 ready_to_start_ = true;
00081 startup_condvar_->Signal();
00082 }
00083 }
00084
00085 virtual void HelperThreadMethod() {
00086 {
00087 ScopedMutex lock(mutex_);
00088 while (!ready_to_start_) {
00089 startup_condvar_->Wait();
00090 }
00091 }
00092 while (true) {
00093 ScopedMutex lock(mutex_);
00096 int iter = current_iter_ + 1;
00097 if (iter > iters_) {
00098 return;
00099 }
00100 ++helper_increments_;
00101 current_iter_ = iter;
00102 (condvar_->*signal_method_)();
00103 while (wait_after_signal_ && current_iter_ == iter) {
00104 condvar_->Wait();
00105 }
00106 }
00107 }
00108
00110
00112 void StartupTest() {
00113 StartHelper();
00114 EXPECT_TRUE(ready_to_start_);
00115 FinishHelper();
00116 EXPECT_EQ(helper_increments_, 0);
00117 }
00118
00121 void BlindSignalsTest() {
00122 iters_ = 10;
00123 StartHelper();
00124 EXPECT_TRUE(ready_to_start_);
00125 FinishHelper();
00126 EXPECT_EQ(helper_increments_, 10);
00127 }
00128
00131 void PingPongTest() {
00132 iters_ = 10;
00133 wait_after_signal_ = true;
00134 StartHelper();
00135 int local_increments = 0;
00136 while (true) {
00137 ScopedMutex lock(mutex_);
00138 while ((current_iter_ % 2) == 0 && current_iter_ < iters_) {
00139 condvar_->Wait();
00140 }
00143 if (current_iter_ == iters_) {
00144 break;
00145 }
00146 ++current_iter_;
00147 ++local_increments;
00148 condvar_->Signal();
00149 }
00150 EXPECT_EQ(local_increments, 5);
00151 FinishHelper();
00152 EXPECT_EQ(helper_increments_, 5);
00153 }
00154
00156 void TimeoutTest() {
00157 iters_ = 0;
00158 StartHelper();
00159 {
00160 ScopedMutex lock(mutex_);
00161 condvar_->TimedWait(10);
00162 }
00163 FinishHelper();
00164 }
00165
00167 void LongTimeoutTest(int wait_ms) {
00168 iters_ = 0;
00169 StartHelper();
00170 int64 start_ms = timer()->NowMs();
00171 {
00172 ScopedMutex lock(mutex_);
00173 condvar_->TimedWait(wait_ms);
00174 }
00175 int64 end_ms = timer()->NowMs();
00176
00179 EXPECT_LE(wait_ms, end_ms - start_ms);
00180 FinishHelper();
00181 }
00182
00186 void TimeoutPingPongTest() {
00187 iters_ = 10;
00188 wait_after_signal_ = true;
00189 StartHelper();
00190 int local_increments = 0;
00191 while (true) {
00192 ScopedMutex lock(mutex_);
00193 if ((current_iter_ % 2) == 0) {
00194 condvar_->TimedWait(1);
00195 }
00200 if (current_iter_ > iters_) {
00201 break;
00202 }
00203 ++current_iter_;
00204 ++local_increments;
00205 condvar_->Signal();
00206 }
00207 FinishHelper();
00208 EXPECT_LE(6, local_increments);
00209 EXPECT_GE(5, helper_increments_);
00210 EXPECT_EQ(11, local_increments + helper_increments_);
00211 }
00212
00213 virtual Timer* timer() = 0;
00214
00215 ThreadSystem::CondvarCapableMutex* mutex_;
00216 ThreadSystem::Condvar* startup_condvar_;
00217 ThreadSystem::Condvar* condvar_;
00218 bool ready_to_start_;
00219 int iters_;
00220 int current_iter_;
00221 SignalMethod signal_method_;
00222 bool wait_after_signal_;
00223 int helper_increments_;
00224 bool init_called_;
00225
00226 private:
00227 DISALLOW_COPY_AND_ASSIGN(CondvarTestBase);
00228 };
00229
00230 }
00231
00232 #endif ///< NET_INSTAWEB_UTIL_PUBLIC_CONDVAR_TEST_BASE_H_