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

Side by Side Diff: content/test/browser_test_utils.cc

Issue 10826311: Move the corresponding cc files from content\test to be alongside their headers in content\public\t… (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « content/test/browser_test_base.cc ('k') | content/test/content_test_suite_base.cc » ('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 (c) 2012 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 "content/public/test/browser_test_utils.h"
6
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/path_service.h"
10 #include "base/process_util.h"
11 #include "base/rand_util.h"
12 #include "base/string_number_conversions.h"
13 #include "base/test/test_timeouts.h"
14 #include "base/utf_string_conversions.h"
15 #include "net/base/net_util.h"
16 #include "content/public/browser/dom_operation_notification_details.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
22 #include "content/public/browser/web_contents_view.h"
23 #include "content/public/test/test_utils.h"
24 #include "net/test/python_utils.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 static const int kDefaultWsPort = 8880;
28
29 namespace content {
30
31 namespace {
32
33 class DOMOperationObserver : public NotificationObserver,
34 public WebContentsObserver {
35 public:
36 explicit DOMOperationObserver(RenderViewHost* render_view_host)
37 : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
38 did_respond_(false) {
39 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
40 Source<RenderViewHost>(render_view_host));
41 message_loop_runner_ = new MessageLoopRunner;
42 }
43
44 virtual void Observe(int type,
45 const NotificationSource& source,
46 const NotificationDetails& details) OVERRIDE {
47 DCHECK(type == NOTIFICATION_DOM_OPERATION_RESPONSE);
48 Details<DomOperationNotificationDetails> dom_op_details(details);
49 response_ = dom_op_details->json;
50 did_respond_ = true;
51 message_loop_runner_->Quit();
52 }
53
54 // Overridden from WebContentsObserver:
55 virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
56 message_loop_runner_->Quit();
57 }
58
59 bool WaitAndGetResponse(std::string* response) WARN_UNUSED_RESULT {
60 message_loop_runner_->Run();
61 *response = response_;
62 return did_respond_;
63 }
64
65 private:
66 NotificationRegistrar registrar_;
67 std::string response_;
68 bool did_respond_;
69 scoped_refptr<MessageLoopRunner> message_loop_runner_;
70
71 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver);
72 };
73
74 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
75 bool ExecuteJavaScriptHelper(RenderViewHost* render_view_host,
76 const std::wstring& frame_xpath,
77 const std::wstring& original_script,
78 scoped_ptr<Value>* result) WARN_UNUSED_RESULT;
79
80 // Executes the passed |original_script| in the frame pointed to by
81 // |frame_xpath|. If |result| is not NULL, stores the value that the evaluation
82 // of the script in |result|. Returns true on success.
83 bool ExecuteJavaScriptHelper(RenderViewHost* render_view_host,
84 const std::wstring& frame_xpath,
85 const std::wstring& original_script,
86 scoped_ptr<Value>* result) {
87 // TODO(jcampan): we should make the domAutomationController not require an
88 // automation id.
89 std::wstring script = L"window.domAutomationController.setAutomationId(0);" +
90 original_script;
91 DOMOperationObserver dom_op_observer(render_view_host);
92 render_view_host->ExecuteJavascriptInWebFrame(WideToUTF16Hack(frame_xpath),
93 WideToUTF16Hack(script));
94 std::string json;
95 if (!dom_op_observer.WaitAndGetResponse(&json)) {
96 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver.";
97 return false;
98 }
99
100 // Nothing more to do for callers that ignore the returned JS value.
101 if (!result)
102 return true;
103
104 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
105 result->reset(reader.ReadToValue(json));
106 if (!result->get()) {
107 DLOG(ERROR) << reader.GetErrorMessage();
108 return false;
109 }
110
111 return true;
112 }
113
114 void BuildSimpleWebKeyEvent(WebKit::WebInputEvent::Type type,
115 ui::KeyboardCode key,
116 bool control,
117 bool shift,
118 bool alt,
119 bool command,
120 NativeWebKeyboardEvent* event) {
121 event->nativeKeyCode = 0;
122 event->windowsKeyCode = key;
123 event->setKeyIdentifierFromWindowsKeyCode();
124 event->type = type;
125 event->modifiers = 0;
126 event->isSystemKey = false;
127 event->timeStampSeconds = base::Time::Now().ToDoubleT();
128 event->skip_in_browser = true;
129
130 if (type == WebKit::WebInputEvent::Char ||
131 type == WebKit::WebInputEvent::RawKeyDown) {
132 event->text[0] = key;
133 event->unmodifiedText[0] = key;
134 }
135
136 if (control)
137 event->modifiers |= WebKit::WebInputEvent::ControlKey;
138
139 if (shift)
140 event->modifiers |= WebKit::WebInputEvent::ShiftKey;
141
142 if (alt)
143 event->modifiers |= WebKit::WebInputEvent::AltKey;
144
145 if (command)
146 event->modifiers |= WebKit::WebInputEvent::MetaKey;
147 }
148
149 } // namespace
150
151
152 GURL GetFileUrlWithQuery(const FilePath& path,
153 const std::string& query_string) {
154 GURL url = net::FilePathToFileURL(path);
155 if (!query_string.empty()) {
156 GURL::Replacements replacements;
157 replacements.SetQueryStr(query_string);
158 return url.ReplaceComponents(replacements);
159 }
160 return url;
161 }
162
163 void WaitForLoadStop(WebContents* web_contents) {
164 WindowedNotificationObserver load_stop_observer(
165 NOTIFICATION_LOAD_STOP,
166 Source<NavigationController>(&web_contents->GetController()));
167 // In many cases, the load may have finished before we get here. Only wait if
168 // the tab still has a pending navigation.
169 if (!web_contents->IsLoading())
170 return;
171 load_stop_observer.Wait();
172 }
173
174 void CrashTab(WebContents* web_contents) {
175 RenderProcessHost* rph = web_contents->GetRenderProcessHost();
176 WindowedNotificationObserver observer(
177 NOTIFICATION_RENDERER_PROCESS_CLOSED,
178 Source<RenderProcessHost>(rph));
179 base::KillProcess(rph->GetHandle(), 0, false);
180 observer.Wait();
181 }
182
183 void SimulateMouseClick(WebContents* web_contents) {
184 int x = web_contents->GetView()->GetContainerSize().width() / 2;
185 int y = web_contents->GetView()->GetContainerSize().height() / 2;
186 WebKit::WebMouseEvent mouse_event;
187 mouse_event.type = WebKit::WebInputEvent::MouseDown;
188 mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
189 mouse_event.x = x;
190 mouse_event.y = y;
191 // Mac needs globalX/globalY for events to plugins.
192 gfx::Rect offset;
193 web_contents->GetView()->GetContainerBounds(&offset);
194 mouse_event.globalX = x + offset.x();
195 mouse_event.globalY = y + offset.y();
196 mouse_event.clickCount = 1;
197 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
198 mouse_event.type = WebKit::WebInputEvent::MouseUp;
199 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
200 }
201
202 void SimulateMouseEvent(WebContents* web_contents,
203 WebKit::WebInputEvent::Type type,
204 const gfx::Point& point) {
205 WebKit::WebMouseEvent mouse_event;
206 mouse_event.type = type;
207 mouse_event.x = point.x();
208 mouse_event.y = point.y();
209 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
210 }
211
212 void SimulateKeyPress(WebContents* web_contents,
213 ui::KeyboardCode key,
214 bool control,
215 bool shift,
216 bool alt,
217 bool command) {
218 NativeWebKeyboardEvent event_down;
219 BuildSimpleWebKeyEvent(
220 WebKit::WebInputEvent::RawKeyDown, key, control, shift, alt, command,
221 &event_down);
222 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event_down);
223
224 NativeWebKeyboardEvent char_event;
225 BuildSimpleWebKeyEvent(
226 WebKit::WebInputEvent::Char, key, control, shift, alt, command,
227 &char_event);
228 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(char_event);
229
230 NativeWebKeyboardEvent event_up;
231 BuildSimpleWebKeyEvent(
232 WebKit::WebInputEvent::KeyUp, key, control, shift, alt, command,
233 &event_up);
234 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event_up);
235 }
236
237 bool ExecuteJavaScript(RenderViewHost* render_view_host,
238 const std::wstring& frame_xpath,
239 const std::wstring& original_script) {
240 std::wstring script =
241 original_script + L";window.domAutomationController.send(0);";
242 return ExecuteJavaScriptHelper(render_view_host, frame_xpath, script, NULL);
243 }
244
245 bool ExecuteJavaScriptAndExtractInt(RenderViewHost* render_view_host,
246 const std::wstring& frame_xpath,
247 const std::wstring& script,
248 int* result) {
249 DCHECK(result);
250 scoped_ptr<Value> value;
251 if (!ExecuteJavaScriptHelper(render_view_host, frame_xpath, script, &value) ||
252 !value.get())
253 return false;
254
255 return value->GetAsInteger(result);
256 }
257
258 bool ExecuteJavaScriptAndExtractBool(RenderViewHost* render_view_host,
259 const std::wstring& frame_xpath,
260 const std::wstring& script,
261 bool* result) {
262 DCHECK(result);
263 scoped_ptr<Value> value;
264 if (!ExecuteJavaScriptHelper(render_view_host, frame_xpath, script, &value) ||
265 !value.get())
266 return false;
267
268 return value->GetAsBoolean(result);
269 }
270
271 bool ExecuteJavaScriptAndExtractString(RenderViewHost* render_view_host,
272 const std::wstring& frame_xpath,
273 const std::wstring& script,
274 std::string* result) {
275 DCHECK(result);
276 scoped_ptr<Value> value;
277 if (!ExecuteJavaScriptHelper(render_view_host, frame_xpath, script, &value) ||
278 !value.get())
279 return false;
280
281 return value->GetAsString(result);
282 }
283
284 TitleWatcher::TitleWatcher(WebContents* web_contents,
285 const string16& expected_title)
286 : web_contents_(web_contents),
287 expected_title_observed_(false),
288 quit_loop_on_observation_(false) {
289 EXPECT_TRUE(web_contents != NULL);
290 expected_titles_.push_back(expected_title);
291 notification_registrar_.Add(this,
292 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
293 Source<WebContents>(web_contents));
294
295 // When navigating through the history, the restored NavigationEntry's title
296 // will be used. If the entry ends up having the same title after we return
297 // to it, as will usually be the case, the
298 // NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED will then be suppressed, since the
299 // NavigationEntry's title hasn't changed.
300 notification_registrar_.Add(
301 this,
302 NOTIFICATION_LOAD_STOP,
303 Source<NavigationController>(&web_contents->GetController()));
304 }
305
306 void TitleWatcher::AlsoWaitForTitle(const string16& expected_title) {
307 expected_titles_.push_back(expected_title);
308 }
309
310 TitleWatcher::~TitleWatcher() {
311 }
312
313 const string16& TitleWatcher::WaitAndGetTitle() {
314 if (expected_title_observed_)
315 return observed_title_;
316 quit_loop_on_observation_ = true;
317 message_loop_runner_ = new MessageLoopRunner;
318 message_loop_runner_->Run();
319 return observed_title_;
320 }
321
322 void TitleWatcher::Observe(int type,
323 const NotificationSource& source,
324 const NotificationDetails& details) {
325 if (type == NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
326 WebContents* source_contents = Source<WebContents>(source).ptr();
327 ASSERT_EQ(web_contents_, source_contents);
328 } else if (type == NOTIFICATION_LOAD_STOP) {
329 NavigationController* controller =
330 Source<NavigationController>(source).ptr();
331 ASSERT_EQ(&web_contents_->GetController(), controller);
332 } else {
333 FAIL() << "Unexpected notification received.";
334 }
335
336 std::vector<string16>::const_iterator it =
337 std::find(expected_titles_.begin(),
338 expected_titles_.end(),
339 web_contents_->GetTitle());
340 if (it == expected_titles_.end())
341 return;
342 observed_title_ = *it;
343 expected_title_observed_ = true;
344 if (quit_loop_on_observation_) {
345 // Only call Quit once, on first Observe:
346 quit_loop_on_observation_ = false;
347 message_loop_runner_->Quit();
348 }
349 }
350
351 TestWebSocketServer::TestWebSocketServer()
352 : started_(false),
353 port_(kDefaultWsPort),
354 secure_(false) {
355 #if defined(OS_POSIX)
356 process_group_id_ = base::kNullProcessHandle;
357 #endif
358 }
359
360 int TestWebSocketServer::UseRandomPort() {
361 port_ = base::RandInt(1024, 65535);
362 return port_;
363 }
364
365 void TestWebSocketServer::UseTLS() {
366 secure_ = true;
367 }
368
369 bool TestWebSocketServer::Start(const FilePath& root_directory) {
370 if (started_)
371 return true;
372 // Append CommandLine arguments after the server script, switches won't work.
373 scoped_ptr<CommandLine> cmd_line(CreateWebSocketServerCommandLine());
374 cmd_line->AppendArg("--server=start");
375 cmd_line->AppendArg("--chromium");
376 cmd_line->AppendArg("--register_cygwin");
377 cmd_line->AppendArgNative(FILE_PATH_LITERAL("--root=") +
378 root_directory.value());
379 cmd_line->AppendArg("--port=" + base::IntToString(port_));
380 if (secure_)
381 cmd_line->AppendArg("--tls");
382 if (!temp_dir_.CreateUniqueTempDir()) {
383 LOG(ERROR) << "Unable to create a temporary directory.";
384 return false;
385 }
386 cmd_line->AppendArgNative(FILE_PATH_LITERAL("--output-dir=") +
387 temp_dir_.path().value());
388 websocket_pid_file_ = temp_dir_.path().AppendASCII("websocket.pid");
389 cmd_line->AppendArgNative(FILE_PATH_LITERAL("--pidfile=") +
390 websocket_pid_file_.value());
391 SetPythonPath();
392
393 base::LaunchOptions options;
394 base::ProcessHandle process_handle;
395
396 #if defined(OS_POSIX)
397 options.new_process_group = true;
398 #elif defined(OS_WIN)
399 job_handle_.Set(CreateJobObject(NULL, NULL));
400 if (!job_handle_.IsValid()) {
401 LOG(ERROR) << "Could not create JobObject.";
402 return false;
403 }
404
405 if (!base::SetJobObjectAsKillOnJobClose(job_handle_.Get())) {
406 LOG(ERROR) << "Could not SetInformationJobObject.";
407 return false;
408 }
409
410 options.inherit_handles = true;
411 options.job_handle = job_handle_.Get();
412 #endif
413
414 // Launch a new WebSocket server process.
415 if (!base::LaunchProcess(*cmd_line.get(), options, &process_handle)) {
416 LOG(ERROR) << "Unable to launch websocket server:\n"
417 << cmd_line.get()->GetCommandLineString();
418 return false;
419 }
420 #if defined(OS_POSIX)
421 process_group_id_ = process_handle;
422 #endif
423 int exit_code;
424 bool wait_success = base::WaitForExitCodeWithTimeout(
425 process_handle,
426 &exit_code,
427 TestTimeouts::action_max_timeout());
428 base::CloseProcessHandle(process_handle);
429
430 if (!wait_success || exit_code != 0) {
431 LOG(ERROR) << "Failed to run new-run-webkit-websocketserver: "
432 << "wait_success = " << wait_success << ", "
433 << "exit_code = " << exit_code << ", "
434 << "command_line = " << cmd_line.get()->GetCommandLineString();
435 return false;
436 }
437
438 started_ = true;
439 return true;
440 }
441
442 CommandLine* TestWebSocketServer::CreatePythonCommandLine() {
443 // Note: Python's first argument must be the script; do not append CommandLine
444 // switches, as they would precede the script path and break this CommandLine.
445 FilePath path;
446 CHECK(GetPythonRunTime(&path));
447 return new CommandLine(path);
448 }
449
450 void TestWebSocketServer::SetPythonPath() {
451 FilePath scripts_path;
452 PathService::Get(base::DIR_SOURCE_ROOT, &scripts_path);
453
454 scripts_path = scripts_path
455 .Append(FILE_PATH_LITERAL("third_party"))
456 .Append(FILE_PATH_LITERAL("WebKit"))
457 .Append(FILE_PATH_LITERAL("Tools"))
458 .Append(FILE_PATH_LITERAL("Scripts"));
459 AppendToPythonPath(scripts_path);
460 }
461
462 CommandLine* TestWebSocketServer::CreateWebSocketServerCommandLine() {
463 FilePath src_path;
464 // Get to 'src' dir.
465 PathService::Get(base::DIR_SOURCE_ROOT, &src_path);
466
467 FilePath script_path(src_path);
468 script_path = script_path.AppendASCII("third_party");
469 script_path = script_path.AppendASCII("WebKit");
470 script_path = script_path.AppendASCII("Tools");
471 script_path = script_path.AppendASCII("Scripts");
472 script_path = script_path.AppendASCII("new-run-webkit-websocketserver");
473
474 CommandLine* cmd_line = CreatePythonCommandLine();
475 cmd_line->AppendArgPath(script_path);
476 return cmd_line;
477 }
478
479 TestWebSocketServer::~TestWebSocketServer() {
480 if (!started_)
481 return;
482 // Append CommandLine arguments after the server script, switches won't work.
483 scoped_ptr<CommandLine> cmd_line(CreateWebSocketServerCommandLine());
484 cmd_line->AppendArg("--server=stop");
485 cmd_line->AppendArg("--chromium");
486 cmd_line->AppendArgNative(FILE_PATH_LITERAL("--pidfile=") +
487 websocket_pid_file_.value());
488 base::LaunchOptions options;
489 options.wait = true;
490 base::LaunchProcess(*cmd_line.get(), options, NULL);
491
492 #if defined(OS_POSIX)
493 // Just to make sure that the server process terminates certainly.
494 if (process_group_id_ != base::kNullProcessHandle)
495 base::KillProcessGroup(process_group_id_);
496 #endif
497 }
498
499 } // namespace content
OLDNEW
« no previous file with comments | « content/test/browser_test_base.cc ('k') | content/test/content_test_suite_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698