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

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. Add GN build config. 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
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 const base::char16 kRegistryPath[] = L"Software\\HangMonitorTest";
erikwright (departed) 2015/03/25 20:06:59 not used
Sigurður Ásgeirsson 2015/03/25 20:41:17 Done.
27
28 class WindowHangMonitorTest : public testing::Test {
29 public:
30 typedef std::vector<WindowHangMonitor::WindowEvent> WindowEventVector;
31
32 WindowHangMonitorTest()
33 : monitor_(base::Bind(&WindowHangMonitorTest::OnWindowEvent,
34 base::Unretained(this))),
35 message_loop_(base::MessageLoop::TYPE_UI),
36 run_loop_(nullptr),
37 pings_(0),
38 worker_thread_("HangMan") {}
39
40 // Callback from the hang detector.
41 void OnWindowEvent(WindowHangMonitor::WindowEvent event) {
42 // Record the event and terminate the message loop.
43 events_.push_back(event);
44 run_loop_->Quit();
45 }
46
47 void SetUp() override {
48 // Pick a window name unique to this process.
49 window_name_ = base::StringPrintf(L"WindowHanMonitorTest-%d",
50 base::GetCurrentProcId());
51 ASSERT_TRUE(worker_thread_.StartWithOptions(
52 base::Thread::Options(base::MessageLoop::TYPE_UI, 0)));
53
54 // Set relatively short hang detection and ping intervals.
55 monitor_.SetHangTimeoutForTesting(base::TimeDelta::FromMilliseconds(50));
56 monitor_.SetPingIntervalForTesting(base::TimeDelta::FromMilliseconds(200));
57 }
58
59 void TearDown() override {
60 DeleteMessageWindow();
61 worker_thread_.Stop();
62 }
63
64 void CreateMessageWindow() {
65 bool succeeded = false;
66 base::WaitableEvent created(true, false);
67 ASSERT_TRUE(worker_thread_.task_runner()->PostTask(
68 FROM_HERE,
69 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread,
70 base::Unretained(this), window_name_, &succeeded,
71 &created)));
72 created.Wait();
73 ASSERT_TRUE(succeeded);
74 }
75
76 void DeleteMessageWindow() {
77 base::WaitableEvent deleted(true, false);
78 worker_thread_.task_runner()->PostTask(
79 FROM_HERE,
80 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread,
81 base::Unretained(this), &deleted));
erikwright (departed) 2015/03/25 20:06:58 deleted is optional and not used, so make it NULL?
Sigurður Ásgeirsson 2015/03/25 20:41:17 Ah - that's why the test flaked - the Wait is miss
82 }
83
84 bool MessageCallback(UINT message,
85 WPARAM wparam,
86 LPARAM lparam,
87 LRESULT* result) {
88 EXPECT_EQ(worker_thread_.message_loop(), base::MessageLoop::current());
89 if (message == WM_NULL)
90 ++pings_;
91
92 return false; // Pass through to DefWindowProc.
93 }
94
95 void RunMessageLoop() {
96 ASSERT_FALSE(run_loop_);
97
98 base::RunLoop loop;
99
100 run_loop_ = &loop;
101 loop.Run();
102 run_loop_ = nullptr;
103 }
104
105 WindowHangMonitor* monitor() { return &monitor_; }
106 const WindowEventVector& events() const { return events_; }
107 const base::win::MessageWindow* message_window() const {
108 return message_window_.get();
109 }
110 size_t pings() const { return pings_; }
111 const base::string16& window_name() const { return window_name_; }
112 base::Thread* worker_thread() { return &worker_thread_; }
113
114 private:
115 void CreateMessageWindowInWorkerThread(const base::string16& name,
116 bool* success,
117 base::WaitableEvent* created) {
118 message_window_.reset(new base::win::MessageWindow);
119 *success = message_window_->CreateNamed(
120 base::Bind(&WindowHangMonitorTest::MessageCallback,
121 base::Unretained(this)),
122 name);
123 created->Signal();
124 }
125
126 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) {
127 message_window_.reset();
128 if (deleted)
129 deleted->Signal();
130 }
131
132 WindowHangMonitor monitor_;
133 WindowEventVector events_;
134
135 // Message and run loops for the main thread.
136 base::MessageLoop message_loop_;
137 base::RunLoop* run_loop_;
138 scoped_ptr<base::win::MessageWindow> message_window_;
139 base::string16 window_name_;
140 size_t pings_;
141 base::Thread worker_thread_;
142 };
143
144 } // namespace
145
146 TEST_F(WindowHangMonitorTest, InitFailsWhenNoWindow) {
147 ASSERT_FALSE(monitor()->Initialize(window_name()));
148 EXPECT_TRUE(monitor()->IsIdleForTesting());
149 EXPECT_EQ(0, pings());
150 EXPECT_EQ(0, events().size());
151 }
152
153 TEST_F(WindowHangMonitorTest, InitSucceedsWhenWindow) {
154 CreateMessageWindow();
155
156 ASSERT_TRUE(monitor()->Initialize(window_name()));
157 EXPECT_FALSE(monitor()->IsIdleForTesting());
158
159 EXPECT_EQ(1, pings());
160 EXPECT_EQ(0, events().size());
161 }
162
163 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) {
164 CreateMessageWindow();
165
166 EXPECT_TRUE(monitor()->Initialize(window_name()));
167 EXPECT_EQ(1, pings());
168 EXPECT_EQ(0, events().size());
169
170 DeleteMessageWindow();
171
172 RunMessageLoop();
173
174 EXPECT_TRUE(monitor()->IsIdleForTesting());
175 ASSERT_EQ(1, events().size());
176 EXPECT_EQ(WindowHangMonitor::WINDOW_VANISHED, events()[0]);
177 }
178
179 TEST_F(WindowHangMonitorTest, DetectsWindowNameChange) {
180 // This test changes the title of the message window as a proxy for what
181 // happens if the window handle is reused for a different purpose. The latter
182 // is impossible to test in a deterministic fashion.
183 CreateMessageWindow();
184
185 ASSERT_TRUE(monitor()->Initialize(window_name()));
186 EXPECT_EQ(1, pings());
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(1, pings());
203 EXPECT_EQ(0, events().size());
204
205 // Block the worker thread.
206 base::WaitableEvent hang(true, false);
207
208 worker_thread()->message_loop_proxy()->PostTask(
209 FROM_HERE,
210 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang)));
211
212 RunMessageLoop();
213
214 // Unblock the worker thread.
215 hang.Signal();
216
217 EXPECT_TRUE(monitor()->IsIdleForTesting());
218 ASSERT_EQ(1, events().size());
219 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, events()[0]);
220 }
221
222 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698