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/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