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