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