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
13namespace net {
14
15namespace {
16
17class 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
137TEST_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