OLD | NEW |
| (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 "chrome/test/automation/proxy_launcher.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/environment.h" | |
10 #include "base/file_util.h" | |
11 #include "base/files/file_enumerator.h" | |
12 #include "base/files/scoped_file.h" | |
13 #include "base/process/kill.h" | |
14 #include "base/process/launch.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "base/strings/string_split.h" | |
17 #include "base/strings/stringprintf.h" | |
18 #include "base/strings/utf_string_conversions.h" | |
19 #include "base/test/test_file_util.h" | |
20 #include "base/test/test_timeouts.h" | |
21 #include "chrome/app/chrome_command_ids.h" | |
22 #include "chrome/common/automation_constants.h" | |
23 #include "chrome/common/chrome_constants.h" | |
24 #include "chrome/common/chrome_switches.h" | |
25 #include "chrome/common/logging_chrome.h" | |
26 #include "chrome/common/url_constants.h" | |
27 #include "chrome/test/automation/automation_proxy.h" | |
28 #include "chrome/test/base/chrome_process_util.h" | |
29 #include "chrome/test/base/test_launcher_utils.h" | |
30 #include "chrome/test/base/test_switches.h" | |
31 #include "chrome/test/ui/ui_test.h" | |
32 #include "content/public/common/process_type.h" | |
33 #include "ipc/ipc_channel.h" | |
34 #include "ipc/ipc_descriptors.h" | |
35 #include "sql/connection.h" | |
36 | |
37 #if defined(OS_POSIX) | |
38 #include <signal.h> | |
39 #include "base/posix/global_descriptors.h" | |
40 #endif | |
41 | |
42 namespace { | |
43 | |
44 // Passed as value of kTestType. | |
45 const char kUITestType[] = "ui"; | |
46 | |
47 // Copies the contents of the given source directory to the given dest | |
48 // directory. This is somewhat different than CopyDirectory in base which will | |
49 // copies "source/" to "dest/source/". This version will copy "source/*" to | |
50 // "dest/*", overwriting existing files as necessary. | |
51 // | |
52 // This also kicks the files out of the memory cache for the startup tests. | |
53 // TODO(brettw) bug 237904: This is the wrong place for this code. It means all | |
54 // startup tests other than the "cold" ones run more slowly than necessary. | |
55 bool CopyDirectoryContentsNoCache(const base::FilePath& source, | |
56 const base::FilePath& dest) { | |
57 base::FileEnumerator en(source, false, | |
58 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | |
59 for (base::FilePath cur = en.Next(); !cur.empty(); cur = en.Next()) { | |
60 base::FileEnumerator::FileInfo info = en.GetInfo(); | |
61 if (info.IsDirectory()) { | |
62 if (!base::CopyDirectory(cur, dest, true)) | |
63 return false; | |
64 } else { | |
65 if (!base::CopyFile(cur, dest.Append(cur.BaseName()))) | |
66 return false; | |
67 } | |
68 } | |
69 | |
70 // Kick out the profile files, this must happen after SetUp which creates the | |
71 // profile. It might be nicer to use EvictFileFromSystemCacheWrapper from | |
72 // UITest which will retry on failure. | |
73 base::FileEnumerator kickout(dest, true, base::FileEnumerator::FILES); | |
74 for (base::FilePath cur = kickout.Next(); !cur.empty(); cur = kickout.Next()) | |
75 base::EvictFileFromSystemCacheWithRetry(cur); | |
76 return true; | |
77 } | |
78 | |
79 // We want to have a current history database when we start the browser so | |
80 // things like the NTP will have thumbnails. This method updates the dates | |
81 // in the history to be more recent. | |
82 void UpdateHistoryDates(const base::FilePath& user_data_dir) { | |
83 // Migrate the times in the segment_usage table to yesterday so we get | |
84 // actual thumbnails on the NTP. | |
85 sql::Connection db; | |
86 base::FilePath history = | |
87 user_data_dir.AppendASCII("Default").AppendASCII("History"); | |
88 // Not all test profiles have a history file. | |
89 if (!base::PathExists(history)) | |
90 return; | |
91 | |
92 ASSERT_TRUE(db.Open(history)); | |
93 base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1); | |
94 std::string yesterday_str = base::Int64ToString(yesterday.ToInternalValue()); | |
95 std::string query = base::StringPrintf( | |
96 "UPDATE segment_usage " | |
97 "SET time_slot = %s " | |
98 "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);", | |
99 yesterday_str.c_str()); | |
100 ASSERT_TRUE(db.Execute(query.c_str())); | |
101 db.Close(); | |
102 base::EvictFileFromSystemCache(history); | |
103 } | |
104 | |
105 } // namespace | |
106 | |
107 // ProxyLauncher functions | |
108 | |
109 #if defined(OS_WIN) | |
110 const char ProxyLauncher::kDefaultInterfaceId[] = "ChromeTestingInterface"; | |
111 #elif defined(OS_POSIX) | |
112 const char ProxyLauncher::kDefaultInterfaceId[] = | |
113 "/var/tmp/ChromeTestingInterface"; | |
114 #endif | |
115 | |
116 ProxyLauncher::ProxyLauncher() | |
117 : process_(base::kNullProcessHandle), | |
118 process_id_(-1), | |
119 shutdown_type_(WINDOW_CLOSE), | |
120 no_sandbox_(CommandLine::ForCurrentProcess()->HasSwitch( | |
121 switches::kNoSandbox)), | |
122 full_memory_dump_(CommandLine::ForCurrentProcess()->HasSwitch( | |
123 switches::kFullMemoryCrashReport)), | |
124 show_error_dialogs_(CommandLine::ForCurrentProcess()->HasSwitch( | |
125 switches::kEnableErrorDialogs)), | |
126 silent_dump_on_dcheck_(CommandLine::ForCurrentProcess()->HasSwitch( | |
127 switches::kSilentDumpOnDCHECK)), | |
128 disable_breakpad_(CommandLine::ForCurrentProcess()->HasSwitch( | |
129 switches::kDisableBreakpad)), | |
130 js_flags_(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
131 switches::kJavaScriptFlags)), | |
132 log_level_(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
133 switches::kLoggingLevel)) { | |
134 } | |
135 | |
136 ProxyLauncher::~ProxyLauncher() {} | |
137 | |
138 bool ProxyLauncher::WaitForBrowserLaunch(bool wait_for_initial_loads) { | |
139 AutomationLaunchResult app_launched = automation_proxy_->WaitForAppLaunch(); | |
140 EXPECT_EQ(AUTOMATION_SUCCESS, app_launched) | |
141 << "Error while awaiting automation ping from browser process"; | |
142 if (app_launched != AUTOMATION_SUCCESS) | |
143 return false; | |
144 | |
145 if (wait_for_initial_loads) { | |
146 if (!automation_proxy_->WaitForInitialLoads()) { | |
147 LOG(ERROR) << "WaitForInitialLoads failed."; | |
148 return false; | |
149 } | |
150 } else { | |
151 #if defined(OS_WIN) | |
152 // TODO(phajdan.jr): Get rid of this Sleep when logging_chrome_uitest | |
153 // stops "relying" on it. | |
154 base::PlatformThread::Sleep(TestTimeouts::action_timeout()); | |
155 #endif | |
156 } | |
157 | |
158 return true; | |
159 } | |
160 | |
161 bool ProxyLauncher::LaunchBrowserAndServer(const LaunchState& state, | |
162 bool wait_for_initial_loads) { | |
163 // Set up IPC testing interface as a server. | |
164 automation_proxy_.reset(CreateAutomationProxy( | |
165 TestTimeouts::action_max_timeout())); | |
166 | |
167 if (!LaunchBrowser(state)) | |
168 return false; | |
169 | |
170 if (!WaitForBrowserLaunch(wait_for_initial_loads)) | |
171 return false; | |
172 | |
173 return true; | |
174 } | |
175 | |
176 bool ProxyLauncher::ConnectToRunningBrowser(bool wait_for_initial_loads) { | |
177 // Set up IPC testing interface as a client. | |
178 automation_proxy_.reset(CreateAutomationProxy( | |
179 TestTimeouts::action_max_timeout())); | |
180 | |
181 return WaitForBrowserLaunch(wait_for_initial_loads); | |
182 } | |
183 | |
184 void ProxyLauncher::CloseBrowserAndServer() { | |
185 QuitBrowser(); | |
186 | |
187 // Suppress spammy failures that seem to be occurring when running | |
188 // the UI tests in single-process mode. | |
189 // TODO(jhughes): figure out why this is necessary at all, and fix it | |
190 AssertAppNotRunning( | |
191 base::StringPrintf( | |
192 "Unable to quit all browser processes. Original PID %d", | |
193 process_id_)); | |
194 | |
195 DisconnectFromRunningBrowser(); | |
196 } | |
197 | |
198 void ProxyLauncher::DisconnectFromRunningBrowser() { | |
199 automation_proxy_.reset(); // Shut down IPC testing interface. | |
200 } | |
201 | |
202 bool ProxyLauncher::LaunchBrowser(const LaunchState& state) { | |
203 if (state.clear_profile || !temp_profile_dir_.IsValid()) { | |
204 if (temp_profile_dir_.IsValid() && !temp_profile_dir_.Delete()) { | |
205 LOG(ERROR) << "Failed to delete temporary directory."; | |
206 return false; | |
207 } | |
208 | |
209 if (!temp_profile_dir_.CreateUniqueTempDir()) { | |
210 LOG(ERROR) << "Failed to create temporary directory."; | |
211 return false; | |
212 } | |
213 | |
214 if (!test_launcher_utils::OverrideUserDataDir(user_data_dir())) { | |
215 LOG(ERROR) << "Failed to override user data directory."; | |
216 return false; | |
217 } | |
218 } | |
219 | |
220 if (!state.template_user_data.empty()) { | |
221 // Recursively copy the template directory to the user_data_dir. | |
222 if (!CopyDirectoryContentsNoCache(state.template_user_data, | |
223 user_data_dir())) { | |
224 LOG(ERROR) << "Failed to copy user data directory template."; | |
225 return false; | |
226 } | |
227 | |
228 // Update the history file to include recent dates. | |
229 UpdateHistoryDates(user_data_dir()); | |
230 } | |
231 | |
232 // Optionally do any final setup of the test environment. | |
233 if (!state.setup_profile_callback.is_null()) | |
234 state.setup_profile_callback.Run(); | |
235 | |
236 if (!LaunchBrowserHelper(state, true, false, &process_)) { | |
237 LOG(ERROR) << "LaunchBrowserHelper failed."; | |
238 return false; | |
239 } | |
240 process_id_ = base::GetProcId(process_); | |
241 | |
242 return true; | |
243 } | |
244 | |
245 void ProxyLauncher::QuitBrowser() { | |
246 // If we have already finished waiting for the browser to exit | |
247 // (or it hasn't launched at all), there's nothing to do here. | |
248 if (process_ == base::kNullProcessHandle || !automation_proxy_.get()) | |
249 return; | |
250 | |
251 if (SESSION_ENDING == shutdown_type_) { | |
252 TerminateBrowser(); | |
253 return; | |
254 } | |
255 | |
256 base::TimeTicks quit_start = base::TimeTicks::Now(); | |
257 | |
258 if (WINDOW_CLOSE == shutdown_type_) { | |
259 int window_count = 0; | |
260 EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); | |
261 | |
262 // Synchronously close all but the last browser window. Closing them | |
263 // one-by-one may help with stability. | |
264 while (window_count > 1) { | |
265 scoped_refptr<BrowserProxy> browser_proxy = | |
266 automation()->GetBrowserWindow(0); | |
267 EXPECT_TRUE(browser_proxy.get()); | |
268 if (browser_proxy.get()) { | |
269 EXPECT_TRUE(browser_proxy->RunCommand(IDC_CLOSE_WINDOW)); | |
270 EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); | |
271 } else { | |
272 break; | |
273 } | |
274 } | |
275 | |
276 // Close the last window asynchronously, because the browser may | |
277 // shutdown faster than it will be able to send a synchronous response | |
278 // to our message. | |
279 scoped_refptr<BrowserProxy> browser_proxy = | |
280 automation()->GetBrowserWindow(0); | |
281 EXPECT_TRUE(browser_proxy.get()); | |
282 if (browser_proxy.get()) { | |
283 EXPECT_TRUE(browser_proxy->is_valid()); | |
284 EXPECT_TRUE(browser_proxy->ApplyAccelerator(IDC_CLOSE_WINDOW)); | |
285 browser_proxy = NULL; | |
286 } | |
287 } else if (USER_QUIT == shutdown_type_) { | |
288 scoped_refptr<BrowserProxy> browser_proxy = | |
289 automation()->GetBrowserWindow(0); | |
290 EXPECT_TRUE(browser_proxy.get()); | |
291 if (browser_proxy.get()) { | |
292 EXPECT_TRUE(browser_proxy->RunCommandAsync(IDC_EXIT)); | |
293 } | |
294 } else { | |
295 NOTREACHED() << "Invalid shutdown type " << shutdown_type_; | |
296 } | |
297 | |
298 ChromeProcessList processes = GetRunningChromeProcesses(process_id_); | |
299 | |
300 // Now, drop the automation IPC channel so that the automation provider in | |
301 // the browser notices and drops its reference to the browser process. | |
302 if (automation_proxy_.get()) | |
303 automation_proxy_->Disconnect(); | |
304 | |
305 // Wait for the browser process to quit. It should quit once all tabs have | |
306 // been closed. | |
307 int exit_code = -1; | |
308 EXPECT_TRUE(WaitForBrowserProcessToQuit( | |
309 TestTimeouts::action_max_timeout(), &exit_code)); | |
310 EXPECT_EQ(0, exit_code); // Expect a clean shutdown. | |
311 | |
312 browser_quit_time_ = base::TimeTicks::Now() - quit_start; | |
313 | |
314 // Ensure no child processes are left dangling. | |
315 TerminateAllChromeProcesses(processes); | |
316 } | |
317 | |
318 void ProxyLauncher::TerminateBrowser() { | |
319 // If we have already finished waiting for the browser to exit | |
320 // (or it hasn't launched at all), there's nothing to do here. | |
321 if (process_ == base::kNullProcessHandle || !automation_proxy_.get()) | |
322 return; | |
323 | |
324 base::TimeTicks quit_start = base::TimeTicks::Now(); | |
325 | |
326 ChromeProcessList processes = GetRunningChromeProcesses(process_id_); | |
327 | |
328 // Now, drop the automation IPC channel so that the automation provider in | |
329 // the browser notices and drops its reference to the browser process. | |
330 if (automation_proxy_.get()) | |
331 automation_proxy_->Disconnect(); | |
332 | |
333 #if defined(OS_POSIX) | |
334 EXPECT_EQ(kill(process_, SIGTERM), 0); | |
335 #endif // OS_POSIX | |
336 | |
337 int exit_code = -1; | |
338 EXPECT_TRUE(WaitForBrowserProcessToQuit( | |
339 TestTimeouts::action_max_timeout(), &exit_code)); | |
340 EXPECT_EQ(0, exit_code); // Expect a clean shutdown. | |
341 | |
342 browser_quit_time_ = base::TimeTicks::Now() - quit_start; | |
343 | |
344 // Ensure no child processes are left dangling. | |
345 TerminateAllChromeProcesses(processes); | |
346 } | |
347 | |
348 void ProxyLauncher::AssertAppNotRunning(const std::string& error_message) { | |
349 std::string final_error_message(error_message); | |
350 | |
351 ChromeProcessList processes = GetRunningChromeProcesses(process_id_); | |
352 if (!processes.empty()) { | |
353 final_error_message += " Leftover PIDs: ["; | |
354 for (ChromeProcessList::const_iterator it = processes.begin(); | |
355 it != processes.end(); ++it) { | |
356 final_error_message += base::StringPrintf(" %d", *it); | |
357 } | |
358 final_error_message += " ]"; | |
359 } | |
360 ASSERT_TRUE(processes.empty()) << final_error_message; | |
361 } | |
362 | |
363 bool ProxyLauncher::WaitForBrowserProcessToQuit( | |
364 base::TimeDelta timeout, | |
365 int* exit_code) { | |
366 #ifdef WAIT_FOR_DEBUGGER_ON_OPEN | |
367 timeout = base::TimeDelta::FromSeconds(500); | |
368 #endif | |
369 bool success = false; | |
370 | |
371 // Only wait for exit if the "browser, please terminate" message had a | |
372 // chance of making it through. | |
373 if (!automation_proxy_->channel_disconnected_on_failure()) | |
374 success = base::WaitForExitCodeWithTimeout(process_, exit_code, timeout); | |
375 | |
376 base::CloseProcessHandle(process_); | |
377 process_ = base::kNullProcessHandle; | |
378 process_id_ = -1; | |
379 | |
380 return success; | |
381 } | |
382 | |
383 void ProxyLauncher::PrepareTestCommandline(CommandLine* command_line, | |
384 bool include_testing_id) { | |
385 // Add any explicit command line flags passed to the process. | |
386 CommandLine::StringType extra_chrome_flags = | |
387 CommandLine::ForCurrentProcess()->GetSwitchValueNative( | |
388 switches::kExtraChromeFlags); | |
389 if (!extra_chrome_flags.empty()) { | |
390 // Split by spaces and append to command line. | |
391 std::vector<CommandLine::StringType> flags; | |
392 base::SplitStringAlongWhitespace(extra_chrome_flags, &flags); | |
393 for (size_t i = 0; i < flags.size(); ++i) | |
394 command_line->AppendArgNative(flags[i]); | |
395 } | |
396 | |
397 // Also look for extra flags in environment. | |
398 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
399 std::string extra_from_env; | |
400 if (env->GetVar("EXTRA_CHROME_FLAGS", &extra_from_env)) { | |
401 std::vector<std::string> flags; | |
402 base::SplitStringAlongWhitespace(extra_from_env, &flags); | |
403 for (size_t i = 0; i < flags.size(); ++i) | |
404 command_line->AppendArg(flags[i]); | |
405 } | |
406 | |
407 // No default browser check, it would create an info-bar (if we are not the | |
408 // default browser) that could conflicts with some tests expectations. | |
409 command_line->AppendSwitch(switches::kNoDefaultBrowserCheck); | |
410 | |
411 // This is a UI test. | |
412 command_line->AppendSwitchASCII(switches::kTestType, kUITestType); | |
413 | |
414 // Tell the browser to use a temporary directory just for this test | |
415 // if it is not already set. | |
416 if (command_line->GetSwitchValuePath(switches::kUserDataDir).empty()) { | |
417 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir()); | |
418 } | |
419 | |
420 if (include_testing_id) | |
421 command_line->AppendSwitchASCII(switches::kTestingChannelID, | |
422 PrefixedChannelID()); | |
423 | |
424 if (!show_error_dialogs_) | |
425 command_line->AppendSwitch(switches::kNoErrorDialogs); | |
426 if (no_sandbox_) | |
427 command_line->AppendSwitch(switches::kNoSandbox); | |
428 if (full_memory_dump_) | |
429 command_line->AppendSwitch(switches::kFullMemoryCrashReport); | |
430 if (silent_dump_on_dcheck_) | |
431 command_line->AppendSwitch(switches::kSilentDumpOnDCHECK); | |
432 if (disable_breakpad_) | |
433 command_line->AppendSwitch(switches::kDisableBreakpad); | |
434 | |
435 if (!js_flags_.empty()) | |
436 command_line->AppendSwitchASCII(switches::kJavaScriptFlags, js_flags_); | |
437 if (!log_level_.empty()) | |
438 command_line->AppendSwitchASCII(switches::kLoggingLevel, log_level_); | |
439 | |
440 command_line->AppendSwitch(switches::kMetricsRecordingOnly); | |
441 | |
442 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
443 switches::kEnableErrorDialogs)) | |
444 command_line->AppendSwitch(switches::kEnableLogging); | |
445 | |
446 #ifdef WAIT_FOR_DEBUGGER_ON_OPEN | |
447 command_line->AppendSwitch(switches::kDebugOnStart); | |
448 #endif | |
449 | |
450 // Force the app to always exit when the last browser window is closed. | |
451 command_line->AppendSwitch(switches::kDisableZeroBrowsersOpenForTests); | |
452 | |
453 // Allow file:// access on ChromeOS. | |
454 command_line->AppendSwitch(switches::kAllowFileAccess); | |
455 | |
456 // The tests assume that file:// URIs can freely access other file:// URIs. | |
457 command_line->AppendSwitch(switches::kAllowFileAccessFromFiles); | |
458 } | |
459 | |
460 bool ProxyLauncher::LaunchBrowserHelper(const LaunchState& state, | |
461 bool main_launch, | |
462 bool wait, | |
463 base::ProcessHandle* process) { | |
464 CommandLine command_line(state.command); | |
465 | |
466 // Add command line arguments that should be applied to all UI tests. | |
467 PrepareTestCommandline(&command_line, state.include_testing_id); | |
468 | |
469 // Sometimes one needs to run the browser under a special environment | |
470 // (e.g. valgrind) without also running the test harness (e.g. python) | |
471 // under the special environment. Provide a way to wrap the browser | |
472 // commandline with a special prefix to invoke the special environment. | |
473 const char* browser_wrapper = getenv("BROWSER_WRAPPER"); | |
474 if (browser_wrapper) { | |
475 #if defined(OS_WIN) | |
476 command_line.PrependWrapper(base::ASCIIToWide(browser_wrapper)); | |
477 #elif defined(OS_POSIX) | |
478 command_line.PrependWrapper(browser_wrapper); | |
479 #endif | |
480 VLOG(1) << "BROWSER_WRAPPER was set, prefixing command_line with " | |
481 << browser_wrapper; | |
482 } | |
483 | |
484 if (main_launch) | |
485 browser_launch_time_ = base::TimeTicks::Now(); | |
486 | |
487 base::LaunchOptions options; | |
488 options.wait = wait; | |
489 | |
490 #if defined(OS_WIN) | |
491 options.start_hidden = !state.show_window; | |
492 #elif defined(OS_POSIX) | |
493 base::ScopedFD ipcfd; | |
494 base::FileHandleMappingVector fds; | |
495 if (main_launch && automation_proxy_.get()) { | |
496 ipcfd.reset(automation_proxy_->channel()->TakeClientFileDescriptor()); | |
497 fds.push_back(std::make_pair(ipcfd.get(), | |
498 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); | |
499 options.fds_to_remap = &fds; | |
500 } | |
501 #endif | |
502 | |
503 return base::LaunchProcess(command_line, options, process); | |
504 } | |
505 | |
506 AutomationProxy* ProxyLauncher::automation() const { | |
507 EXPECT_TRUE(automation_proxy_.get()); | |
508 return automation_proxy_.get(); | |
509 } | |
510 | |
511 base::FilePath ProxyLauncher::user_data_dir() const { | |
512 EXPECT_TRUE(temp_profile_dir_.IsValid()); | |
513 return temp_profile_dir_.path(); | |
514 } | |
515 | |
516 base::ProcessHandle ProxyLauncher::process() const { | |
517 return process_; | |
518 } | |
519 | |
520 base::ProcessId ProxyLauncher::process_id() const { | |
521 return process_id_; | |
522 } | |
523 | |
524 base::TimeTicks ProxyLauncher::browser_launch_time() const { | |
525 return browser_launch_time_; | |
526 } | |
527 | |
528 base::TimeDelta ProxyLauncher::browser_quit_time() const { | |
529 return browser_quit_time_; | |
530 } | |
531 | |
532 // NamedProxyLauncher functions | |
533 | |
534 NamedProxyLauncher::NamedProxyLauncher(const std::string& channel_id, | |
535 bool launch_browser, | |
536 bool disconnect_on_failure) | |
537 : channel_id_(channel_id), | |
538 launch_browser_(launch_browser), | |
539 disconnect_on_failure_(disconnect_on_failure) { | |
540 } | |
541 | |
542 AutomationProxy* NamedProxyLauncher::CreateAutomationProxy( | |
543 base::TimeDelta execution_timeout) { | |
544 AutomationProxy* proxy = new AutomationProxy(execution_timeout, | |
545 disconnect_on_failure_); | |
546 proxy->InitializeChannel(channel_id_, true); | |
547 return proxy; | |
548 } | |
549 | |
550 bool NamedProxyLauncher::InitializeConnection(const LaunchState& state, | |
551 bool wait_for_initial_loads) { | |
552 if (launch_browser_) { | |
553 #if defined(OS_POSIX) | |
554 // Because we are waiting on the existence of the testing file below, | |
555 // make sure there isn't one already there before browser launch. | |
556 if (!base::DeleteFile(base::FilePath(channel_id_), false)) { | |
557 LOG(ERROR) << "Failed to delete " << channel_id_; | |
558 return false; | |
559 } | |
560 #endif | |
561 | |
562 if (!LaunchBrowser(state)) { | |
563 LOG(ERROR) << "Failed to LaunchBrowser"; | |
564 return false; | |
565 } | |
566 } | |
567 | |
568 // Wait for browser to be ready for connections. | |
569 bool channel_initialized = false; | |
570 base::TimeDelta sleep_time = base::TimeDelta::FromMilliseconds( | |
571 automation::kSleepTime); | |
572 for (base::TimeDelta wait_time = base::TimeDelta(); | |
573 wait_time < TestTimeouts::action_max_timeout(); | |
574 wait_time += sleep_time) { | |
575 channel_initialized = IPC::Channel::IsNamedServerInitialized(channel_id_); | |
576 if (channel_initialized) | |
577 break; | |
578 base::PlatformThread::Sleep(sleep_time); | |
579 } | |
580 if (!channel_initialized) { | |
581 LOG(ERROR) << "Failed to wait for testing channel presence."; | |
582 return false; | |
583 } | |
584 | |
585 if (!ConnectToRunningBrowser(wait_for_initial_loads)) { | |
586 LOG(ERROR) << "Failed to ConnectToRunningBrowser"; | |
587 return false; | |
588 } | |
589 return true; | |
590 } | |
591 | |
592 void NamedProxyLauncher::TerminateConnection() { | |
593 if (launch_browser_) | |
594 CloseBrowserAndServer(); | |
595 else | |
596 DisconnectFromRunningBrowser(); | |
597 } | |
598 | |
599 std::string NamedProxyLauncher::PrefixedChannelID() const { | |
600 std::string channel_id; | |
601 channel_id.append(automation::kNamedInterfacePrefix).append(channel_id_); | |
602 return channel_id; | |
603 } | |
604 | |
605 // AnonymousProxyLauncher functions | |
606 | |
607 AnonymousProxyLauncher::AnonymousProxyLauncher(bool disconnect_on_failure) | |
608 : disconnect_on_failure_(disconnect_on_failure) { | |
609 channel_id_ = AutomationProxy::GenerateChannelID(); | |
610 } | |
611 | |
612 AutomationProxy* AnonymousProxyLauncher::CreateAutomationProxy( | |
613 base::TimeDelta execution_timeout) { | |
614 AutomationProxy* proxy = new AutomationProxy(execution_timeout, | |
615 disconnect_on_failure_); | |
616 proxy->InitializeChannel(channel_id_, false); | |
617 return proxy; | |
618 } | |
619 | |
620 bool AnonymousProxyLauncher::InitializeConnection(const LaunchState& state, | |
621 bool wait_for_initial_loads) { | |
622 return LaunchBrowserAndServer(state, wait_for_initial_loads); | |
623 } | |
624 | |
625 void AnonymousProxyLauncher::TerminateConnection() { | |
626 CloseBrowserAndServer(); | |
627 } | |
628 | |
629 std::string AnonymousProxyLauncher::PrefixedChannelID() const { | |
630 return channel_id_; | |
631 } | |
OLD | NEW |