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_frame/test/net/fake_external_tab.h" 6 7 #include <atlbase.h> 8 #include <atlcom.h> 9 #include <exdisp.h> 10 #include <Winsock2.h> 11 12 #include "base/bind.h" 13 #include "base/command_line.h" 14 #include "base/debug/debugger.h" 15 #include "base/file_util.h" 16 #include "base/file_version_info.h" 17 #include "base/files/scoped_temp_dir.h" 18 #include "base/i18n/icu_util.h" 19 #include "base/lazy_instance.h" 20 #include "base/memory/scoped_ptr.h" 21 #include "base/path_service.h" 22 #include "base/prefs/json_pref_store.h" 23 #include "base/prefs/pref_registry_simple.h" 24 #include "base/prefs/pref_service.h" 25 #include "base/strings/string_piece.h" 26 #include "base/strings/string_util.h" 27 #include "base/strings/stringprintf.h" 28 #include "base/system_monitor/system_monitor.h" 29 #include "base/test/test_timeouts.h" 30 #include "base/threading/platform_thread.h" 31 #include "base/threading/thread.h" 32 #include "base/win/scoped_comptr.h" 33 #include "base/win/scoped_handle.h" 34 #include "chrome/app/chrome_main_delegate.h" 35 #include "chrome/browser/automation/automation_provider_list.h" 36 #include "chrome/browser/chrome_content_browser_client.h" 37 #include "chrome/browser/prefs/browser_prefs.h" 38 #include "chrome/browser/prefs/proxy_config_dictionary.h" 39 #include "chrome/browser/process_singleton.h" 40 #include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h" 41 #include "chrome/browser/profiles/profile_manager.h" 42 #include "chrome/browser/profiles/profiles_state.h" 43 #include "chrome/browser/renderer_host/web_cache_manager.h" 44 #include "chrome/common/chrome_constants.h" 45 #include "chrome/common/chrome_content_client.h" 46 #include "chrome/common/chrome_paths.h" 47 #include "chrome/common/chrome_paths_internal.h" 48 #include "chrome/common/chrome_switches.h" 49 #include "chrome/common/pref_names.h" 50 #include "chrome/renderer/chrome_content_renderer_client.h" 51 #include "chrome/test/base/ui_test_utils.h" 52 #include "chrome/test/logging/win/file_logger.h" 53 #include "chrome/test/logging/win/log_file_printer.h" 54 #include "chrome/test/logging/win/test_log_collector.h" 55 #include "chrome_frame/crash_server_init.h" 56 #include "chrome_frame/test/chrome_frame_test_utils.h" 57 #include "chrome_frame/test/ie_configurator.h" 58 #include "chrome_frame/test/net/test_automation_resource_message_filter.h" 59 #include "chrome_frame/test/simulate_input.h" 60 #include "chrome_frame/test/win_event_receiver.h" 61 #include "chrome_frame/utils.h" 62 #include "content/public/app/content_main.h" 63 #include "content/public/app/startup_helper_win.h" 64 #include "content/public/browser/browser_thread.h" 65 #include "content/public/browser/notification_service.h" 66 #include "content/public/browser/render_process_host.h" 67 #include "content/public/common/content_client.h" 68 #include "content/public/common/content_paths.h" 69 #include "net/base/net_util.h" 70 #include "net/url_request/url_request_test_util.h" 71 #include "sandbox/win/src/sandbox_types.h" 72 #include "testing/gtest/include/gtest/gtest.h" 73 #include "ui/base/resource/resource_bundle.h" 74 #include "ui/base/resource/resource_bundle_win.h" 75 #include "ui/base/ui_base_paths.h" 76 77 #if defined(USE_AURA) 78 #include "ui/gfx/screen.h" 79 #include "ui/views/widget/desktop_aura/desktop_screen.h" 80 #endif 81 82 using content::BrowserThread; 83 84 namespace { 85 86 // We must store this globally so that our main delegate can set it. 87 static CFUrlRequestUnittestRunner* g_test_suite = NULL; 88 89 // Copied here for access by CreateBrowserMainParts and InitGoogleTest. 90 static int g_argc = 0; 91 static char** g_argv = NULL; 92 93 // A special command line switch to allow developers to manually launch the 94 // browser and debug CF inside the browser. 95 const char kManualBrowserLaunch[] = "manual-browser"; 96 97 // Pops up a message box after the test environment has been set up 98 // and before tearing it down. Useful for when debugging tests and not 99 // the test environment that's been set up. 100 const char kPromptAfterSetup[] = "prompt-after-setup"; 101 102 const int kTestServerPort = 4666; 103 // The test HTML we use to initialize Chrome Frame. 104 // Note that there's a little trick in there to avoid an extra URL request 105 // that the browser will otherwise make for the site's favicon. 106 // If we don't do this the browser will create a new URL request after 107 // the CF page has been initialized and that URL request will confuse the 108 // global URL instance counter in the unit tests and subsequently trip 109 // some DCHECKs. 110 const char kChromeFrameHtml[] = "<html><head>" 111 "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />" 112 "<link rel=\"shortcut icon\" href=\"file://c:\\favicon.ico\"/>" 113 "</head><body>Chrome Frame should now be loaded</body></html>"; 114 115 // Uses the IAccessible interface for the window to set the focus. 116 // This can be useful when you don't have control over the thread that 117 // owns the window. 118 // NOTE: this depends on oleacc.lib which the net tests already depend on 119 // but other unit tests don't depend on oleacc so we can't just add the method 120 // directly into chrome_frame_test_utils.cc (without adding a 121 // #pragma comment(lib, "oleacc.lib")). 122 bool SetFocusToAccessibleWindow(HWND hwnd) { 123 bool ret = false; 124 base::win::ScopedComPtr<IAccessible> acc; 125 AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, 126 reinterpret_cast<void**>(acc.Receive())); 127 if (acc) { 128 VARIANT self = { VT_I4 }; 129 self.lVal = CHILDID_SELF; 130 ret = SUCCEEDED(acc->accSelect(SELFLAG_TAKEFOCUS, self)); 131 } 132 return ret; 133 } 134 135 class FakeContentBrowserClient : public chrome::ChromeContentBrowserClient { 136 public: 137 virtual ~FakeContentBrowserClient() {} 138 139 virtual content::BrowserMainParts* CreateBrowserMainParts( 140 const content::MainFunctionParams& parameters) OVERRIDE; 141 }; 142 143 base::LazyInstance<chrome::ChromeContentClient> 144 g_chrome_content_client = LAZY_INSTANCE_INITIALIZER; 145 146 // Override the default ContentBrowserClient to let Chrome participate in 147 // content logic. Must be done before any tabs are created. 148 base::LazyInstance<FakeContentBrowserClient> 149 g_browser_client = LAZY_INSTANCE_INITIALIZER; 150 151 base::LazyInstance<chrome::ChromeContentRendererClient> 152 g_renderer_client = LAZY_INSTANCE_INITIALIZER; 153 154 class FakeMainDelegate : public content::ContentMainDelegate { 155 public: 156 virtual ~FakeMainDelegate() {} 157 158 virtual bool BasicStartupComplete(int* exit_code) OVERRIDE { 159 logging_win::InstallTestLogCollector( 160 testing::UnitTest::GetInstance()); 161 162 content::SetContentClient(&g_chrome_content_client.Get()); 163 content::SetRendererClientForTesting(&g_renderer_client.Get()); 164 return false; 165 } 166 167 // Override the default ContentBrowserClient to let Chrome participate in 168 // content logic. We use a subclass of Chrome's implementation, 169 // FakeContentBrowserClient, to override CreateBrowserMainParts. Must 170 // be done before any tabs are created. 171 virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE { 172 return &g_browser_client.Get(); 173 }; 174 }; 175 176 void FilterDisabledTests() { 177 if (::testing::FLAGS_gtest_filter.length() && 178 ::testing::FLAGS_gtest_filter != "*") { 179 // Don't override user specified filters. 180 return; 181 } 182 183 const char* disabled_tests[] = { 184 // Tests disabled since they're testing the same functionality used 185 // by the TestAutomationProvider. 186 "URLRequestTest.Intercept", 187 "URLRequestTest.InterceptNetworkError", 188 "URLRequestTest.InterceptRestartRequired", 189 "URLRequestTest.InterceptRespectsCancelMain", 190 "URLRequestTest.InterceptRespectsCancelRedirect", 191 "URLRequestTest.InterceptRespectsCancelFinal", 192 "URLRequestTest.InterceptRespectsCancelInRestart", 193 "URLRequestTest.InterceptRedirect", 194 "URLRequestTest.InterceptServerError", 195 "URLRequestTestFTP.*", 196 197 // Tests that are currently not working: 198 199 // Temporarily disabled because they needs user input (login dialog). 200 "URLRequestTestHTTP.BasicAuth", 201 "URLRequestTestHTTP.BasicAuthWithCookies", 202 203 // ChromeFrame does not support load timing. 204 "URLRequestTestHTTP.BasicAuthLoadTiming", 205 "URLRequestTestHTTP.GetTestLoadTiming", 206 "URLRequestTestHTTP.RedirectLoadTiming", 207 208 // HTTPS tests temporarily disabled due to the certificate error dialog. 209 // TODO(tommi): The tests currently fail though, so need to fix. 210 "HTTPSRequestTest.HTTPSMismatchedTest", 211 "HTTPSRequestTest.HTTPSExpiredTest", 212 "HTTPSRequestTest.ClientAuthTest", 213 214 // More HTTPS tests failing due to certificate dialogs. 215 // http://crbug.com/102991 216 "URLRequestTestHTTP.HTTPSToHTTPRedirectNoRefererTest", 217 "HTTPSRequestTest.HTTPSGetTest", 218 219 // Tests chrome's network stack's cache (might not apply to CF). 220 "URLRequestTestHTTP.VaryHeader", 221 "URLRequestTestHTTP.GetZippedTest", 222 223 // Tests that requests can be blocked asynchronously in states 224 // OnBeforeURLRequest, OnBeforeSendHeaders and OnHeadersReceived. At least 225 // the second state is not supported by CF. 226 "URLRequestTestHTTP.NetworkDelegateBlockAsynchronously", 227 228 // Tests for cancelling requests in states OnBeforeSendHeaders and 229 // OnHeadersReceived, which do not seem supported by CF. 230 "URLRequestTestHTTP.NetworkDelegateCancelRequestSynchronously2", 231 "URLRequestTestHTTP.NetworkDelegateCancelRequestSynchronously3", 232 "URLRequestTestHTTP.NetworkDelegateCancelRequestAsynchronously2", 233 "URLRequestTestHTTP.NetworkDelegateCancelRequestAsynchronously3", 234 235 // Tests that requests can be cancelled while blocking in 236 // OnBeforeSendHeaders state. But this state is not supported by CF. 237 "URLRequestTestHTTP.NetworkDelegateCancelWhileWaiting2", 238 239 // Tests that requests can be cancelled while blocking in 240 // OnHeadersRecevied state. At first glance, this state does not appear to 241 // be supported by CF. 242 "URLRequestTestHTTP.NetworkDelegateCancelWhileWaiting3", 243 244 // Tests that requests can be cancelled while blocking in OnAuthRequired 245 // state. At first glance, this state does not appear to be supported by CF. 246 // IE displays a credentials prompt during this test - I (erikwright) 247 // believe that, from Chrome's point of view this is not a state change. In 248 // any case, I also believe that we do not have support for handling the 249 // credentials dialog during tests. 250 "URLRequestTestHTTP.NetworkDelegateCancelWhileWaiting4", 251 252 // I suspect we can only get this one to work (if at all) on IE8 and 253 // later by using the new INTERNET_OPTION_SUPPRESS_BEHAVIOR flags 254 // See http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx 255 "URLRequestTest.DoNotSaveCookies", 256 "URLRequestTest.DelayedCookieCallback", 257 258 // TODO(ananta): This test has been consistently failing. Disabling it for 259 // now. 260 "URLRequestTestHTTP.GetTest_NoCache", 261 262 // These tests use HTTPS, and IE's trust store does not have the test 263 // certs. So these tests time out waiting for user input. The 264 // functionality they test (HTTP Strict Transport Security and 265 // HTTP-based Public Key Pinning) does not work in Chrome Frame anyway. 266 "URLRequestTestHTTP.ProcessPKP", 267 "URLRequestTestHTTP.ProcessSTS", 268 "URLRequestTestHTTP.ProcessSTSOnce", 269 "URLRequestTestHTTP.ProcessSTSAndPKP", 270 "URLRequestTestHTTP.ProcessSTSAndPKP2", 271 272 // These tests have been disabled as the Chrome cookie policies don't make 273 // sense or have not been implemented for the host network stack. 274 "URLRequestTest.DoNotSaveCookies_ViaPolicy", 275 "URLRequestTest.DoNotSendCookies_ViaPolicy", 276 "URLRequestTest.DoNotSaveCookies_ViaPolicy_Async", 277 "URLRequestTest.CookiePolicy_ForceSession", 278 "URLRequestTest.DoNotSendCookies", 279 "URLRequestTest.DoNotSendCookies_ViaPolicy_Async", 280 "URLRequestTest.CancelTest_During_OnGetCookies", 281 "URLRequestTest.CancelTest_During_OnSetCookie", 282 283 // These tests are disabled as they rely on functionality provided by 284 // Chrome's HTTP stack like the ability to set the proxy for a URL, etc. 285 "URLRequestTestHTTP.ProxyTunnelRedirectTest", 286 "URLRequestTestHTTP.NetworkDelegateTunnelConnectionFailed", 287 "URLRequestTestHTTP.UnexpectedServerAuthTest", 288 289 // These tests are disabled as they expect an empty UA to be echoed back 290 // from the server which is not the case in ChromeFrame. 291 "URLRequestTestHTTP.DefaultUserAgent", 292 "URLRequestTestHTTP.EmptyHttpUserAgentSettings", 293 // This test modifies the UploadData object after it has been marshaled to 294 // ChromeFrame. We don't support this. 295 "URLRequestTestHTTP.TestPostChunkedDataAfterStart", 296 297 // Do not work in CF, it may well be that IE is unconditionally 298 // adding Accept-Encoding header by default to outgoing requests. 299 "URLRequestTestHTTP.DefaultAcceptEncoding", 300 "URLRequestTestHTTP.OverrideAcceptEncoding", 301 302 // Not supported in ChromeFrame as we use IE's network stack. 303 "URLRequestTest.NetworkDelegateProxyError", 304 "URLRequestTest.AcceptClockSkewCookieWithWrongDateTimezone", 305 306 // URLRequestAutomationJob needs to support NeedsAuth. 307 // http://crbug.com/98446 308 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncNoAction", 309 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncSetAuth", 310 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncCancel", 311 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncNoAction", 312 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncSetAuth", 313 "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncCancel", 314 315 // Flaky on the tryservers, http://crbug.com/103097 316 "URLRequestTestHTTP.MultipleRedirectTest", 317 "URLRequestTestHTTP.NetworkDelegateRedirectRequest", 318 319 // These tests are unsupported in CF. 320 "HTTPSRequestTest.HTTPSPreloadedHSTSTest", 321 "HTTPSRequestTest.HTTPSErrorsNoClobberTSSTest", 322 "HTTPSRequestTest.HSTSPreservesPosts", 323 "HTTPSRequestTest.ResumeTest", 324 "HTTPSRequestTest.SSLSessionCacheShardTest", 325 "HTTPSRequestTest.SSLSessionCacheShardTest", 326 "HTTPSRequestTest.SSLv3Fallback", 327 "HTTPSRequestTest.TLSv1Fallback", 328 "HTTPSHardFailTest.*", 329 "HTTPSOCSPTest.*", 330 "HTTPSEVCRLSetTest.*", 331 "HTTPSCRLSetTest.*", 332 333 // Chrome Frame doesn't support GetFullRequestHeaders. 334 "URLRequestTest*.*_GetFullRequestHeaders" 335 }; 336 337 const char* ie9_disabled_tests[] = { 338 // These always hang on Joi's box with IE9, http://crbug.com/105435. 339 // Several other tests, e.g. URLRequestTestHTTP.CancelTest2, 3 and 340 // 5, often hang but not always. 341 "URLRequestTestHTTP.NetworkDelegateRedirectRequestPost", 342 "URLRequestTestHTTP.GetTest", 343 "HTTPSRequestTest.HTTPSPreloadedHSTSTest", 344 // This always hangs on erikwright's box with IE9. 345 "URLRequestTestHTTP.Redirect302Tests" 346 }; 347 348 std::string filter("-"); // All following filters will be negative. 349 for (int i = 0; i < arraysize(disabled_tests); ++i) { 350 if (i > 0) 351 filter += ":"; 352 353 // If the rule has the form TestSuite.TestCase, also filter out 354 // TestSuite.FLAKY_TestCase . This way the exclusion rules above 355 // don't need to be updated when a test is marked flaky. 356 base::StringPiece test_name(disabled_tests[i]); 357 size_t dot_index = test_name.find('.'); 358 if (dot_index != base::StringPiece::npos && 359 dot_index + 1 < test_name.size()) { 360 test_name.substr(0, dot_index).AppendToString(&filter); 361 filter += ".FLAKY_"; 362 test_name.substr(dot_index + 1).AppendToString(&filter); 363 filter += ":"; 364 } 365 filter += disabled_tests[i]; 366 } 367 368 if (chrome_frame_test::GetInstalledIEVersion() >= IE_9) { 369 for (int i = 0; i < arraysize(ie9_disabled_tests); ++i) { 370 filter += ":"; 371 filter += ie9_disabled_tests[i]; 372 } 373 } 374 375 ::testing::FLAGS_gtest_filter = filter; 376 } 377 378 } // namespace 379 380 // Same as BrowserProcessImpl, but uses custom profile manager. 381 class FakeBrowserProcessImpl : public BrowserProcessImpl { 382 public: 383 FakeBrowserProcessImpl(base::SequencedTaskRunner* local_state_task_runner, 384 const CommandLine& command_line) 385 : BrowserProcessImpl(local_state_task_runner, command_line) { 386 profiles_dir_.CreateUniqueTempDir(); 387 } 388 389 virtual ~FakeBrowserProcessImpl() {} 390 391 virtual ProfileManager* profile_manager() OVERRIDE { 392 if (!profile_manager_.get()) { 393 profile_manager_.reset( 394 new ProfileManagerWithoutInit(profiles_dir_.path())); 395 } 396 return profile_manager_.get(); 397 } 398 399 virtual MetricsService* metrics_service() OVERRIDE { 400 return NULL; 401 } 402 403 void DestroyProfileManager() { 404 profile_manager_.reset(); 405 } 406 407 private: 408 base::ScopedTempDir profiles_dir_; 409 scoped_ptr<ProfileManager> profile_manager_; 410 }; 411 412 class SupplyProxyCredentials : public WindowObserver { 413 public: 414 SupplyProxyCredentials(const char* username, const char* password); 415 416 protected: 417 struct DialogProps { 418 HWND username_; 419 HWND password_; 420 }; 421 422 virtual void OnWindowOpen(HWND hwnd); 423 virtual void OnWindowClose(HWND hwnd); 424 static BOOL CALLBACK EnumChildren(HWND hwnd, LPARAM param); 425 426 protected: 427 std::string username_; 428 std::string password_; 429 }; 430 431 432 SupplyProxyCredentials::SupplyProxyCredentials(const char* username, 433 const char* password) 434 : username_(username), password_(password) { 435 } 436 437 void SupplyProxyCredentials::OnWindowClose(HWND hwnd) { } 438 439 void SupplyProxyCredentials::OnWindowOpen(HWND hwnd) { 440 DialogProps props = {0}; 441 ::EnumChildWindows(hwnd, EnumChildren, reinterpret_cast<LPARAM>(&props)); 442 DCHECK(::IsWindow(props.username_)); 443 DCHECK(::IsWindow(props.password_)); 444 445 // We can't use SetWindowText to set the username/password, so simulate 446 // keyboard input instead. 447 simulate_input::ForceSetForegroundWindow(hwnd); 448 CHECK(SetFocusToAccessibleWindow(props.username_)); 449 simulate_input::SendStringA(username_.c_str()); 450 Sleep(100); 451 452 simulate_input::SendCharA(VK_TAB, simulate_input::NONE); 453 Sleep(100); 454 simulate_input::SendStringA(password_.c_str()); 455 456 Sleep(100); 457 simulate_input::SendCharA(VK_RETURN, simulate_input::NONE); 458 } 459 460 // static 461 BOOL SupplyProxyCredentials::EnumChildren(HWND hwnd, LPARAM param) { 462 if (!::IsWindowVisible(hwnd)) 463 return TRUE; // Ignore but continue to enumerate. 464 465 DialogProps* props = reinterpret_cast<DialogProps*>(param); 466 467 char class_name[MAX_PATH] = {0}; 468 ::GetClassNameA(hwnd, class_name, arraysize(class_name)); 469 if (lstrcmpiA(class_name, "Edit") == 0) { 470 if (props->username_ == NULL || props->username_ == hwnd) { 471 props->username_ = hwnd; 472 } else if (props->password_ == NULL) { 473 props->password_ = hwnd; 474 } 475 } else { 476 EnumChildWindows(hwnd, EnumChildren, param); 477 } 478 479 return TRUE; 480 } 481 482 FakeExternalTab::FakeExternalTab() { 483 user_data_dir_ = chrome_frame_test::GetProfilePathForIE(); 484 485 if (base::PathExists(user_data_dir_)) { 486 VLOG(1) << __FUNCTION__ << " deleting IE Profile user data directory " 487 << user_data_dir_.value(); 488 bool deleted = base::DeleteFile(user_data_dir_, true); 489 LOG_IF(ERROR, !deleted) << "Failed to delete user data directory directory " 490 << user_data_dir_.value(); 491 } 492 493 PathService::Get(chrome::DIR_USER_DATA, &overridden_user_dir_); 494 PathService::Override(chrome::DIR_USER_DATA, user_data_dir_); 495 } 496 497 FakeExternalTab::~FakeExternalTab() { 498 if (!overridden_user_dir_.empty()) { 499 PathService::Override(chrome::DIR_USER_DATA, overridden_user_dir_); 500 } 501 } 502 503 void FakeExternalTab::Initialize() { 504 DCHECK(g_browser_process == NULL); 505 506 TestTimeouts::Initialize(); 507 508 // Load Chrome.dll as our resource dll. 509 base::FilePath dll; 510 PathService::Get(base::DIR_MODULE, &dll); 511 dll = dll.Append(chrome::kBrowserResourcesDll); 512 HMODULE res_mod = ::LoadLibraryExW(dll.value().c_str(), 513 NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); 514 DCHECK(res_mod); 515 _AtlBaseModule.SetResourceInstance(res_mod); 516 517 // Point the ResourceBundle at chrome.dll. 518 ui::SetResourcesDataDLL(_AtlBaseModule.GetResourceInstance()); 519 520 ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL); 521 522 CommandLine* cmd = CommandLine::ForCurrentProcess(); 523 cmd->AppendSwitch(switches::kDisableWebResources); 524 cmd->AppendSwitch(switches::kSingleProcess); 525 526 base::FilePath local_state_path; 527 CHECK(PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path)); 528 scoped_refptr<base::SequencedTaskRunner> local_state_task_runner = 529 JsonPrefStore::GetTaskRunnerForFile(local_state_path, 530 BrowserThread::GetBlockingPool()); 531 browser_process_.reset(new FakeBrowserProcessImpl(local_state_task_runner, 532 *cmd)); 533 // BrowserProcessImpl's constructor should set g_browser_process. 534 DCHECK(g_browser_process); 535 g_browser_process->SetApplicationLocale("en-US"); 536 537 content::RenderProcessHost::SetRunRendererInProcess(true); 538 539 // TODO(joi): Registration should be done up front via browser_prefs.cc 540 scoped_refptr<PrefRegistrySimple> registry = static_cast<PrefRegistrySimple*>( 541 browser_process_->local_state()->DeprecatedGetPrefRegistry()); 542 if (!browser_process_->local_state()->FindPreference( 543 prefs::kMetricsReportingEnabled)) { 544 registry->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false); 545 } 546 } 547 548 void FakeExternalTab::InitializePostThreadsCreated() { 549 #if defined(USE_AURA) 550 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, 551 views::CreateDesktopScreen()); 552 #endif 553 base::FilePath profile_path( 554 profiles::GetDefaultProfileDir(user_data())); 555 Profile* profile = 556 g_browser_process->profile_manager()->GetProfile(profile_path); 557 } 558 559 void FakeExternalTab::Shutdown() { 560 browser_process_.reset(); 561 g_browser_process = NULL; 562 563 ResourceBundle::CleanupSharedInstance(); 564 } 565 566 FakeBrowserProcessImpl* FakeExternalTab::browser_process() const { 567 return browser_process_.get(); 568 } 569 570 CFUrlRequestUnittestRunner::CFUrlRequestUnittestRunner(int argc, char** argv) 571 : NetTestSuite(argc, argv, false), 572 chrome_frame_html_("/chrome_frame", kChromeFrameHtml), 573 registrar_(chrome_frame_test::GetTestBedType()), 574 test_result_(0), 575 launch_browser_( 576 !CommandLine::ForCurrentProcess()->HasSwitch(kManualBrowserLaunch)), 577 prompt_after_setup_( 578 CommandLine::ForCurrentProcess()->HasSwitch(kPromptAfterSetup)), 579 tests_ran_(false) { 580 } 581 582 CFUrlRequestUnittestRunner::~CFUrlRequestUnittestRunner() { 583 } 584 585 void CFUrlRequestUnittestRunner::StartChromeFrameInHostBrowser() { 586 if (!launch_browser_) 587 return; 588 589 chrome_frame_test::CloseAllIEWindows(); 590 591 // Tweak IE settings to make it amenable to testing before launching it. 592 ie_configurator_.reset(chrome_frame_test::CreateConfigurator()); 593 if (ie_configurator_.get() != NULL) { 594 ie_configurator_->Initialize(); 595 ie_configurator_->ApplySettings(); 596 } 597 598 test_http_server_.reset(new test_server::SimpleWebServer("127.0.0.1", 599 kTestServerPort)); 600 test_http_server_->AddResponse(&chrome_frame_html_); 601 std::wstring url(base::StringPrintf(L"http://localhost:%i/chrome_frame", 602 kTestServerPort)); 603 604 // Launch IE. This launches IE correctly on Vista too. 605 base::win::ScopedHandle ie_process(chrome_frame_test::LaunchIE(url)); 606 EXPECT_TRUE(ie_process.IsValid()); 607 608 // NOTE: If you're running IE8 and CF is not being loaded, you need to 609 // disable IE8's prebinding until CF properly handles that situation. 610 // 611 // HKCU\Software\Microsoft\Internet Explorer\Main 612 // Value name: EnablePreBinding (REG_DWORD) 613 // Value: 0 614 } 615 616 void CFUrlRequestUnittestRunner::ShutDownHostBrowser() { 617 if (launch_browser_) 618 chrome_frame_test::CloseAllIEWindows(); 619 } 620 621 void CFUrlRequestUnittestRunner::OnIEShutdownFailure() { 622 LOG(ERROR) << "Failed to shutdown IE and npchrome_frame cleanly after test " 623 "execution."; 624 625 if (ie_configurator_.get() != NULL) 626 ie_configurator_->RevertSettings(); 627 628 StopFileLogger(true); 629 ::ExitProcess(0); 630 } 631 632 // Override virtual void Initialize to not call icu initialize. 633 void CFUrlRequestUnittestRunner::Initialize() { 634 DCHECK(::GetCurrentThreadId() == test_thread_id_); 635 636 // Start by replicating some of the steps that would otherwise be 637 // done by TestSuite::Initialize. We can't call the base class 638 // directly because it will attempt to initialize some things such as 639 // ICU that have already been initialized for this process. 640 CFUrlRequestUnittestRunner::InitializeLogging(); 641 642 SuppressErrorDialogs(); 643 base::debug::SetSuppressDebugUI(true); 644 logging::SetLogAssertHandler(UnitTestAssertHandler); 645 646 // Next, do some initialization for NetTestSuite. 647 NetTestSuite::InitializeTestThreadNoNetworkChangeNotifier(); 648 649 // Finally, override the host used by the HTTP tests. See 650 // http://crbug.com/114369 . 651 OverrideHttpHost(); 652 } 653 654 void CFUrlRequestUnittestRunner::Shutdown() { 655 DCHECK(::GetCurrentThreadId() == test_thread_id_); 656 NetTestSuite::Shutdown(); 657 OleUninitialize(); 658 } 659 660 void CFUrlRequestUnittestRunner::OnInitialTabLoaded() { 661 test_http_server_.reset(); 662 BrowserThread::PostTask( 663 BrowserThread::UI, 664 FROM_HERE, 665 base::Bind(&CFUrlRequestUnittestRunner::CancelInitializationTimeout, 666 base::Unretained(this))); 667 StartTests(); 668 } 669 670 void CFUrlRequestUnittestRunner::OnProviderDestroyed() { 671 if (tests_ran_) { 672 StopFileLogger(false); 673 674 if (ie_configurator_.get() != NULL) 675 ie_configurator_->RevertSettings(); 676 677 if (crash_service_) 678 base::KillProcess(crash_service_, 0, false); 679 680 ::ExitProcess(test_result()); 681 } else { 682 DLOG(ERROR) << "Automation Provider shutting down before test execution " 683 "has completed."; 684 } 685 } 686 687 void CFUrlRequestUnittestRunner::StartTests() { 688 if (prompt_after_setup_) 689 MessageBoxA(NULL, "click ok to run", "", MB_OK); 690 691 DCHECK_EQ(test_thread_.IsValid(), false); 692 StopFileLogger(false); 693 test_thread_.Set(::CreateThread(NULL, 0, RunAllUnittests, this, 0, 694 &test_thread_id_)); 695 DCHECK(test_thread_.IsValid()); 696 } 697 698 // static 699 DWORD CFUrlRequestUnittestRunner::RunAllUnittests(void* param) { 700 base::PlatformThread::SetName("CFUrlRequestUnittestRunner"); 701 CFUrlRequestUnittestRunner* me = 702 reinterpret_cast<CFUrlRequestUnittestRunner*>(param); 703 me->test_result_ = me->Run(); 704 me->tests_ran_ = true; 705 BrowserThread::PostTask( 706 BrowserThread::UI, 707 FROM_HERE, 708 base::Bind(&CFUrlRequestUnittestRunner::TakeDownBrowser, 709 base::Unretained(me))); 710 return 0; 711 } 712 713 void CFUrlRequestUnittestRunner::TakeDownBrowser() { 714 if (prompt_after_setup_) 715 MessageBoxA(NULL, "click ok to exit", "", MB_OK); 716 717 // Start capturing logs from npchrome_frame and the in-process Chrome to help 718 // diagnose failures in IE shutdown. This will be Stopped in either 719 // OnIEShutdownFailure or OnProviderDestroyed. 720 StartFileLogger(); 721 722 // AddRef to ensure that IE going away does not trigger the Chrome shutdown 723 // process. 724 // IE shutting down will, however, trigger the automation channel to shut 725 // down, at which time we will exit the process (see OnProviderDestroyed). 726 g_browser_process->AddRefModule(); 727 ShutDownHostBrowser(); 728 729 // In case IE is somehow hung, make sure we don't sit around until a try-bot 730 // kills us. OnIEShutdownFailure will log and exit with an error. 731 BrowserThread::PostDelayedTask( 732 BrowserThread::UI, 733 FROM_HERE, 734 base::Bind(&CFUrlRequestUnittestRunner::OnIEShutdownFailure, 735 base::Unretained(this)), 736 TestTimeouts::action_max_timeout()); 737 } 738 739 void CFUrlRequestUnittestRunner::InitializeLogging() { 740 base::FilePath exe; 741 PathService::Get(base::FILE_EXE, &exe); 742 base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 743 logging::LoggingSettings settings; 744 settings.logging_dest = logging::LOG_TO_ALL; 745 settings.log_file = log_filename.value().c_str(); 746 settings.delete_old = logging::DELETE_OLD_LOG_FILE; 747 logging::InitLogging(settings); 748 // We want process and thread IDs because we may have multiple processes. 749 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 750 logging::SetLogItems(true, true, true, true); 751 } 752 753 void CFUrlRequestUnittestRunner::CancelInitializationTimeout() { 754 timeout_closure_.Cancel(); 755 } 756 757 void CFUrlRequestUnittestRunner::StartInitializationTimeout() { 758 timeout_closure_.Reset( 759 base::Bind(&CFUrlRequestUnittestRunner::OnInitializationTimeout, 760 base::Unretained(this))); 761 base::MessageLoop::current()->PostDelayedTask( 762 FROM_HERE, 763 timeout_closure_.callback(), 764 TestTimeouts::action_max_timeout()); 765 } 766 767 void CFUrlRequestUnittestRunner::OnInitializationTimeout() { 768 LOG(ERROR) << "Failed to start Chrome Frame in the host browser."; 769 770 base::FilePath snapshot; 771 if (ui_test_utils::SaveScreenSnapshotToDesktop(&snapshot)) 772 LOG(ERROR) << "Screen snapshot saved to " << snapshot.value(); 773 774 StopFileLogger(true); 775 776 if (launch_browser_) 777 chrome_frame_test::CloseAllIEWindows(); 778 779 if (ie_configurator_.get() != NULL) 780 ie_configurator_->RevertSettings(); 781 782 if (crash_service_) 783 base::KillProcess(crash_service_, 0, false); 784 785 ::ExitProcess(1); 786 } 787 788 void CFUrlRequestUnittestRunner::OverrideHttpHost() { 789 override_http_host_.reset( 790 new net::ScopedCustomUrlRequestTestHttpHost( 791 chrome_frame_test::GetLocalIPv4Address())); 792 } 793 794 void CFUrlRequestUnittestRunner::PreEarlyInitialization() { 795 testing::InitGoogleTest(&g_argc, g_argv); 796 FilterDisabledTests(); 797 StartFileLogger(); 798 } 799 800 int CFUrlRequestUnittestRunner::PreCreateThreads() { 801 fake_chrome_.reset(new FakeExternalTab()); 802 fake_chrome_->Initialize(); 803 fake_chrome_->browser_process()->PreCreateThreads(); 804 ProcessSingleton::NotificationCallback callback( 805 base::Bind( 806 &CFUrlRequestUnittestRunner::ProcessSingletonNotificationCallback, 807 base::Unretained(this))); 808 process_singleton_.reset(new ProcessSingleton(fake_chrome_->user_data(), 809 callback)); 810 return 0; 811 } 812 813 bool CFUrlRequestUnittestRunner::ProcessSingletonNotificationCallback( 814 const CommandLine& command_line, const base::FilePath& current_directory) { 815 std::string channel_id = command_line.GetSwitchValueASCII( 816 switches::kAutomationClientChannelID); 817 EXPECT_FALSE(channel_id.empty()); 818 819 Profile* profile = g_browser_process->profile_manager()->GetLastUsedProfile( 820 fake_chrome_->user_data()); 821 822 AutomationProviderList* list = g_browser_process->GetAutomationProviderList(); 823 DCHECK(list); 824 list->AddProvider( 825 TestAutomationProvider::NewAutomationProvider(profile, channel_id, this)); 826 return true; 827 } 828 829 void CFUrlRequestUnittestRunner::PreMainMessageLoopRun() { 830 fake_chrome_->InitializePostThreadsCreated(); 831 // Call Create directly instead of NotifyOtherProcessOrCreate as failure is 832 // prefered to notifying another process here. 833 if (!process_singleton_->Create()) { 834 LOG(FATAL) << "Failed to start up ProcessSingleton. Is another test " 835 << "executable or Chrome Frame running?"; 836 if (crash_service_) 837 base::KillProcess(crash_service_, 0, false); 838 ::ExitProcess(1); 839 } 840 } 841 842 bool CFUrlRequestUnittestRunner::MainMessageLoopRun(int* result_code) { 843 DCHECK(base::MessageLoop::current()); 844 DCHECK(base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI); 845 846 // We need to allow IO on the main thread for these tests. 847 base::ThreadRestrictions::SetIOAllowed(true); 848 StartChromeFrameInHostBrowser(); 849 StartInitializationTimeout(); 850 return false; 851 } 852 853 void CFUrlRequestUnittestRunner::PostMainMessageLoopRun() { 854 process_singleton_->Cleanup(); 855 fake_chrome_->browser_process()->StartTearDown(); 856 857 // Must do this separately as the mock profile_manager_ is not the 858 // same member as BrowserProcessImpl::StartTearDown resets. 859 fake_chrome_->browser_process()->DestroyProfileManager(); 860 861 if (crash_service_) 862 base::KillProcess(crash_service_, 0, false); 863 864 base::KillProcesses(chrome_frame_test::kIEImageName, 0, NULL); 865 base::KillProcesses(chrome_frame_test::kIEBrokerImageName, 0, NULL); 866 } 867 868 void CFUrlRequestUnittestRunner::PostDestroyThreads() { 869 process_singleton_.reset(); 870 fake_chrome_->browser_process()->PostDestroyThreads(); 871 fake_chrome_->Shutdown(); 872 fake_chrome_.reset(); 873 874 #ifndef NDEBUG 875 // Avoid CRT cleanup in debug test runs to ensure that webkit ASSERTs which 876 // check if globals are created and destroyed on the same thread don't fire. 877 // Webkit global objects are created on the inproc renderer thread. 878 ::ExitProcess(test_result()); 879 #endif 880 } 881 882 void CFUrlRequestUnittestRunner::StartFileLogger() { 883 if (file_util::CreateTemporaryFile(&log_file_)) { 884 file_logger_.reset(new logging_win::FileLogger()); 885 file_logger_->Initialize(); 886 file_logger_->StartLogging(log_file_); 887 } else { 888 LOG(ERROR) << "Failed to create an ETW log file"; 889 } 890 } 891 892 void CFUrlRequestUnittestRunner::StopFileLogger(bool print) { 893 if (file_logger_.get() != NULL && file_logger_->is_logging()) { 894 file_logger_->StopLogging(); 895 896 if (print) { 897 // Flushing stdout should prevent unrelated output from being interleaved 898 // with the log file output. 899 std::cout.flush(); 900 // Dump the log to stderr. 901 logging_win::PrintLogFile(log_file_, &std::cerr); 902 std::cerr.flush(); 903 } 904 } 905 906 if (!log_file_.empty() && !base::DeleteFile(log_file_, false)) 907 LOG(ERROR) << "Failed to delete log file " << log_file_.value(); 908 909 log_file_.clear(); 910 file_logger_.reset(); 911 } 912 913 const char* IEVersionToString(IEVersion version) { 914 switch (version) { 915 case IE_6: 916 return "IE6"; 917 case IE_7: 918 return "IE7"; 919 case IE_8: 920 return "IE8"; 921 case IE_9: 922 return "IE9"; 923 case IE_10: 924 return "IE10"; 925 case IE_UNSUPPORTED: 926 return "Unknown IE Version"; 927 case NON_IE: 928 return "Could not find IE"; 929 default: 930 return "Error."; 931 } 932 } 933 934 content::BrowserMainParts* FakeContentBrowserClient::CreateBrowserMainParts( 935 const content::MainFunctionParams& parameters) { 936 // Normally this would happen during browser startup, but for tests 937 // we need to trigger creation of Profile-related services. 938 ChromeBrowserMainExtraPartsProfiles:: 939 EnsureBrowserContextKeyedServiceFactoriesBuilt(); 940 941 // We never delete this, as the content module takes ownership. 942 // 943 // We must not construct this earlier, or we will have out-of-order 944 // AtExitManager creation/destruction. 945 g_test_suite = new CFUrlRequestUnittestRunner(g_argc, g_argv); 946 g_test_suite->set_crash_service(chrome_frame_test::StartCrashService()); 947 return g_test_suite; 948 } 949 950 // We must provide a few functions content/ expects to link with. They 951 // are never called for this executable. 952 int PluginMain(const content::MainFunctionParams& parameters) { 953 NOTREACHED(); 954 return 0; 955 } 956 957 int PpapiBrokerMain(const content::MainFunctionParams& parameters) { 958 return PluginMain(parameters); 959 } 960 961 int PpapiPluginMain(const content::MainFunctionParams& parameters) { 962 return PluginMain(parameters); 963 } 964 965 int WorkerMain(const content::MainFunctionParams& parameters) { 966 return PluginMain(parameters); 967 } 968 969 int main(int argc, char** argv) { 970 ScopedChromeFrameRegistrar::RegisterAndExitProcessIfDirected(); 971 g_argc = argc; 972 g_argv = argv; 973 974 google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( 975 InitializeCrashReporting(HEADLESS)); 976 977 // Display the IE version we run with. This must be done after 978 // CFUrlRequestUnittestRunner is constructed since that initializes logging. 979 IEVersion ie_version = chrome_frame_test::GetInstalledIEVersion(); 980 LOG(INFO) << "Running CF net tests with IE version: " 981 << IEVersionToString(ie_version); 982 983 // See url_request_unittest.cc for these credentials. 984 SupplyProxyCredentials credentials("user", "secret"); 985 WindowWatchdog watchdog; 986 watchdog.AddObserver(&credentials, "Windows Security", ""); 987 988 sandbox::SandboxInterfaceInfo sandbox_info = {0}; 989 content::InitializeSandboxInfo(&sandbox_info); 990 FakeMainDelegate delegate; 991 content::ContentMain( 992 reinterpret_cast<HINSTANCE>(GetModuleHandle(NULL)), 993 &sandbox_info, 994 &delegate); 995 996 // Note: In debug builds, we ExitProcess during PostDestroyThreads. 997 return g_test_suite->test_result(); 998 } 999