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

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

Powered by Google App Engine
This is Rietveld 408576698