Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sync / internal_api / public / base / cancelation_signal_unittest.cc
blob244c9258331c0ae6a2a485fa6ad9c5f3597389cb
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.
5 #include "sync/internal_api/public/base/cancelation_signal.h"
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"
16 namespace syncer {
18 class BlockingTask : public CancelationObserver {
19 public:
20 BlockingTask(CancelationSignal* cancel_signal);
21 ~BlockingTask() override;
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);
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);
34 // Implementation of CancelationObserver.
35 // Wakes up the thread blocked in Run().
36 void OnSignalReceived() override;
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();
43 private:
44 base::WaitableEvent event_;
45 base::Thread exec_thread_;
46 CancelationSignal* cancel_signal_;
47 bool was_started_;
50 BlockingTask::BlockingTask(CancelationSignal* cancel_signal)
51 : event_(true, false),
52 exec_thread_("BlockingTaskBackgroundThread"),
53 cancel_signal_(cancel_signal),
54 was_started_(false) { }
56 BlockingTask::~BlockingTask() {
57 if (was_started_) {
58 cancel_signal_->UnregisterHandler(this);
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)));
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();
82 task_done_signal->Signal();
85 void BlockingTask::OnSignalReceived() {
86 event_.Signal();
89 bool BlockingTask::WasStarted() {
90 return was_started_;
93 class CancelationSignalTest : public ::testing::Test {
94 public:
95 CancelationSignalTest();
96 ~CancelationSignalTest() override;
98 // Starts the blocking task on a background thread. Does not wait for the
99 // task to start.
100 void StartBlockingTaskAsync();
102 // Starts the blocking task on a background thread. Does not return until
103 // the task has been started.
104 void StartBlockingTaskAndWaitForItToStart();
106 // Cancels the blocking task.
107 void CancelBlocking();
109 // Verifies that the background task was canceled early.
111 // This method may block for a brief period of time while waiting for the
112 // background thread to make progress.
113 bool VerifyTaskNotStarted();
115 private:
116 base::MessageLoop main_loop_;
118 CancelationSignal signal_;
119 base::WaitableEvent task_start_event_;
120 base::WaitableEvent task_done_event_;
121 BlockingTask blocking_task_;
124 CancelationSignalTest::CancelationSignalTest()
125 : task_start_event_(false, false),
126 task_done_event_(false, false),
127 blocking_task_(&signal_) {}
129 CancelationSignalTest::~CancelationSignalTest() {}
131 void CancelationSignalTest::StartBlockingTaskAsync() {
132 blocking_task_.RunAsync(&task_start_event_, &task_done_event_);
135 void CancelationSignalTest::StartBlockingTaskAndWaitForItToStart() {
136 blocking_task_.RunAsync(&task_start_event_, &task_done_event_);
137 task_start_event_.Wait();
140 void CancelationSignalTest::CancelBlocking() {
141 signal_.Signal();
144 bool CancelationSignalTest::VerifyTaskNotStarted() {
145 // Wait until BlockingTask::Run() has finished.
146 task_done_event_.Wait();
148 // Verify the background thread never started blocking.
149 return !blocking_task_.WasStarted();
152 class FakeCancelationObserver : public CancelationObserver {
153 void OnSignalReceived() override {}
156 TEST(CancelationSignalTest_SingleThread, CheckFlags) {
157 FakeCancelationObserver observer;
158 CancelationSignal signal;
160 EXPECT_FALSE(signal.IsSignalled());
161 signal.Signal();
162 EXPECT_TRUE(signal.IsSignalled());
163 EXPECT_FALSE(signal.TryRegisterHandler(&observer));
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());
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();
181 // Wait for the task to finish and let verify it has been started.
182 CancelBlocking();
183 EXPECT_FALSE(VerifyTaskNotStarted());
186 } // namespace syncer