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

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

Powered by Google App Engine
This is Rietveld 408576698