Home | History | Annotate | Download | only in net
      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