1 // Copyright 2011 The Chromium Authors
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 "base/win/object_watcher.h"
6
7 #include <windows.h>
8
9 #include <utility>
10
11 #include "base/memory/raw_ptr.h"
12 #include "base/run_loop.h"
13 #include "base/test/task_environment.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17 namespace win {
18
19 namespace {
20
21 class QuitDelegate : public ObjectWatcher::Delegate {
22 public:
QuitDelegate(base::OnceClosure quit_closure)23 explicit QuitDelegate(base::OnceClosure quit_closure)
24 : quit_closure_(std::move(quit_closure)) {}
25
OnObjectSignaled(HANDLE object)26 void OnObjectSignaled(HANDLE object) override {
27 std::move(quit_closure_).Run();
28 }
29
30 private:
31 base::OnceClosure quit_closure_;
32 };
33
34 class DecrementCountDelegate : public ObjectWatcher::Delegate {
35 public:
DecrementCountDelegate(int * counter)36 explicit DecrementCountDelegate(int* counter) : counter_(counter) {}
OnObjectSignaled(HANDLE object)37 void OnObjectSignaled(HANDLE object) override { --(*counter_); }
38
39 private:
40 raw_ptr<int> counter_;
41 };
42
RunTest_BasicSignal(test::TaskEnvironment::MainThreadType main_thread_type)43 void RunTest_BasicSignal(
44 test::TaskEnvironment::MainThreadType main_thread_type) {
45 test::TaskEnvironment task_environment(main_thread_type);
46
47 ObjectWatcher watcher;
48 EXPECT_FALSE(watcher.IsWatching());
49
50 // A manual-reset event that is not yet signaled.
51 HANDLE event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
52
53 base::RunLoop loop;
54 QuitDelegate delegate(loop.QuitWhenIdleClosure());
55 bool ok = watcher.StartWatchingOnce(event, &delegate);
56 EXPECT_TRUE(ok);
57 EXPECT_TRUE(watcher.IsWatching());
58 EXPECT_EQ(event, watcher.GetWatchedObject());
59
60 SetEvent(event);
61
62 loop.Run();
63
64 EXPECT_FALSE(watcher.IsWatching());
65 CloseHandle(event);
66 }
67
RunTest_BasicCancel(test::TaskEnvironment::MainThreadType main_thread_type)68 void RunTest_BasicCancel(
69 test::TaskEnvironment::MainThreadType main_thread_type) {
70 test::TaskEnvironment task_environment(main_thread_type);
71
72 ObjectWatcher watcher;
73
74 // A manual-reset event that is not yet signaled.
75 HANDLE event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
76
77 base::RunLoop loop;
78 QuitDelegate delegate(loop.QuitWhenIdleClosure());
79 bool ok = watcher.StartWatchingOnce(event, &delegate);
80 EXPECT_TRUE(ok);
81
82 watcher.StopWatching();
83
84 CloseHandle(event);
85 }
86
RunTest_CancelAfterSet(test::TaskEnvironment::MainThreadType main_thread_type)87 void RunTest_CancelAfterSet(
88 test::TaskEnvironment::MainThreadType main_thread_type) {
89 test::TaskEnvironment task_environment(main_thread_type);
90
91 ObjectWatcher watcher;
92
93 int counter = 1;
94 DecrementCountDelegate delegate(&counter);
95 base::RunLoop loop;
96 // A manual-reset event that is not yet signaled.
97 HANDLE event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
98
99 bool ok = watcher.StartWatchingOnce(event, &delegate);
100 EXPECT_TRUE(ok);
101
102 SetEvent(event);
103
104 // Let the background thread do its business
105 Sleep(30);
106
107 watcher.StopWatching();
108
109 loop.RunUntilIdle();
110
111 // Our delegate should not have fired.
112 EXPECT_EQ(1, counter);
113
114 CloseHandle(event);
115 }
116
RunTest_SignalBeforeWatch(test::TaskEnvironment::MainThreadType main_thread_type)117 void RunTest_SignalBeforeWatch(
118 test::TaskEnvironment::MainThreadType main_thread_type) {
119 test::TaskEnvironment task_environment(main_thread_type);
120
121 ObjectWatcher watcher;
122
123 // A manual-reset event that is signaled before we begin watching.
124 HANDLE event = CreateEvent(nullptr, TRUE, TRUE, nullptr);
125
126 base::RunLoop loop;
127 QuitDelegate delegate(loop.QuitWhenIdleClosure());
128 bool ok = watcher.StartWatchingOnce(event, &delegate);
129 EXPECT_TRUE(ok);
130
131 loop.Run();
132
133 EXPECT_FALSE(watcher.IsWatching());
134 CloseHandle(event);
135 }
136
RunTest_OutlivesTaskEnvironment(test::TaskEnvironment::MainThreadType main_thread_type)137 void RunTest_OutlivesTaskEnvironment(
138 test::TaskEnvironment::MainThreadType main_thread_type) {
139 // Simulate a task environment that dies before an ObjectWatcher. This
140 // ordinarily doesn't happen when people use the Thread class, but it can
141 // happen when people use the Singleton pattern or atexit.
142 HANDLE event = CreateEvent(nullptr, TRUE, FALSE, nullptr); // not signaled
143 {
144 ObjectWatcher watcher;
145 {
146 test::TaskEnvironment task_environment(main_thread_type);
147
148 base::RunLoop loop;
149 QuitDelegate delegate(loop.QuitWhenIdleClosure());
150 watcher.StartWatchingOnce(event, &delegate);
151 }
152 }
153 CloseHandle(event);
154 }
155
156 class QuitAfterMultipleDelegate : public ObjectWatcher::Delegate {
157 public:
QuitAfterMultipleDelegate(HANDLE event,int iterations,base::OnceClosure quit_closure)158 QuitAfterMultipleDelegate(HANDLE event,
159 int iterations,
160 base::OnceClosure quit_closure)
161 : event_(event),
162 iterations_(iterations),
163 quit_closure_(std::move(quit_closure)) {}
OnObjectSignaled(HANDLE object)164 void OnObjectSignaled(HANDLE object) override {
165 if (--iterations_) {
166 SetEvent(event_);
167 } else {
168 std::move(quit_closure_).Run();
169 }
170 }
171
172 private:
173 HANDLE event_;
174 int iterations_;
175 base::OnceClosure quit_closure_;
176 };
177
RunTest_ExecuteMultipleTimes(test::TaskEnvironment::MainThreadType main_thread_type)178 void RunTest_ExecuteMultipleTimes(
179 test::TaskEnvironment::MainThreadType main_thread_type) {
180 test::TaskEnvironment task_environment(main_thread_type);
181
182 ObjectWatcher watcher;
183 EXPECT_FALSE(watcher.IsWatching());
184
185 // An auto-reset event that is not yet signaled.
186 HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
187
188 base::RunLoop loop;
189 QuitAfterMultipleDelegate delegate(event, 2, loop.QuitWhenIdleClosure());
190 bool ok = watcher.StartWatchingMultipleTimes(event, &delegate);
191 EXPECT_TRUE(ok);
192 EXPECT_TRUE(watcher.IsWatching());
193 EXPECT_EQ(event, watcher.GetWatchedObject());
194
195 SetEvent(event);
196
197 loop.Run();
198
199 EXPECT_TRUE(watcher.IsWatching());
200 EXPECT_TRUE(watcher.StopWatching());
201 CloseHandle(event);
202 }
203
204 } // namespace
205
206 //-----------------------------------------------------------------------------
207
TEST(ObjectWatcherTest,BasicSignal)208 TEST(ObjectWatcherTest, BasicSignal) {
209 RunTest_BasicSignal(test::TaskEnvironment::MainThreadType::DEFAULT);
210 RunTest_BasicSignal(test::TaskEnvironment::MainThreadType::IO);
211 RunTest_BasicSignal(test::TaskEnvironment::MainThreadType::UI);
212 }
213
TEST(ObjectWatcherTest,BasicCancel)214 TEST(ObjectWatcherTest, BasicCancel) {
215 RunTest_BasicCancel(test::TaskEnvironment::MainThreadType::DEFAULT);
216 RunTest_BasicCancel(test::TaskEnvironment::MainThreadType::IO);
217 RunTest_BasicCancel(test::TaskEnvironment::MainThreadType::UI);
218 }
219
TEST(ObjectWatcherTest,CancelAfterSet)220 TEST(ObjectWatcherTest, CancelAfterSet) {
221 RunTest_CancelAfterSet(test::TaskEnvironment::MainThreadType::DEFAULT);
222 RunTest_CancelAfterSet(test::TaskEnvironment::MainThreadType::IO);
223 RunTest_CancelAfterSet(test::TaskEnvironment::MainThreadType::UI);
224 }
225
TEST(ObjectWatcherTest,SignalBeforeWatch)226 TEST(ObjectWatcherTest, SignalBeforeWatch) {
227 RunTest_SignalBeforeWatch(test::TaskEnvironment::MainThreadType::DEFAULT);
228 RunTest_SignalBeforeWatch(test::TaskEnvironment::MainThreadType::IO);
229 RunTest_SignalBeforeWatch(test::TaskEnvironment::MainThreadType::UI);
230 }
231
TEST(ObjectWatcherTest,OutlivesTaskEnvironment)232 TEST(ObjectWatcherTest, OutlivesTaskEnvironment) {
233 RunTest_OutlivesTaskEnvironment(
234 test::TaskEnvironment::MainThreadType::DEFAULT);
235 RunTest_OutlivesTaskEnvironment(test::TaskEnvironment::MainThreadType::IO);
236 RunTest_OutlivesTaskEnvironment(test::TaskEnvironment::MainThreadType::UI);
237 }
238
TEST(ObjectWatcherTest,ExecuteMultipleTimes)239 TEST(ObjectWatcherTest, ExecuteMultipleTimes) {
240 RunTest_ExecuteMultipleTimes(test::TaskEnvironment::MainThreadType::DEFAULT);
241 RunTest_ExecuteMultipleTimes(test::TaskEnvironment::MainThreadType::IO);
242 RunTest_ExecuteMultipleTimes(test::TaskEnvironment::MainThreadType::UI);
243 }
244
245 } // namespace win
246 } // namespace base
247