Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: sync/internal_api/public/base/cancelation_signal_unittest.cc

Issue 23189021: sync: Gracefully handle very early shutdown (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix sync_client.cc compile Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 OnStopRequested() 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 event_.Wait();
64 }
65 task_done_signal->Signal();
66 }
67
68 void BlockingTask::OnStopRequested() {
69 event_.Signal();
70 }
71
72 bool BlockingTask::WasStarted() {
73 return was_started_;
74 }
75
76 class CancelationSignalTest : public ::testing::Test {
77 public:
78 CancelationSignalTest();
79 virtual ~CancelationSignalTest();
80
81 // Starts the blocking task on a background thread.
82 void StartBlockingTask();
83
84 // Cancels the blocking task.
85 void RequestStop();
86
87 // Verifies that the background task is not running. This could be beacause
88 // it was canceled early or because it was canceled after it was started.
89 //
90 // This method may block for a brief period of time while waiting for the
91 // background thread to make progress.
92 bool VerifyTaskDone();
93
94 // Verifies that the background task was canceled early.
95 //
96 // This method may block for a brief period of time while waiting for the
97 // background thread to make progress.
98 bool VerifyTaskNotStarted();
99
100 private:
101 base::MessageLoop main_loop_;
102
103 CancelationSignal signal_;
104 base::WaitableEvent task_done_event_;
105 BlockingTask blocking_task_;
tim (not reviewing) 2013/09/09 18:46:34 I don't see anything ever call event_.Reset yet it
106 };
107
108 CancelationSignalTest::CancelationSignalTest()
109 : task_done_event_(false, false), blocking_task_(&signal_) {}
110
111 CancelationSignalTest::~CancelationSignalTest() {}
112
113 void CancelationSignalTest::StartBlockingTask() {
114 blocking_task_.RunAsync(&task_done_event_);
115 }
116
117 void CancelationSignalTest::RequestStop() {
118 signal_.RequestStop();
119 }
120
121 bool CancelationSignalTest::VerifyTaskDone() {
122 // Wait until BlockingTask::Run() has finished.
123 task_done_event_.Wait();
124 return true;
125 }
126
127 bool CancelationSignalTest::VerifyTaskNotStarted() {
128 // Wait until BlockingTask::Run() has finished.
129 task_done_event_.Wait();
130
131 // Verify the background thread never started blocking.
132 return !blocking_task_.WasStarted();
133 }
134
135 class FakeCancelationObserver : public CancelationObserver {
136 virtual void OnStopRequested() OVERRIDE { }
137 };
138
139 TEST(CancelationSignalTest_SingleThread, CheckFlags) {
140 FakeCancelationObserver observer;
141 CancelationSignal signal;
142
143 EXPECT_FALSE(signal.IsStopRequested());
144 signal.RequestStop();
145 EXPECT_TRUE(signal.IsStopRequested());
146 EXPECT_FALSE(signal.TryRegisterHandler(&observer));
147 }
148
149 // Send the cancelation signal before the task is started. This will ensure
150 // that the task will never be attempted.
151 TEST_F(CancelationSignalTest, CancelEarly) {
152 RequestStop();
153 StartBlockingTask();
154 EXPECT_TRUE(VerifyTaskNotStarted());
155 }
156
157 // Send the cancelation signal after the request to start the task has been
158 // posted. This is racy. The signal to stop may arrive before the signal to
159 // run the task. If that happens, we end up with another instance of the
160 // CancelEarly test defined earlier. If the signal requesting a stop arrives
161 // after the task has been started, it should end up stopping the task.
162 TEST_F(CancelationSignalTest, Cancel) {
163 StartBlockingTask();
164 RequestStop();
165 EXPECT_TRUE(VerifyTaskDone());
166 }
167
168 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/internal_api/public/base/cancelation_signal.cc ('k') | sync/internal_api/public/internal_components_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698