Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / components / browser_watcher / window_hang_monitor_win_unittest.cc
blob236c18d0445d9d40c3abc3598397ec6c2f0f6a50
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.
5 #include "components/browser_watcher/window_hang_monitor_win.h"
7 #include <vector>
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"
22 namespace browser_watcher {
24 namespace {
26 class WindowHangMonitorTest : public testing::Test {
27 public:
28 typedef std::vector<WindowHangMonitor::WindowEvent> WindowEventVector;
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") {}
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();
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)));
52 // Set relatively short hang detection and ping intervals.
53 monitor_.SetHangTimeoutForTesting(base::TimeDelta::FromMilliseconds(50));
54 monitor_.SetPingIntervalForTesting(base::TimeDelta::FromMilliseconds(200));
57 void TearDown() override {
58 DeleteMessageWindow();
59 worker_thread_.Stop();
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);
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();
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_;
91 return false; // Pass through to DefWindowProc.
94 void RunMessageLoop() {
95 ASSERT_FALSE(run_loop_);
97 base::RunLoop loop;
99 run_loop_ = &loop;
100 loop.Run();
101 run_loop_ = nullptr;
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();
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_; }
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();
125 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) {
126 message_window_.reset();
127 if (deleted)
128 deleted->Signal();
131 WindowHangMonitor monitor_;
132 WindowEventVector events_;
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_;
143 } // namespace
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());
152 TEST_F(WindowHangMonitorTest, InitSucceedsWhenWindow) {
153 CreateMessageWindow();
155 ASSERT_TRUE(monitor()->Initialize(window_name()));
156 EXPECT_FALSE(monitor()->IsIdleForTesting());
158 // Delete the window to synchronize against any pending message pings.
159 DeleteMessageWindow();
161 EXPECT_EQ(1, pings());
162 EXPECT_EQ(0, events().size());
165 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) {
166 CreateMessageWindow();
168 EXPECT_TRUE(monitor()->Initialize(window_name()));
169 EXPECT_EQ(0, events().size());
171 DeleteMessageWindow();
173 RunMessageLoop();
175 EXPECT_TRUE(monitor()->IsIdleForTesting());
176 ASSERT_EQ(1, events().size());
177 EXPECT_EQ(WindowHangMonitor::WINDOW_VANISHED, events()[0]);
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();
186 ASSERT_TRUE(monitor()->Initialize(window_name()));
187 EXPECT_EQ(0, events().size());
189 ASSERT_TRUE(::SetWindowText(message_window()->hwnd(), L"Gonsky"));
191 RunMessageLoop();
193 EXPECT_TRUE(monitor()->IsIdleForTesting());
194 ASSERT_EQ(1, events().size());
195 EXPECT_EQ(WindowHangMonitor::WINDOW_VANISHED, events()[0]);
198 TEST_F(WindowHangMonitorTest, DetectsWindowHang) {
199 CreateMessageWindow();
201 ASSERT_TRUE(monitor()->Initialize(window_name()));
202 EXPECT_EQ(0, events().size());
204 // Block the worker thread.
205 base::WaitableEvent hang(true, false);
207 worker_thread()->message_loop_proxy()->PostTask(
208 FROM_HERE,
209 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang)));
211 RunMessageLoop();
213 // Unblock the worker thread.
214 hang.Signal();
216 EXPECT_TRUE(monitor()->IsIdleForTesting());
217 ASSERT_EQ(1, events().size());
218 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, events()[0]);
221 } // namespace browser_watcher