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

Side by Side Diff: chrome/test/chromedriver/chrome_launcher.cc

Issue 23643005: [chromedriver] Load the automation extension as a component extension. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 7 years, 3 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/test/chromedriver/chrome_launcher.h" 5 #include "chrome/test/chromedriver/chrome_launcher.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
(...skipping 26 matching lines...) Expand all
37 #include "chrome/test/chromedriver/chrome/user_data_dir.h" 37 #include "chrome/test/chromedriver/chrome/user_data_dir.h"
38 #include "chrome/test/chromedriver/chrome/version.h" 38 #include "chrome/test/chromedriver/chrome/version.h"
39 #include "chrome/test/chromedriver/chrome/web_view.h" 39 #include "chrome/test/chromedriver/chrome/web_view.h"
40 #include "chrome/test/chromedriver/chrome/zip.h" 40 #include "chrome/test/chromedriver/chrome/zip.h"
41 #include "chrome/test/chromedriver/net/net_util.h" 41 #include "chrome/test/chromedriver/net/net_util.h"
42 #include "chrome/test/chromedriver/net/url_request_context_getter.h" 42 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
43 #include "crypto/sha2.h" 43 #include "crypto/sha2.h"
44 44
45 namespace { 45 namespace {
46 46
47 const char* kCommonSwitches[] = {
48 "ignore-certificate-errors", "metrics-recording-only"};
49
50 Status UnpackAutomationExtension(const base::FilePath& temp_dir, 47 Status UnpackAutomationExtension(const base::FilePath& temp_dir,
51 base::FilePath* automation_extension) { 48 base::FilePath* automation_extension) {
52 std::string decoded_extension; 49 std::string decoded_extension;
53 if (!base::Base64Decode(kAutomationExtension, &decoded_extension)) 50 if (!base::Base64Decode(kAutomationExtension, &decoded_extension))
54 return Status(kUnknownError, "failed to base64decode automation extension"); 51 return Status(kUnknownError, "failed to base64decode automation extension");
55 52
56 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip"); 53 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip");
57 int size = static_cast<int>(decoded_extension.length()); 54 int size = static_cast<int>(decoded_extension.length());
58 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size) 55 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size)
59 != size) { 56 != size) {
60 return Status(kUnknownError, "failed to write automation extension zip"); 57 return Status(kUnknownError, "failed to write automation extension zip");
61 } 58 }
62 59
63 base::FilePath extension_dir = temp_dir.AppendASCII("internal"); 60 base::FilePath extension_dir = temp_dir.AppendASCII("internal");
64 if (!zip::Unzip(extension_zip, extension_dir)) 61 if (!zip::Unzip(extension_zip, extension_dir))
65 return Status(kUnknownError, "failed to unzip automation extension"); 62 return Status(kUnknownError, "failed to unzip automation extension");
66 63
67 *automation_extension = extension_dir; 64 *automation_extension = extension_dir;
68 return Status(kOk); 65 return Status(kOk);
69 } 66 }
70 67
71 void AddSwitches(CommandLine* command,
72 const char* switches[],
73 size_t switch_count,
74 const std::set<std::string>& exclude_switches) {
75 for (size_t i = 0; i < switch_count; ++i) {
76 if (exclude_switches.find(switches[i]) == exclude_switches.end())
77 command->AppendSwitch(switches[i]);
78 }
79 }
80
81 Status PrepareCommandLine(int port, 68 Status PrepareCommandLine(int port,
82 const Capabilities& capabilities, 69 const Capabilities& capabilities,
70 Switches* switches,
83 CommandLine* prepared_command, 71 CommandLine* prepared_command,
84 base::ScopedTempDir* user_data_dir, 72 base::ScopedTempDir* user_data_dir,
85 base::ScopedTempDir* extension_dir, 73 base::ScopedTempDir* extension_dir,
86 std::vector<std::string>* extension_bg_pages) { 74 std::vector<std::string>* extension_bg_pages) {
87 CommandLine command = capabilities.command; 75 base::FilePath program = capabilities.binary;
88 base::FilePath program = command.GetProgram();
89 if (program.empty()) { 76 if (program.empty()) {
90 if (!FindChrome(&program)) 77 if (!FindChrome(&program))
91 return Status(kUnknownError, "cannot find Chrome binary"); 78 return Status(kUnknownError, "cannot find Chrome binary");
92 command.SetProgram(program);
93 } else if (!base::PathExists(program)) { 79 } else if (!base::PathExists(program)) {
94 return Status(kUnknownError, 80 return Status(kUnknownError,
95 base::StringPrintf("no chrome binary at %" PRFilePath, 81 base::StringPrintf("no chrome binary at %" PRFilePath,
96 program.value().c_str())); 82 program.value().c_str()));
97 } 83 }
84 CommandLine command(program);
98 85
99 const char* excludable_switches[] = { 86 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported.
100 "disable-hang-monitor", 87 // For chrome 30-, it leads to crash when opening chrome://settings.
101 "disable-prompt-on-repost", 88 switches->SetSwitch("disable-hang-monitor");
102 "full-memory-crash-report", 89 switches->SetSwitch("disable-prompt-on-repost");
103 "no-first-run", 90 switches->SetSwitch("full-memory-crash-report");
104 "disable-background-networking", 91 switches->SetSwitch("no-first-run");
105 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported. 92 switches->SetSwitch("disable-background-networking");
106 // For chrome 30-, it leads to crash when opening chrome://settings. 93 switches->SetSwitch("disable-web-resources");
107 "disable-web-resources", 94 switches->SetSwitch("safebrowsing-disable-auto-update");
108 "safebrowsing-disable-auto-update", 95 switches->SetSwitch("safebrowsing-disable-download-protection");
109 "safebrowsing-disable-download-protection", 96 switches->SetSwitch("disable-client-side-phishing-detection");
110 "disable-client-side-phishing-detection", 97 switches->SetSwitch("disable-component-update");
111 "disable-component-update", 98 switches->SetSwitch("disable-default-apps");
112 "disable-default-apps", 99 switches->SetSwitch("enable-logging");
113 }; 100 switches->SetSwitch("logging-level", "1");
101 switches->SetSwitch("password-store", "basic");
102 switches->SetSwitch("use-mock-keychain");
103 switches->SetSwitch("remote-debugging-port", base::IntToString(port));
114 104
115 AddSwitches(&command, excludable_switches, arraysize(excludable_switches), 105 if (!switches->HasSwitch("user-data-dir")) {
116 capabilities.exclude_switches);
117 AddSwitches(&command, kCommonSwitches, arraysize(kCommonSwitches),
118 capabilities.exclude_switches);
119
120 command.AppendSwitch("enable-logging");
121 command.AppendSwitchASCII("logging-level", "1");
122 command.AppendSwitchASCII("password-store", "basic");
123 command.AppendSwitch("use-mock-keychain");
124 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
125
126 if (!command.HasSwitch("user-data-dir")) {
127 command.AppendArg("about:blank"); 106 command.AppendArg("about:blank");
128 if (!user_data_dir->CreateUniqueTempDir()) 107 if (!user_data_dir->CreateUniqueTempDir())
129 return Status(kUnknownError, "cannot create temp dir for user data dir"); 108 return Status(kUnknownError, "cannot create temp dir for user data dir");
130 command.AppendSwitchPath("user-data-dir", user_data_dir->path()); 109 command.AppendSwitchPath("user-data-dir", user_data_dir->path());
131 Status status = internal::PrepareUserDataDir( 110 Status status = internal::PrepareUserDataDir(
132 user_data_dir->path(), capabilities.prefs.get(), 111 user_data_dir->path(), capabilities.prefs.get(),
133 capabilities.local_state.get()); 112 capabilities.local_state.get());
134 if (status.IsError()) 113 if (status.IsError())
135 return status; 114 return status;
136 } 115 }
137 116
138 if (!extension_dir->CreateUniqueTempDir()) { 117 if (!extension_dir->CreateUniqueTempDir()) {
139 return Status(kUnknownError, 118 return Status(kUnknownError,
140 "cannot create temp dir for unpacking extensions"); 119 "cannot create temp dir for unpacking extensions");
141 } 120 }
142 Status status = internal::ProcessExtensions(capabilities.extensions, 121 Status status = internal::ProcessExtensions(capabilities.extensions,
143 extension_dir->path(), 122 extension_dir->path(),
144 true, 123 true,
145 &command, 124 switches,
146 extension_bg_pages); 125 extension_bg_pages);
147 if (status.IsError()) 126 if (status.IsError())
148 return status; 127 return status;
149 128
129 switches->SetFromSwitches(capabilities.switches);
chrisgao (Use stgao instead) 2013/08/30 02:12:55 including excludeSwitches, automation-extension mi
130 switches->AppendToCommandLine(&command);
150 *prepared_command = command; 131 *prepared_command = command;
151 return Status(kOk); 132 return Status(kOk);
152 } 133 }
153 134
154 Status WaitForDevToolsAndCheckVersion( 135 Status WaitForDevToolsAndCheckVersion(
155 const NetAddress& address, 136 const NetAddress& address,
156 URLRequestContextGetter* context_getter, 137 URLRequestContextGetter* context_getter,
157 const SyncWebSocketFactory& socket_factory, 138 const SyncWebSocketFactory& socket_factory,
158 Log* log, 139 Log* log,
159 scoped_ptr<DevToolsHttpClient>* user_client) { 140 scoped_ptr<DevToolsHttpClient>* user_client) {
(...skipping 23 matching lines...) Expand all
183 Status LaunchExistingChromeSession( 164 Status LaunchExistingChromeSession(
184 URLRequestContextGetter* context_getter, 165 URLRequestContextGetter* context_getter,
185 const SyncWebSocketFactory& socket_factory, 166 const SyncWebSocketFactory& socket_factory,
186 Log* log, 167 Log* log,
187 const Capabilities& capabilities, 168 const Capabilities& capabilities,
188 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 169 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
189 scoped_ptr<Chrome>* chrome) { 170 scoped_ptr<Chrome>* chrome) {
190 Status status(kOk); 171 Status status(kOk);
191 scoped_ptr<DevToolsHttpClient> devtools_client; 172 scoped_ptr<DevToolsHttpClient> devtools_client;
192 status = WaitForDevToolsAndCheckVersion( 173 status = WaitForDevToolsAndCheckVersion(
193 capabilities.use_existing_browser, context_getter, socket_factory, log, 174 capabilities.debugger_address, context_getter, socket_factory, log,
194 &devtools_client); 175 &devtools_client);
195 if (status.IsError()) { 176 if (status.IsError()) {
196 return Status(kUnknownError, "cannot connect to chrome at " + 177 return Status(kUnknownError, "cannot connect to chrome at " +
197 capabilities.use_existing_browser.ToString(), 178 capabilities.debugger_address.ToString(),
198 status); 179 status);
199 } 180 }
200 chrome->reset(new ChromeExistingImpl(devtools_client.Pass(), 181 chrome->reset(new ChromeExistingImpl(devtools_client.Pass(),
201 devtools_event_listeners, 182 devtools_event_listeners,
202 log)); 183 log));
203 return Status(kOk); 184 return Status(kOk);
204 } 185 }
205 186
206 Status LaunchDesktopChrome( 187 Status LaunchDesktopChrome(
207 URLRequestContextGetter* context_getter, 188 URLRequestContextGetter* context_getter,
208 int port, 189 int port,
209 const SyncWebSocketFactory& socket_factory, 190 const SyncWebSocketFactory& socket_factory,
210 Log* log, 191 Log* log,
211 const Capabilities& capabilities, 192 const Capabilities& capabilities,
193 Switches* switches,
212 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 194 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
213 scoped_ptr<Chrome>* chrome) { 195 scoped_ptr<Chrome>* chrome) {
214 CommandLine command(CommandLine::NO_PROGRAM); 196 CommandLine command(CommandLine::NO_PROGRAM);
215 base::ScopedTempDir user_data_dir; 197 base::ScopedTempDir user_data_dir;
216 base::ScopedTempDir extension_dir; 198 base::ScopedTempDir extension_dir;
217 std::vector<std::string> extension_bg_pages; 199 std::vector<std::string> extension_bg_pages;
218 Status status = PrepareCommandLine(port, 200 Status status = PrepareCommandLine(port,
219 capabilities, 201 capabilities,
202 switches,
220 &command, 203 &command,
221 &user_data_dir, 204 &user_data_dir,
222 &extension_dir, 205 &extension_dir,
223 &extension_bg_pages); 206 &extension_bg_pages);
224 if (status.IsError()) 207 if (status.IsError())
225 return status; 208 return status;
226 209
227 base::LaunchOptions options; 210 base::LaunchOptions options;
228 211
229 #if !defined(OS_WIN) 212 #if !defined(OS_WIN)
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 *chrome = chrome_desktop.Pass(); 290 *chrome = chrome_desktop.Pass();
308 return Status(kOk); 291 return Status(kOk);
309 } 292 }
310 293
311 Status LaunchAndroidChrome( 294 Status LaunchAndroidChrome(
312 URLRequestContextGetter* context_getter, 295 URLRequestContextGetter* context_getter,
313 int port, 296 int port,
314 const SyncWebSocketFactory& socket_factory, 297 const SyncWebSocketFactory& socket_factory,
315 Log* log, 298 Log* log,
316 const Capabilities& capabilities, 299 const Capabilities& capabilities,
300 Switches* switches,
317 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 301 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
318 DeviceManager* device_manager, 302 DeviceManager* device_manager,
319 scoped_ptr<Chrome>* chrome) { 303 scoped_ptr<Chrome>* chrome) {
320 Status status(kOk); 304 Status status(kOk);
321 scoped_ptr<Device> device; 305 scoped_ptr<Device> device;
322 if (capabilities.android_device_serial.empty()) { 306 if (capabilities.android_device_serial.empty()) {
323 status = device_manager->AcquireDevice(&device); 307 status = device_manager->AcquireDevice(&device);
324 } else { 308 } else {
325 status = device_manager->AcquireSpecificDevice( 309 status = device_manager->AcquireSpecificDevice(
326 capabilities.android_device_serial, &device); 310 capabilities.android_device_serial, &device);
327 } 311 }
328 if (!status.IsOk()) 312 if (!status.IsOk())
329 return status; 313 return status;
330 314
331 std::string args(capabilities.android_args); 315 switches->SetSwitch("disable-fre");
332 for (size_t i = 0; i < arraysize(kCommonSwitches); i++) 316 switches->SetSwitch("enable-remote-debugging");
333 args += "--" + std::string(kCommonSwitches[i]) + " ";
334 args += "--disable-fre --enable-remote-debugging";
335
336 status = device->StartApp(capabilities.android_package, 317 status = device->StartApp(capabilities.android_package,
337 capabilities.android_activity, 318 capabilities.android_activity,
338 capabilities.android_process, 319 capabilities.android_process,
339 args, port); 320 switches->ToString(), port);
340 if (!status.IsOk()) { 321 if (!status.IsOk()) {
341 device->StopApp(); 322 device->StopApp();
342 return status; 323 return status;
343 } 324 }
344 325
345 scoped_ptr<DevToolsHttpClient> devtools_client; 326 scoped_ptr<DevToolsHttpClient> devtools_client;
346 status = WaitForDevToolsAndCheckVersion(NetAddress(port), 327 status = WaitForDevToolsAndCheckVersion(NetAddress(port),
347 context_getter, 328 context_getter,
348 socket_factory, 329 socket_factory,
349 log, 330 log,
(...skipping 19 matching lines...) Expand all
369 if (capabilities.IsExistingBrowser()) { 350 if (capabilities.IsExistingBrowser()) {
370 return LaunchExistingChromeSession( 351 return LaunchExistingChromeSession(
371 context_getter, socket_factory, 352 context_getter, socket_factory,
372 log, capabilities, devtools_event_listeners, chrome); 353 log, capabilities, devtools_event_listeners, chrome);
373 } 354 }
374 355
375 int port; 356 int port;
376 if (!FindOpenPort(&port)) 357 if (!FindOpenPort(&port))
377 return Status(kUnknownError, "failed to find an open port for Chrome"); 358 return Status(kUnknownError, "failed to find an open port for Chrome");
378 359
360 Switches switches;
361 const char* kCommonSwitches[] = {
362 "ignore-certificate-errors", "metrics-recording-only"};
363 for (size_t i = 0; i < arraysize(kCommonSwitches); i++)
364 switches.SetSwitch(kCommonSwitches[i]);
365
379 if (capabilities.IsAndroid()) { 366 if (capabilities.IsAndroid()) {
380 return LaunchAndroidChrome( 367 return LaunchAndroidChrome(
381 context_getter, port, socket_factory, log, capabilities, 368 context_getter, port, socket_factory, log, capabilities,
382 devtools_event_listeners, device_manager, chrome); 369 &switches, devtools_event_listeners, device_manager, chrome);
383 } else { 370 } else {
384 return LaunchDesktopChrome( 371 return LaunchDesktopChrome(
385 context_getter, port, socket_factory, log, capabilities, 372 context_getter, port, socket_factory, log, capabilities,
386 devtools_event_listeners, chrome); 373 &switches, devtools_event_listeners, chrome);
387 } 374 }
388 } 375 }
389 376
390 namespace internal { 377 namespace internal {
391 378
392 void ConvertHexadecimalToIDAlphabet(std::string* id) { 379 void ConvertHexadecimalToIDAlphabet(std::string* id) {
393 for (size_t i = 0; i < id->size(); ++i) { 380 for (size_t i = 0; i < id->size(); ++i) {
394 int val; 381 int val;
395 if (base::HexStringToInt(base::StringPiece(id->begin() + i, 382 if (base::HexStringToInt(base::StringPiece(id->begin() + i,
396 id->begin() + i + 1), 383 id->begin() + i + 1),
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp); 480 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp);
494 if (status.IsError()) 481 if (status.IsError())
495 return status; 482 return status;
496 483
497 *path = extension_dir; 484 *path = extension_dir;
498 if (bg_page_tmp.size()) 485 if (bg_page_tmp.size())
499 *bg_page = bg_page_tmp; 486 *bg_page = bg_page_tmp;
500 return Status(kOk); 487 return Status(kOk);
501 } 488 }
502 489
490 void UpdateExtensionSwitch(Switches* switches,
491 const char name[],
492 const base::FilePath::StringType& extension) {
493 base::FilePath::StringType value = switches->GetSwitchValueNative(name);
494 if (value.length())
495 value += FILE_PATH_LITERAL(",");
496 value += extension;
497 switches->SetSwitch(name, value);
498 }
499
503 Status ProcessExtensions(const std::vector<std::string>& extensions, 500 Status ProcessExtensions(const std::vector<std::string>& extensions,
504 const base::FilePath& temp_dir, 501 const base::FilePath& temp_dir,
505 bool include_automation_extension, 502 bool include_automation_extension,
506 CommandLine* command, 503 Switches* switches,
507 std::vector<std::string>* bg_pages) { 504 std::vector<std::string>* bg_pages) {
508 std::vector<std::string> bg_pages_tmp; 505 std::vector<std::string> bg_pages_tmp;
509 std::vector<base::FilePath::StringType> extension_paths; 506 std::vector<base::FilePath::StringType> extension_paths;
510 for (size_t i = 0; i < extensions.size(); ++i) { 507 for (size_t i = 0; i < extensions.size(); ++i) {
511 base::FilePath path; 508 base::FilePath path;
512 std::string bg_page; 509 std::string bg_page;
513 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page); 510 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page);
514 if (status.IsError()) { 511 if (status.IsError()) {
515 return Status( 512 return Status(
516 kUnknownError, 513 kUnknownError,
517 base::StringPrintf("cannot process extension #%" PRIuS, i + 1), 514 base::StringPrintf("cannot process extension #%" PRIuS, i + 1),
518 status); 515 status);
519 } 516 }
520 extension_paths.push_back(path.value()); 517 extension_paths.push_back(path.value());
521 if (bg_page.length()) 518 if (bg_page.length())
522 bg_pages_tmp.push_back(bg_page); 519 bg_pages_tmp.push_back(bg_page);
523 } 520 }
524 521
525 if (include_automation_extension) { 522 if (include_automation_extension) {
526 base::FilePath automation_extension; 523 base::FilePath automation_extension;
527 Status status = UnpackAutomationExtension(temp_dir, &automation_extension); 524 Status status = UnpackAutomationExtension(temp_dir, &automation_extension);
528 if (status.IsError()) 525 if (status.IsError())
529 return status; 526 return status;
530 if (command->HasSwitch("disable-extensions")) { 527 if (switches->HasSwitch("disable-extensions")) {
531 command->AppendSwitchNative("load-component-extension", 528 UpdateExtensionSwitch(switches, "load-component-extension",
532 automation_extension.value()); 529 automation_extension.value());
533 } else { 530 } else {
534 extension_paths.push_back(automation_extension.value()); 531 extension_paths.push_back(automation_extension.value());
535 } 532 }
536 } 533 }
537 534
538 if (extension_paths.size()) { 535 if (extension_paths.size()) {
539 base::FilePath::StringType extension_paths_value = JoinString( 536 base::FilePath::StringType extension_paths_value = JoinString(
540 extension_paths, FILE_PATH_LITERAL(',')); 537 extension_paths, FILE_PATH_LITERAL(','));
541 command->AppendSwitchNative("load-extension", extension_paths_value); 538 UpdateExtensionSwitch(switches, "load-extension", extension_paths_value);
542 } 539 }
543 bg_pages->swap(bg_pages_tmp); 540 bg_pages->swap(bg_pages_tmp);
544 return Status(kOk); 541 return Status(kOk);
545 } 542 }
546 543
547 Status WritePrefsFile( 544 Status WritePrefsFile(
548 const std::string& template_string, 545 const std::string& template_string,
549 const base::DictionaryValue* custom_prefs, 546 const base::DictionaryValue* custom_prefs,
550 const base::FilePath& path) { 547 const base::FilePath& path) {
551 int code; 548 int code;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 // Write empty "First Run" file, otherwise Chrome will wipe the default 596 // Write empty "First Run" file, otherwise Chrome will wipe the default
600 // profile that was written. 597 // profile that was written.
601 if (file_util::WriteFile( 598 if (file_util::WriteFile(
602 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { 599 user_data_dir.AppendASCII("First Run"), "", 0) != 0) {
603 return Status(kUnknownError, "failed to write first run file"); 600 return Status(kUnknownError, "failed to write first run file");
604 } 601 }
605 return Status(kOk); 602 return Status(kOk);
606 } 603 }
607 604
608 } // namespace internal 605 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/chrome_launcher.h ('k') | chrome/test/chromedriver/chrome_launcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698