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