613e7560ede3769c2ee6182ba1649796da2e3255
[platform/framework/web/crosswalk.git] / src / sync / internal_api / public / base / cancelation_signal_unittest.cc
1 // Copyright 2013 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 "sync/internal_api/public/base/cancelation_signal.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/thread.h"
11 #include "sync/internal_api/public/base/cancelation_observer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace syncer {
15
16 class BlockingTask : public CancelationObserver {
17  public:
18   BlockingTask(CancelationSignal* cancel_signal);
19   virtual ~BlockingTask();
20
21   // Starts the |exec_thread_| and uses it to execute DoRun().
22   void RunAsync(base::WaitableEvent* task_done_signal);
23
24   // Blocks until canceled.  Signals |task_done_signal| when finished.
25   void Run(base::WaitableEvent* task_done_signal);
26
27   // Implementation of CancelationObserver.
28   // Wakes up the thread blocked in Run().
29   virtual void OnSignalReceived() OVERRIDE;
30
31   // Checks if we ever did successfully start waiting for |event_|.  Be careful
32   // with this.  The flag itself is thread-unsafe, and the event that flips it
33   // is racy.
34   bool WasStarted();
35
36  private:
37   base::WaitableEvent event_;
38   base::Thread exec_thread_;
39   CancelationSignal* cancel_signal_;
40   bool was_started_;
41 };
42
43 BlockingTask::BlockingTask(CancelationSignal* cancel_signal)
44   : event_(true, false),
45     exec_thread_("BlockingTaskBackgroundThread"),
46     cancel_signal_(cancel_signal),
47     was_started_(false) { }
48
49 BlockingTask::~BlockingTask() {}
50
51 void BlockingTask::RunAsync(base::WaitableEvent* task_done_signal) {
52   exec_thread_.Start();
53   exec_thread_.message_loop()->PostTask(
54       FROM_HERE,
55       base::Bind(&BlockingTask::Run,
56                  base::Unretained(this),
57                  base::Unretained(task_done_signal)));
58 }
59
60 void BlockingTask::Run(base::WaitableEvent* task_done_signal) {
61   if (cancel_signal_->TryRegisterHandler(this)) {
62     DCHECK(!event_.IsSignaled());
63     was_started_ = true;
64     event_.Wait();
65   }
66   task_done_signal->Signal();
67 }
68
69 void BlockingTask::OnSignalReceived() {
70   event_.Signal();
71 }
72
73 bool BlockingTask::WasStarted() {
74   return was_started_;
75 }
76
77 class CancelationSignalTest : public ::testing::Test {
78  public:
79   CancelationSignalTest();
80   virtual ~CancelationSignalTest();
81
82   // Starts the blocking task on a background thread.
83   void StartBlockingTask();
84
85   // Cancels the blocking task.
86   void CancelBlocking();
87
88   // Verifies that the background task is not running.  This could be beacause
89   // it was canceled early or because it was canceled after it was started.
90   //
91   // This method may block for a brief period of time while waiting for the
92   // background thread to make progress.
93   bool VerifyTaskDone();
94
95   // Verifies that the background task was canceled early.
96   //
97   // This method may block for a brief period of time while waiting for the
98   // background thread to make progress.
99   bool VerifyTaskNotStarted();
100
101  private:
102   base::MessageLoop main_loop_;
103
104   CancelationSignal signal_;
105   base::WaitableEvent task_done_event_;
106   BlockingTask blocking_task_;
107 };
108
109 CancelationSignalTest::CancelationSignalTest()
110   : task_done_event_(false, false), blocking_task_(&signal_) {}
111
112 CancelationSignalTest::~CancelationSignalTest() {}
113
114 void CancelationSignalTest::StartBlockingTask() {
115   blocking_task_.RunAsync(&task_done_event_);
116 }
117
118 void CancelationSignalTest::CancelBlocking() {
119   signal_.Signal();
120 }
121
122 bool CancelationSignalTest::VerifyTaskDone() {
123   // Wait until BlockingTask::Run() has finished.
124   task_done_event_.Wait();
125   return true;
126 }
127
128 bool CancelationSignalTest::VerifyTaskNotStarted() {
129   // Wait until BlockingTask::Run() has finished.
130   task_done_event_.Wait();
131
132   // Verify the background thread never started blocking.
133   return !blocking_task_.WasStarted();
134 }
135
136 class FakeCancelationObserver : public CancelationObserver {
137   virtual void OnSignalReceived() OVERRIDE { }
138 };
139
140 TEST(CancelationSignalTest_SingleThread, CheckFlags) {
141   FakeCancelationObserver observer;
142   CancelationSignal signal;
143
144   EXPECT_FALSE(signal.IsSignalled());
145   signal.Signal();
146   EXPECT_TRUE(signal.IsSignalled());
147   EXPECT_FALSE(signal.TryRegisterHandler(&observer));
148 }
149
150 // Send the cancelation signal before the task is started.  This will ensure
151 // that the task will never be attempted.
152 TEST_F(CancelationSignalTest, CancelEarly) {
153   CancelBlocking();
154   StartBlockingTask();
155   EXPECT_TRUE(VerifyTaskNotStarted());
156 }
157
158 // Send the cancelation signal after the request to start the task has been
159 // posted.  This is racy.  The signal to stop may arrive before the signal to
160 // run the task.  If that happens, we end up with another instance of the
161 // CancelEarly test defined earlier.  If the signal requesting a stop arrives
162 // after the task has been started, it should end up stopping the task.
163 TEST_F(CancelationSignalTest, Cancel) {
164   StartBlockingTask();
165   CancelBlocking();
166   EXPECT_TRUE(VerifyTaskDone());
167 }
168
169 }  // namespace syncer