• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestSerialWorker(SerialWorkerTest * t)22     explicit TestSerialWorker(SerialWorkerTest* t)
23       : test_(t) {}
DoWork()24     virtual void DoWork() OVERRIDE {
25       ASSERT_TRUE(test_);
26       test_->OnWork();
27     }
OnWorkFinished()28     virtual void OnWorkFinished() OVERRIDE {
29       ASSERT_TRUE(test_);
30       test_->OnWorkFinished();
31     }
32    private:
~TestSerialWorker()33     virtual ~TestSerialWorker() {}
34     SerialWorkerTest* test_;
35   };
36 
37   // Mocks
38 
OnWork()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 
OnWorkFinished()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:
BreakCallback(std::string breakpoint)64   void BreakCallback(std::string breakpoint) {
65     breakpoint_ = breakpoint;
66     base::MessageLoop::current()->QuitNow();
67   }
68 
BreakNow(std::string b)69   void BreakNow(std::string b) {
70     message_loop_->PostTask(FROM_HERE,
71         base::Bind(&SerialWorkerTest::BreakCallback,
72                    base::Unretained(this), b));
73   }
74 
RunUntilBreak(std::string b)75   void RunUntilBreak(std::string b) {
76     message_loop_->Run();
77     ASSERT_EQ(breakpoint_, b);
78   }
79 
SerialWorkerTest()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.
WaitForWork()92   void WaitForWork() {
93     RunUntilBreak("OnWork");
94     work_allowed_.Signal();
95     work_called_.Wait();
96   }
97 
98   // test::Test methods
SetUp()99   virtual void SetUp() OVERRIDE {
100     message_loop_ = base::MessageLoop::current();
101     worker_ = new TestSerialWorker(this);
102   }
103 
TearDown()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 
TEST_F(SerialWorkerTest,ExecuteAndSerializeReads)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