Home | History | Annotate | Download | only in dns
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/dns/serial_worker.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/synchronization/lock.h"
     10 #include "base/synchronization/waitable_event.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 class SerialWorkerTest : public testing::Test {
     18  public:
     19   // The class under test
     20   class TestSerialWorker : public SerialWorker {
     21    public:
     22     explicit TestSerialWorker(SerialWorkerTest* t)
     23       : test_(t) {}
     24     virtual void DoWork() OVERRIDE {
     25       ASSERT_TRUE(test_);
     26       test_->OnWork();
     27     }
     28     virtual void OnWorkFinished() OVERRIDE {
     29       ASSERT_TRUE(test_);
     30       test_->OnWorkFinished();
     31     }
     32    private:
     33     virtual ~TestSerialWorker() {}
     34     SerialWorkerTest* test_;
     35   };
     36 
     37   // Mocks
     38 
     39   void OnWork() {
     40     { // Check that OnWork is executed serially.
     41       base::AutoLock lock(work_lock_);
     42       EXPECT_FALSE(work_running_) << "DoRead is not called serially!";
     43       work_running_ = true;
     44     }
     45     BreakNow("OnWork");
     46     work_allowed_.Wait();
     47     // Calling from WorkerPool, but protected by work_allowed_/work_called_.
     48     output_value_ = input_value_;
     49 
     50     { // This lock might be destroyed after work_called_ is signalled.
     51       base::AutoLock lock(work_lock_);
     52       work_running_ = false;
     53     }
     54     work_called_.Signal();
     55   }
     56 
     57   void OnWorkFinished() {
     58     EXPECT_TRUE(message_loop_ == base::MessageLoop::current());
     59     EXPECT_EQ(output_value_, input_value_);
     60     BreakNow("OnWorkFinished");
     61   }
     62 
     63  protected:
     64   void BreakCallback(std::string breakpoint) {
     65     breakpoint_ = breakpoint;
     66     base::MessageLoop::current()->QuitNow();
     67   }
     68 
     69   void BreakNow(std::string b) {
     70     message_loop_->PostTask(FROM_HERE,
     71         base::Bind(&SerialWorkerTest::BreakCallback,
     72                    base::Unretained(this), b));
     73   }
     74 
     75   void RunUntilBreak(std::string b) {
     76     message_loop_->Run();
     77     ASSERT_EQ(breakpoint_, b);
     78   }
     79 
     80   SerialWorkerTest()
     81       : input_value_(0),
     82         output_value_(-1),
     83         work_allowed_(false, false),
     84         work_called_(false, false),
     85         work_running_(false) {
     86   }
     87 
     88   // Helpers for tests.
     89 
     90   // Lets OnWork run and waits for it to complete. Can only return if OnWork is
     91   // executed on a concurrent thread.
     92   void WaitForWork() {
     93     RunUntilBreak("OnWork");
     94     work_allowed_.Signal();
     95     work_called_.Wait();
     96   }
     97 
     98   // test::Test methods
     99   virtual void SetUp() OVERRIDE {
    100     message_loop_ = base::MessageLoop::current();
    101     worker_ = new TestSerialWorker(this);
    102   }
    103 
    104   virtual void TearDown() OVERRIDE {
    105     // Cancel the worker to catch if it makes a late DoWork call.
    106     worker_->Cancel();
    107     // Check if OnWork is stalled.
    108     EXPECT_FALSE(work_running_) << "OnWork should be done by TearDown";
    109     // Release it for cleanliness.
    110     if (work_running_) {
    111       WaitForWork();
    112     }
    113   }
    114 
    115   // Input value read on WorkerPool.
    116   int input_value_;
    117   // Output value written on WorkerPool.
    118   int output_value_;
    119 
    120   // read is called on WorkerPool so we need to synchronize with it.
    121   base::WaitableEvent work_allowed_;
    122   base::WaitableEvent work_called_;
    123 
    124   // Protected by read_lock_. Used to verify that read calls are serialized.
    125   bool work_running_;
    126   base::Lock work_lock_;
    127 
    128   // Loop for this thread.
    129   base::MessageLoop* message_loop_;
    130 
    131   // WatcherDelegate under test.
    132   scoped_refptr<TestSerialWorker> worker_;
    133 
    134   std::string breakpoint_;
    135 };
    136 
    137 TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) {
    138   for (int i = 0; i < 3; ++i) {
    139     ++input_value_;
    140     worker_->WorkNow();
    141     WaitForWork();
    142     RunUntilBreak("OnWorkFinished");
    143 
    144     EXPECT_TRUE(message_loop_->IsIdleForTesting());
    145   }
    146 
    147   // Schedule two calls. OnWork checks if it is called serially.
    148   ++input_value_;
    149   worker_->WorkNow();
    150   // read is blocked, so this will have to induce re-work
    151   worker_->WorkNow();
    152   WaitForWork();
    153   WaitForWork();
    154   RunUntilBreak("OnWorkFinished");
    155 
    156   // No more tasks should remain.
    157   EXPECT_TRUE(message_loop_->IsIdleForTesting());
    158 }
    159 
    160 }  // namespace
    161 
    162 }  // namespace net
    163 
    164