63e4cb6a8676b5aa047a69324afcf016f59dcd51
[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/platform_thread.h"
11 #include "base/threading/thread.h"
12 #include "base/time/time.h"
13 #include "sync/internal_api/public/base/cancelation_observer.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace syncer {
17
18 class BlockingTask : public CancelationObserver {
19  public:
20   BlockingTask(CancelationSignal* cancel_signal);
21   virtual ~BlockingTask();
22
23   // Starts the |exec_thread_| and uses it to execute DoRun().
24   void RunAsync(base::WaitableEvent* task_start_signal,
25                 base::WaitableEvent* task_done_signal);
26
27   // Blocks until canceled.  Signals |task_done_signal| when finished (either
28   // via early cancel or cancel after start).  Signals |task_start_signal| if
29   // and when the task starts successfully (which will not happen if the task
30   // was cancelled early).
31   void Run(base::WaitableEvent* task_start_signal,
32            base::WaitableEvent* task_done_signal);
33
34   // Implementation of CancelationObserver.
35   // Wakes up the thread blocked in Run().
36   virtual void OnSignalReceived() OVERRIDE;
37
38   // Checks if we ever did successfully start waiting for |event_|.  Be careful
39   // with this.  The flag itself is thread-unsafe, and the event that flips it
40   // is racy.
41   bool WasStarted();
42
43  private:
44   base::WaitableEvent event_;
45   base::Thread exec_thread_;
46   CancelationSignal* cancel_signal_;
47   bool was_started_;
48 };
49
50 BlockingTask::BlockingTask(CancelationSignal* cancel_signal)
51   : event_(true, false),
52     exec_thread_("BlockingTaskBackgroundThread"),
53     cancel_signal_(cancel_signal),
54     was_started_(false) { }
55
56 BlockingTask::~BlockingTask() {
57   if (was_started_) {
58     cancel_signal_->UnregisterHandler(this);
59   }
60 }
61
62 void BlockingTask::RunAsync(base::WaitableEvent* task_start_signal,
63                             base::WaitableEvent* task_done_signal) {
64   exec_thread_.Start();
65   exec_thread_.message_loop()->PostTask(
66       FROM_HERE,
67       base::Bind(&BlockingTask::Run,
68                  base::Unretained(this),
69                  base::Unretained(task_start_signal),
70                  base::Unretained(task_done_signal)));
71 }
72
73 void BlockingTask::Run(
74     base::WaitableEvent* task_start_signal,
75     base::WaitableEvent* task_done_signal) {
76   if (cancel_signal_->TryRegisterHandler(this)) {
77     DCHECK(!event_.IsSignaled());
78     was_started_ = true;
79     task_start_signal->Signal();
80     event_.Wait();
81   }
82   task_done_signal->Signal();
83 }
84
85 void BlockingTask::OnSignalReceived() {
86   event_.Signal();
87 }
88
89 bool BlockingTask::WasStarted() {
90   return was_started_;
91 }
92
93 class CancelationSignalTest : public ::testing::Test {
94  public:
95   CancelationSignalTest();
96   virtual ~CancelationSignalTest();
97
98   // Starts the blocking task on a background thread.  Does not wait for the
99   // task to start.
100   void StartBlockingTaskAsync();
101
102   // Starts the blocking task on a background thread.  Does not return until
103   // the task has been started.
104   void StartBlockingTaskAndWaitForItToStart();
105
106   // Cancels the blocking task.
107   void CancelBlocking();
108
109   // Verifies that the background task was canceled early.
110   //
111   // This method may block for a brief period of time while waiting for the
112   // background thread to make progress.
113   bool VerifyTaskNotStarted();
114
115  private:
116   base::MessageLoop main_loop_;
117
118   CancelationSignal signal_;
119   base::WaitableEvent task_start_event_;
120   base::WaitableEvent task_done_event_;
121   BlockingTask blocking_task_;
122 };
123
124 CancelationSignalTest::CancelationSignalTest()
125   : task_start_event_(false, false),
126     task_done_event_(false, false),
127     blocking_task_(&signal_) {}
128
129 CancelationSignalTest::~CancelationSignalTest() {}
130
131 void CancelationSignalTest::StartBlockingTaskAsync() {
132   blocking_task_.RunAsync(&task_start_event_, &task_done_event_);
133 }
134
135 void CancelationSignalTest::StartBlockingTaskAndWaitForItToStart() {
136   blocking_task_.RunAsync(&task_start_event_, &task_done_event_);
137   task_start_event_.Wait();
138 }
139
140 void CancelationSignalTest::CancelBlocking() {
141   signal_.Signal();
142 }
143
144 bool CancelationSignalTest::VerifyTaskNotStarted() {
145   // Wait until BlockingTask::Run() has finished.
146   task_done_event_.Wait();
147
148   // Verify the background thread never started blocking.
149   return !blocking_task_.WasStarted();
150 }
151
152 class FakeCancelationObserver : public CancelationObserver {
153   virtual void OnSignalReceived() OVERRIDE { }
154 };
155
156 TEST(CancelationSignalTest_SingleThread, CheckFlags) {
157   FakeCancelationObserver observer;
158   CancelationSignal signal;
159
160   EXPECT_FALSE(signal.IsSignalled());
161   signal.Signal();
162   EXPECT_TRUE(signal.IsSignalled());
163   EXPECT_FALSE(signal.TryRegisterHandler(&observer));
164 }
165
166 // Send the cancelation signal before the task is started.  This will ensure
167 // that the task will never be "started" (ie. TryRegisterHandler() will fail,
168 // so it will never start blocking on its main WaitableEvent).
169 TEST_F(CancelationSignalTest, CancelEarly) {
170   CancelBlocking();
171   StartBlockingTaskAsync();
172   EXPECT_TRUE(VerifyTaskNotStarted());
173 }
174
175 // Send the cancelation signal after the task has started running.  This tests
176 // the non-early exit code path, where the task is stopped while it is in
177 // progress.
178 TEST_F(CancelationSignalTest, Cancel) {
179   StartBlockingTaskAndWaitForItToStart();
180
181   // Wait for the task to finish and let verify it has been started.
182   CancelBlocking();
183   EXPECT_FALSE(VerifyTaskNotStarted());
184 }
185
186 }  // namespace syncer