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

Side by Side Diff: components/browser_watcher/window_hang_monitor_win_unittest.cc

Issue 1543803005: Added an integration test for kasko hang reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing Created 4 years, 11 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/browser_watcher/window_hang_monitor_win.h" 5 #include "components/browser_watcher/window_hang_monitor_win.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <vector> 9 #include <vector>
10 10
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 HangMonitorThread() 50 HangMonitorThread()
51 : event_(WindowHangMonitor::WINDOW_NOT_FOUND), 51 : event_(WindowHangMonitor::WINDOW_NOT_FOUND),
52 event_received_(false, false), 52 event_received_(false, false),
53 thread_("HangMonitorThread") {} 53 thread_("HangMonitorThread") {}
54 54
55 ~HangMonitorThread() { 55 ~HangMonitorThread() {
56 if (hang_monitor_.get()) 56 if (hang_monitor_.get())
57 DestroyWatcher(); 57 DestroyWatcher();
58 } 58 }
59 59
60 // Starts the background thread and the monitor to observe the window named 60 // Starts the background thread and the monitor to observe Chrome message
61 // |window_name| in |process|. Blocks until the monitor has been initialized. 61 // window for |process|. Blocks until the monitor has been initialized.
62 bool Start(base::Process process, const base::string16& window_name) { 62 bool Start(base::Process process) {
63 if (!thread_.StartWithOptions( 63 if (!thread_.StartWithOptions(
64 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))) { 64 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))) {
65 return false; 65 return false;
66 } 66 }
67 67
68 base::WaitableEvent complete(false, false); 68 base::WaitableEvent complete(false, false);
69 if (!thread_.task_runner()->PostTask( 69 if (!thread_.task_runner()->PostTask(
70 FROM_HERE, base::Bind(&HangMonitorThread::StartupOnThread, 70 FROM_HERE,
71 base::Unretained(this), window_name, 71 base::Bind(&HangMonitorThread::StartupOnThread,
72 base::Passed(process.Pass()), 72 base::Unretained(this), base::Passed(std::move(process)),
73 base::Unretained(&complete)))) { 73 base::Unretained(&complete)))) {
74 return false; 74 return false;
75 } 75 }
76 76
77 complete.Wait(); 77 complete.Wait();
78 78
79 return true; 79 return true;
80 } 80 }
81 81
82 // Returns true if a window event is detected within |timeout|. 82 // Returns true if a window event is detected within |timeout|.
83 bool TimedWaitForEvent(base::TimeDelta timeout) { 83 bool TimedWaitForEvent(base::TimeDelta timeout) {
(...skipping 19 matching lines...) Expand all
103 private: 103 private:
104 // Invoked when the monitor signals an event. Unblocks a call to 104 // Invoked when the monitor signals an event. Unblocks a call to
105 // TimedWaitForEvent or WaitForEvent. 105 // TimedWaitForEvent or WaitForEvent.
106 void EventCallback(WindowHangMonitor::WindowEvent event) { 106 void EventCallback(WindowHangMonitor::WindowEvent event) {
107 if (event_received_.IsSignaled()) 107 if (event_received_.IsSignaled())
108 ADD_FAILURE() << "Multiple calls to EventCallback."; 108 ADD_FAILURE() << "Multiple calls to EventCallback.";
109 event_ = event; 109 event_ = event;
110 event_received_.Signal(); 110 event_received_.Signal();
111 } 111 }
112 112
113 // Initializes the WindowHangMonitor to observe the window named |window_name| 113 // Initializes the WindowHangMonitor to observe the Chrome message window for
114 // in |process|. Signals |complete| when done. 114 // |process|. Signals |complete| when done.
115 void StartupOnThread(const base::string16& window_name, 115 void StartupOnThread(base::Process process, base::WaitableEvent* complete) {
116 base::Process process,
117 base::WaitableEvent* complete) {
118 hang_monitor_.reset(new WindowHangMonitor( 116 hang_monitor_.reset(new WindowHangMonitor(
119 base::TimeDelta::FromMilliseconds(100), 117 base::TimeDelta::FromMilliseconds(100),
120 base::TimeDelta::FromMilliseconds(100), 118 base::TimeDelta::FromMilliseconds(100),
121 base::Bind(&HangMonitorThread::EventCallback, base::Unretained(this)))); 119 base::Bind(&HangMonitorThread::EventCallback, base::Unretained(this))));
122 hang_monitor_->Initialize(process.Pass(), window_name); 120 hang_monitor_->Initialize(std::move(process));
123 complete->Signal(); 121 complete->Signal();
124 } 122 }
125 123
126 // Destroys the WindowHangMonitor. 124 // Destroys the WindowHangMonitor.
127 void ShutdownOnThread() { hang_monitor_.reset(); } 125 void ShutdownOnThread() { hang_monitor_.reset(); }
128 126
129 // The detected event. Invalid if |event_received_| has not been signaled. 127 // The detected event. Invalid if |event_received_| has not been signaled.
130 WindowHangMonitor::WindowEvent event_; 128 WindowHangMonitor::WindowEvent event_;
131 // Indicates that |event_| has been assigned in response to a callback from 129 // Indicates that |event_| has been assigned in response to a callback from
132 // the WindowHangMonitor. 130 // the WindowHangMonitor.
133 base::WaitableEvent event_received_; 131 base::WaitableEvent event_received_;
134 // The WindowHangMonitor under test. 132 // The WindowHangMonitor under test.
135 scoped_ptr<WindowHangMonitor> hang_monitor_; 133 scoped_ptr<WindowHangMonitor> hang_monitor_;
136 // The background thread. 134 // The background thread.
137 base::Thread thread_; 135 base::Thread thread_;
138 136
139 DISALLOW_COPY_AND_ASSIGN(HangMonitorThread); 137 DISALLOW_COPY_AND_ASSIGN(HangMonitorThread);
140 }; 138 };
141 139
142 class WindowHangMonitorTest : public testing::Test { 140 class WindowHangMonitorTest : public testing::Test {
143 public: 141 public:
144 WindowHangMonitorTest() 142 WindowHangMonitorTest()
145 : ping_event_(false, false), 143 : ping_event_(false, false),
146 pings_(0), 144 pings_(0),
147 window_thread_("WindowHangMonitorTest window_thread") {} 145 window_thread_("WindowHangMonitorTest window_thread") {}
148 146
149 void SetUp() override { 147 void SetUp() override {
150 // Pick a window name unique to this process.
151 window_name_ = base::StringPrintf(L"WindowHanMonitorTest-%d",
152 base::GetCurrentProcId());
153 ASSERT_TRUE(window_thread_.StartWithOptions( 148 ASSERT_TRUE(window_thread_.StartWithOptions(
154 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))); 149 base::Thread::Options(base::MessageLoop::TYPE_UI, 0)));
155 } 150 }
156 151
157 void TearDown() override { 152 void TearDown() override {
158 DeleteMessageWindow(); 153 DeleteMessageWindow();
159 window_thread_.Stop(); 154 window_thread_.Stop();
160 } 155 }
161 156
162 void CreateMessageWindow() { 157 void CreateMessageWindow() {
163 bool succeeded = false; 158 bool succeeded = false;
164 base::WaitableEvent created(true, false); 159 base::WaitableEvent created(true, false);
165 ASSERT_TRUE(window_thread_.task_runner()->PostTask( 160 ASSERT_TRUE(window_thread_.task_runner()->PostTask(
166 FROM_HERE, 161 FROM_HERE,
167 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread, 162 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread,
168 base::Unretained(this), window_name_, &succeeded, 163 base::Unretained(this), &succeeded, &created)));
169 &created)));
170 created.Wait(); 164 created.Wait();
171 ASSERT_TRUE(succeeded); 165 ASSERT_TRUE(succeeded);
172 } 166 }
173 167
174 void DeleteMessageWindow() { 168 void DeleteMessageWindow() {
175 base::WaitableEvent deleted(true, false); 169 base::WaitableEvent deleted(true, false);
176 window_thread_.task_runner()->PostTask( 170 window_thread_.task_runner()->PostTask(
177 FROM_HERE, 171 FROM_HERE,
178 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread, 172 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread,
179 base::Unretained(this), &deleted)); 173 base::Unretained(this), &deleted));
(...skipping 13 matching lines...) Expand all
193 ping_event_.Wait(); 187 ping_event_.Wait();
194 } 188 }
195 } 189 }
196 190
197 HangMonitorThread& monitor_thread() { return monitor_thread_; } 191 HangMonitorThread& monitor_thread() { return monitor_thread_; }
198 192
199 const base::win::MessageWindow* message_window() const { 193 const base::win::MessageWindow* message_window() const {
200 return message_window_.get(); 194 return message_window_.get();
201 } 195 }
202 196
203 const base::string16& window_name() const { return window_name_; }
204
205 base::Thread* window_thread() { return &window_thread_; } 197 base::Thread* window_thread() { return &window_thread_; }
206 198
207 private: 199 private:
208 bool MessageCallback(UINT message, 200 bool MessageCallback(UINT message,
209 WPARAM wparam, 201 WPARAM wparam,
210 LPARAM lparam, 202 LPARAM lparam,
211 LRESULT* result) { 203 LRESULT* result) {
212 EXPECT_EQ(window_thread_.message_loop(), base::MessageLoop::current()); 204 EXPECT_EQ(window_thread_.message_loop(), base::MessageLoop::current());
213 if (message == WM_NULL) { 205 if (message == WM_NULL) {
214 base::AutoLock auto_lock(ping_lock_); 206 base::AutoLock auto_lock(ping_lock_);
215 ++pings_; 207 ++pings_;
216 ping_event_.Signal(); 208 ping_event_.Signal();
217 } 209 }
218 210
219 return false; // Pass through to DefWindowProc. 211 return false; // Pass through to DefWindowProc.
220 } 212 }
221 213
222 void CreateMessageWindowInWorkerThread(const base::string16& name, 214 void CreateMessageWindowInWorkerThread(bool* success,
223 bool* success,
224 base::WaitableEvent* created) { 215 base::WaitableEvent* created) {
225 message_window_.reset(new base::win::MessageWindow); 216 message_window_.reset(new base::win::MessageWindow);
226 *success = message_window_->CreateNamed( 217 *success = message_window_->CreateNamed(
227 base::Bind(&WindowHangMonitorTest::MessageCallback, 218 base::Bind(&WindowHangMonitorTest::MessageCallback,
228 base::Unretained(this)), 219 base::Unretained(this)),
229 name); 220 L"BogusMessageWindowName");
230 created->Signal(); 221 created->Signal();
231 } 222 }
232 223
233 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) { 224 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) {
234 message_window_.reset(); 225 message_window_.reset();
235 if (deleted) 226 if (deleted)
236 deleted->Signal(); 227 deleted->Signal();
237 } 228 }
238 229
239 HangMonitorThread monitor_thread_; 230 HangMonitorThread monitor_thread_;
240 scoped_ptr<base::win::MessageWindow> message_window_; 231 scoped_ptr<base::win::MessageWindow> message_window_;
241 base::string16 window_name_;
242 base::Lock ping_lock_; 232 base::Lock ping_lock_;
243 base::WaitableEvent ping_event_; 233 base::WaitableEvent ping_event_;
244 size_t pings_; 234 size_t pings_;
245 base::Thread window_thread_; 235 base::Thread window_thread_;
246 236
247 DISALLOW_COPY_AND_ASSIGN(WindowHangMonitorTest); 237 DISALLOW_COPY_AND_ASSIGN(WindowHangMonitorTest);
248 }; 238 };
249 239
250 } // namespace 240 } // namespace
251 241
252 TEST_F(WindowHangMonitorTest, NoWindow) { 242 TEST_F(WindowHangMonitorTest, NoWindow) {
253 base::CommandLine child_command_line = 243 base::CommandLine child_command_line =
254 base::GetMultiProcessTestChildBaseCommandLine(); 244 base::GetMultiProcessTestChildBaseCommandLine();
255 child_command_line.AppendSwitchASCII(switches::kTestChildProcess, 245 child_command_line.AppendSwitchASCII(switches::kTestChildProcess,
256 "NoWindowChild"); 246 "NoWindowChild");
257 base::Process process = 247 base::Process process =
258 base::LaunchProcess(child_command_line, base::LaunchOptions()); 248 base::LaunchProcess(child_command_line, base::LaunchOptions());
259 ASSERT_TRUE(process.IsValid()); 249 ASSERT_TRUE(process.IsValid());
260 250
261 base::ScopedClosureRunner terminate_process_runner( 251 base::ScopedClosureRunner terminate_process_runner(
262 base::Bind(base::IgnoreResult(&base::Process::Terminate), 252 base::Bind(base::IgnoreResult(&base::Process::Terminate),
263 base::Unretained(&process), 1, true)); 253 base::Unretained(&process), 1, true));
264 254
265 monitor_thread().Start(process.Duplicate(), window_name()); 255 monitor_thread().Start(process.Duplicate());
266 256
267 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 257 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
268 base::TimeDelta::FromMilliseconds(150))); 258 base::TimeDelta::FromMilliseconds(150)));
269 259
270 terminate_process_runner.Reset(); 260 terminate_process_runner.Reset();
271 261
272 ASSERT_EQ(WindowHangMonitor::WINDOW_NOT_FOUND, 262 ASSERT_EQ(WindowHangMonitor::WINDOW_NOT_FOUND,
273 monitor_thread().WaitForEvent()); 263 monitor_thread().WaitForEvent());
274 264
275 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 265 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
276 base::TimeDelta::FromMilliseconds(150))); 266 base::TimeDelta::FromMilliseconds(150)));
277 } 267 }
278 268
279 TEST_F(WindowHangMonitorTest, WindowBeforeWatcher) { 269 TEST_F(WindowHangMonitorTest, WindowBeforeWatcher) {
280 CreateMessageWindow(); 270 CreateMessageWindow();
281 271
282 monitor_thread().Start(base::Process::Current(), window_name()); 272 monitor_thread().Start(base::Process::Current());
283 273
284 WaitForPing(); 274 WaitForPing();
285 275
286 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 276 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
287 base::TimeDelta::FromMilliseconds(150))); 277 base::TimeDelta::FromMilliseconds(150)));
288 } 278 }
289 279
290 TEST_F(WindowHangMonitorTest, WindowBeforeDestroy) { 280 TEST_F(WindowHangMonitorTest, WindowBeforeDestroy) {
291 CreateMessageWindow(); 281 CreateMessageWindow();
292 282
293 monitor_thread().Start(base::Process::Current(), window_name()); 283 monitor_thread().Start(base::Process::Current());
294 284
295 WaitForPing(); 285 WaitForPing();
296 286
297 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 287 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
298 base::TimeDelta::FromMilliseconds(150))); 288 base::TimeDelta::FromMilliseconds(150)));
299 289
300 monitor_thread().DestroyWatcher(); 290 monitor_thread().DestroyWatcher();
301 291
302 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); 292 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta()));
303 } 293 }
304 294
305 TEST_F(WindowHangMonitorTest, NoWindowBeforeDestroy) { 295 TEST_F(WindowHangMonitorTest, NoWindowBeforeDestroy) {
306 monitor_thread().Start(base::Process::Current(), window_name()); 296 monitor_thread().Start(base::Process::Current());
307 297
308 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 298 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
309 base::TimeDelta::FromMilliseconds(150))); 299 base::TimeDelta::FromMilliseconds(150)));
310 monitor_thread().DestroyWatcher(); 300 monitor_thread().DestroyWatcher();
311 301
312 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); 302 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta()));
313 } 303 }
314 304
315 TEST_F(WindowHangMonitorTest, WatcherBeforeWindow) { 305 TEST_F(WindowHangMonitorTest, WatcherBeforeWindow) {
316 monitor_thread().Start(base::Process::Current(), window_name()); 306 monitor_thread().Start(base::Process::Current());
317 307
318 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 308 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
319 base::TimeDelta::FromMilliseconds(150))); 309 base::TimeDelta::FromMilliseconds(150)));
320 310
321 CreateMessageWindow(); 311 CreateMessageWindow();
322 312
323 WaitForPing(); 313 WaitForPing();
324 314
325 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 315 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
326 base::TimeDelta::FromMilliseconds(150))); 316 base::TimeDelta::FromMilliseconds(150)));
327 } 317 }
328 318
329 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) { 319 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) {
330 CreateMessageWindow(); 320 CreateMessageWindow();
331 321
332 monitor_thread().Start(base::Process::Current(), window_name()); 322 monitor_thread().Start(base::Process::Current());
333 323
334 WaitForPing(); 324 WaitForPing();
335 325
336 DeleteMessageWindow(); 326 DeleteMessageWindow();
337 327
338 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED, 328 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED,
339 monitor_thread().WaitForEvent()); 329 monitor_thread().WaitForEvent());
340 330
341 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 331 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
342 base::TimeDelta::FromMilliseconds(150))); 332 base::TimeDelta::FromMilliseconds(150)));
343 } 333 }
344 334
345 TEST_F(WindowHangMonitorTest, DetectsWindowNameChange) {
346 // This test changes the title of the message window as a proxy for what
347 // happens if the window handle is reused for a different purpose. The latter
348 // is impossible to test in a deterministic fashion.
349 CreateMessageWindow();
350
351 monitor_thread().Start(base::Process::Current(), window_name());
352
353 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
354 base::TimeDelta::FromMilliseconds(150)));
355
356 ASSERT_TRUE(::SetWindowText(message_window()->hwnd(), L"Gonsky"));
357
358 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED,
359 monitor_thread().WaitForEvent());
360 }
361
362 TEST_F(WindowHangMonitorTest, DetectsWindowHang) { 335 TEST_F(WindowHangMonitorTest, DetectsWindowHang) {
363 CreateMessageWindow(); 336 CreateMessageWindow();
364 337
365 monitor_thread().Start(base::Process::Current(), window_name()); 338 monitor_thread().Start(base::Process::Current());
366 339
367 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 340 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
368 base::TimeDelta::FromMilliseconds(150))); 341 base::TimeDelta::FromMilliseconds(150)));
369 342
370 // Block the worker thread. 343 // Block the worker thread.
371 base::WaitableEvent hang(true, false); 344 base::WaitableEvent hang(true, false);
372 345
373 window_thread()->task_runner()->PostTask( 346 window_thread()->task_runner()->PostTask(
374 FROM_HERE, 347 FROM_HERE,
375 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang))); 348 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang)));
376 349
377 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, 350 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG,
378 monitor_thread().WaitForEvent()); 351 monitor_thread().WaitForEvent());
379 352
380 // Unblock the worker thread. 353 // Unblock the worker thread.
381 hang.Signal(); 354 hang.Signal();
382 355
383 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( 356 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(
384 base::TimeDelta::FromMilliseconds(150))); 357 base::TimeDelta::FromMilliseconds(150)));
385 } 358 }
386 359
387 } // namespace browser_watcher 360 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698