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

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

Issue 1036623002: Implements a monitor to watch for the browser hanging. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Erik's comments. Synchronize for ping() or remove the tests. Created 5 years, 9 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
« no previous file with comments | « components/browser_watcher/window_hang_monitor_win.cc ('k') | components/components_tests.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/browser_watcher/window_hang_monitor_win.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/process/process_handle.h"
14 #include "base/run_loop.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/threading/thread.h"
19 #include "base/win/message_window.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace browser_watcher {
23
24 namespace {
25
26 class WindowHangMonitorTest : public testing::Test {
27 public:
28 typedef std::vector<WindowHangMonitor::WindowEvent> WindowEventVector;
29
30 WindowHangMonitorTest()
31 : monitor_(base::Bind(&WindowHangMonitorTest::OnWindowEvent,
32 base::Unretained(this))),
33 message_loop_(base::MessageLoop::TYPE_UI),
34 run_loop_(nullptr),
35 pings_(0),
36 worker_thread_("HangMan") {}
37
38 // Callback from the hang detector.
39 void OnWindowEvent(WindowHangMonitor::WindowEvent event) {
40 // Record the event and terminate the message loop.
41 events_.push_back(event);
42 run_loop_->Quit();
43 }
44
45 void SetUp() override {
46 // Pick a window name unique to this process.
47 window_name_ = base::StringPrintf(L"WindowHanMonitorTest-%d",
48 base::GetCurrentProcId());
49 ASSERT_TRUE(worker_thread_.StartWithOptions(
50 base::Thread::Options(base::MessageLoop::TYPE_UI, 0)));
51
52 // Set relatively short hang detection and ping intervals.
53 monitor_.SetHangTimeoutForTesting(base::TimeDelta::FromMilliseconds(50));
54 monitor_.SetPingIntervalForTesting(base::TimeDelta::FromMilliseconds(200));
55 }
56
57 void TearDown() override {
58 DeleteMessageWindow();
59 worker_thread_.Stop();
60 }
61
62 void CreateMessageWindow() {
63 bool succeeded = false;
64 base::WaitableEvent created(true, false);
65 ASSERT_TRUE(worker_thread_.task_runner()->PostTask(
66 FROM_HERE,
67 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread,
68 base::Unretained(this), window_name_, &succeeded,
69 &created)));
70 created.Wait();
71 ASSERT_TRUE(succeeded);
72 }
73
74 void DeleteMessageWindow() {
75 base::WaitableEvent deleted(true, false);
76 worker_thread_.task_runner()->PostTask(
77 FROM_HERE,
78 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread,
79 base::Unretained(this), &deleted));
80 deleted.Wait();
81 }
82
83 bool MessageCallback(UINT message,
84 WPARAM wparam,
85 LPARAM lparam,
86 LRESULT* result) {
87 EXPECT_EQ(worker_thread_.message_loop(), base::MessageLoop::current());
88 if (message == WM_NULL)
89 ++pings_;
90
91 return false; // Pass through to DefWindowProc.
92 }
93
94 void RunMessageLoop() {
95 ASSERT_FALSE(run_loop_);
96
97 base::RunLoop loop;
98
99 run_loop_ = &loop;
100 loop.Run();
101 run_loop_ = nullptr;
102 }
103
104 WindowHangMonitor* monitor() { return &monitor_; }
105 const WindowEventVector& events() const { return events_; }
106 const base::win::MessageWindow* message_window() const {
107 return message_window_.get();
108 }
109 size_t pings() const { return pings_; }
110 const base::string16& window_name() const { return window_name_; }
111 base::Thread* worker_thread() { return &worker_thread_; }
112
113 private:
114 void CreateMessageWindowInWorkerThread(const base::string16& name,
115 bool* success,
116 base::WaitableEvent* created) {
117 message_window_.reset(new base::win::MessageWindow);
118 *success = message_window_->CreateNamed(
119 base::Bind(&WindowHangMonitorTest::MessageCallback,
120 base::Unretained(this)),
121 name);
122 created->Signal();
123 }
124
125 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) {
126 message_window_.reset();
127 if (deleted)
128 deleted->Signal();
129 }
130
131 WindowHangMonitor monitor_;
132 WindowEventVector events_;
133
134 // Message and run loops for the main thread.
135 base::MessageLoop message_loop_;
136 base::RunLoop* run_loop_;
137 scoped_ptr<base::win::MessageWindow> message_window_;
138 base::string16 window_name_;
139 size_t pings_;
140 base::Thread worker_thread_;
141 };
142
143 } // namespace
144
145 TEST_F(WindowHangMonitorTest, InitFailsWhenNoWindow) {
146 ASSERT_FALSE(monitor()->Initialize(window_name()));
147 EXPECT_TRUE(monitor()->IsIdleForTesting());
148 EXPECT_EQ(0, pings());
149 EXPECT_EQ(0, events().size());
150 }
151
152 TEST_F(WindowHangMonitorTest, InitSucceedsWhenWindow) {
153 CreateMessageWindow();
154
155 ASSERT_TRUE(monitor()->Initialize(window_name()));
156 EXPECT_FALSE(monitor()->IsIdleForTesting());
157
158 // Delete the window to synchronize against any pending message pings.
159 DeleteMessageWindow();
160
161 EXPECT_EQ(1, pings());
162 EXPECT_EQ(0, events().size());
163 }
164
165 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) {
166 CreateMessageWindow();
167
168 EXPECT_TRUE(monitor()->Initialize(window_name()));
169 EXPECT_EQ(0, events().size());
170
171 DeleteMessageWindow();
172
173 RunMessageLoop();
174
175 EXPECT_TRUE(monitor()->IsIdleForTesting());
176 ASSERT_EQ(1, events().size());
177 EXPECT_EQ(WindowHangMonitor::WINDOW_VANISHED, events()[0]);
178 }
179
180 TEST_F(WindowHangMonitorTest, DetectsWindowNameChange) {
181 // This test changes the title of the message window as a proxy for what
182 // happens if the window handle is reused for a different purpose. The latter
183 // is impossible to test in a deterministic fashion.
184 CreateMessageWindow();
185
186 ASSERT_TRUE(monitor()->Initialize(window_name()));
187 EXPECT_EQ(0, events().size());
188
189 ASSERT_TRUE(::SetWindowText(message_window()->hwnd(), L"Gonsky"));
190
191 RunMessageLoop();
192
193 EXPECT_TRUE(monitor()->IsIdleForTesting());
194 ASSERT_EQ(1, events().size());
195 EXPECT_EQ(WindowHangMonitor::WINDOW_VANISHED, events()[0]);
196 }
197
198 TEST_F(WindowHangMonitorTest, DetectsWindowHang) {
199 CreateMessageWindow();
200
201 ASSERT_TRUE(monitor()->Initialize(window_name()));
202 EXPECT_EQ(0, events().size());
203
204 // Block the worker thread.
205 base::WaitableEvent hang(true, false);
206
207 worker_thread()->message_loop_proxy()->PostTask(
208 FROM_HERE,
209 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang)));
210
211 RunMessageLoop();
212
213 // Unblock the worker thread.
214 hang.Signal();
215
216 EXPECT_TRUE(monitor()->IsIdleForTesting());
217 ASSERT_EQ(1, events().size());
218 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, events()[0]);
219 }
220
221 } // namespace browser_watcher
OLDNEW
« no previous file with comments | « components/browser_watcher/window_hang_monitor_win.cc ('k') | components/components_tests.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698