OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 <exdisp.h> |
| 8 |
| 9 #include "app/app_paths.h" |
| 10 #include "app/resource_bundle.h" |
| 11 #include "app/win_util.h" |
| 12 |
| 13 #include "base/command_line.h" |
| 14 #include "base/file_util.h" |
| 15 #include "base/icu_util.h" |
| 16 #include "base/path_service.h" |
| 17 #include "base/scoped_bstr_win.h" |
| 18 #include "base/scoped_comptr_win.h" |
| 19 #include "base/scoped_variant_win.h" |
| 20 |
| 21 #include "chrome/browser/browser_prefs.h" |
| 22 #include "chrome/browser/chrome_thread.h" |
| 23 #include "chrome/browser/process_singleton.h" |
| 24 #include "chrome/browser/profile_manager.h" |
| 25 #include "chrome/common/chrome_constants.h" |
| 26 #include "chrome/common/chrome_paths.h" |
| 27 #include "chrome/common/chrome_switches.h" |
| 28 #include "chrome/common/pref_names.h" |
| 29 #include "chrome/browser/renderer_host/render_process_host.h" |
| 30 |
| 31 #include "chrome_frame/utils.h" |
| 32 #include "chrome_frame/test/chrome_frame_test_utils.h" |
| 33 #include "chrome_frame/test/net/dialog_watchdog.h" |
| 34 #include "chrome_frame/test/net/test_automation_resource_message_filter.h" |
| 35 |
| 36 namespace { |
| 37 |
| 38 // A special command line switch to allow developers to manually launch the |
| 39 // browser and debug CF inside the browser. |
| 40 const wchar_t kManualBrowserLaunch[] = L"manual-browser"; |
| 41 |
| 42 // Pops up a message box after the test environment has been set up |
| 43 // and before tearing it down. Useful for when debugging tests and not |
| 44 // the test environment that's been set up. |
| 45 const wchar_t kPromptAfterSetup[] = L"prompt-after-setup"; |
| 46 |
| 47 const int kTestServerPort = 4666; |
| 48 // The test HTML we use to initialize Chrome Frame. |
| 49 // Note that there's a little trick in there to avoid an extra URL request |
| 50 // that the browser will otherwise make for the site's favicon. |
| 51 // If we don't do this the browser will create a new URL request after |
| 52 // the CF page has been initialized and that URL request will confuse the |
| 53 // global URL instance counter in the unit tests and subsequently trip |
| 54 // some DCHECKs. |
| 55 const char kChromeFrameHtml[] = "<html><head>" |
| 56 "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />" |
| 57 "<link rel=\"shortcut icon\" href=\"file://c:\\favicon.ico\"/>" |
| 58 "</head><body>Chrome Frame should now be loaded</body></html>"; |
| 59 |
| 60 bool ShouldLaunchBrowser() { |
| 61 return !CommandLine::ForCurrentProcess()->HasSwitch(kManualBrowserLaunch); |
| 62 } |
| 63 |
| 64 bool PromptAfterSetup() { |
| 65 return CommandLine::ForCurrentProcess()->HasSwitch(kPromptAfterSetup); |
| 66 } |
| 67 |
| 68 } // end namespace |
| 69 |
| 70 FakeExternalTab::FakeExternalTab() { |
| 71 PathService::Get(chrome::DIR_USER_DATA, &overridden_user_dir_); |
| 72 user_data_dir_ = FilePath::FromWStringHack(GetProfilePath()); |
| 73 PathService::Override(chrome::DIR_USER_DATA, user_data_dir_); |
| 74 process_singleton_.reset(new ProcessSingleton(user_data_dir_)); |
| 75 } |
| 76 |
| 77 FakeExternalTab::~FakeExternalTab() { |
| 78 if (!overridden_user_dir_.empty()) { |
| 79 PathService::Override(chrome::DIR_USER_DATA, overridden_user_dir_); |
| 80 } |
| 81 } |
| 82 |
| 83 std::wstring FakeExternalTab::GetProfileName() { |
| 84 return L"iexplore"; |
| 85 } |
| 86 |
| 87 std::wstring FakeExternalTab::GetProfilePath() { |
| 88 std::wstring path; |
| 89 GetUserProfileBaseDirectory(&path); |
| 90 file_util::AppendToPath(&path, GetProfileName()); |
| 91 return path; |
| 92 } |
| 93 |
| 94 void FakeExternalTab::Initialize() { |
| 95 DCHECK(g_browser_process == NULL); |
| 96 |
| 97 // The gears plugin causes the PluginRequestInterceptor to kick in and it |
| 98 // will cause problems when it tries to intercept URL requests. |
| 99 PathService::Override(chrome::FILE_GEARS_PLUGIN, FilePath()); |
| 100 |
| 101 icu_util::Initialize(); |
| 102 |
| 103 chrome::RegisterPathProvider(); |
| 104 app::RegisterPathProvider(); |
| 105 |
| 106 ResourceBundle::InitSharedInstance(L"en-US"); |
| 107 ResourceBundle::GetSharedInstance().LoadThemeResources(); |
| 108 |
| 109 const CommandLine* cmd = CommandLine::ForCurrentProcess(); |
| 110 browser_process_.reset(new BrowserProcessImpl(*cmd)); |
| 111 RenderProcessHost::set_run_renderer_in_process(true); |
| 112 // BrowserProcessImpl's constructor should set g_browser_process. |
| 113 DCHECK(g_browser_process); |
| 114 |
| 115 Profile* profile = g_browser_process->profile_manager()-> |
| 116 GetDefaultProfile(FilePath(user_data())); |
| 117 PrefService* prefs = profile->GetPrefs(); |
| 118 PrefService* local_state = browser_process_->local_state(); |
| 119 local_state->RegisterStringPref(prefs::kApplicationLocale, L""); |
| 120 local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false); |
| 121 |
| 122 browser::RegisterAllPrefs(prefs, local_state); |
| 123 |
| 124 // Override some settings to avoid hitting some preferences that have not |
| 125 // been registered. |
| 126 prefs->SetBoolean(prefs::kPasswordManagerEnabled, false); |
| 127 prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false); |
| 128 prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false); |
| 129 |
| 130 profile->InitExtensions(); |
| 131 } |
| 132 |
| 133 void FakeExternalTab::Shutdown() { |
| 134 browser_process_.reset(); |
| 135 g_browser_process = NULL; |
| 136 process_singleton_.reset(); |
| 137 |
| 138 ResourceBundle::CleanupSharedInstance(); |
| 139 } |
| 140 |
| 141 CFUrlRequestUnittestRunner::CFUrlRequestUnittestRunner(int argc, char** argv) |
| 142 : NetTestSuite(argc, argv), |
| 143 chrome_frame_html_("/chrome_frame", kChromeFrameHtml) { |
| 144 fake_chrome_.Initialize(); |
| 145 pss_subclass_.reset(new ProcessSingletonSubclass(this)); |
| 146 EXPECT_TRUE(pss_subclass_->Subclass(fake_chrome_.user_data())); |
| 147 StartChromeFrameInHostBrowser(); |
| 148 } |
| 149 |
| 150 CFUrlRequestUnittestRunner::~CFUrlRequestUnittestRunner() { |
| 151 fake_chrome_.Shutdown(); |
| 152 } |
| 153 |
| 154 DWORD WINAPI NavigateIE(void* param) { |
| 155 return 0; |
| 156 win_util::ScopedCOMInitializer com; |
| 157 BSTR url = reinterpret_cast<BSTR>(param); |
| 158 |
| 159 bool found = false; |
| 160 int retries = 0; |
| 161 const int kMaxRetries = 20; |
| 162 while (!found && retries < kMaxRetries) { |
| 163 ScopedComPtr<IShellWindows> windows; |
| 164 HRESULT hr = ::CoCreateInstance(__uuidof(ShellWindows), NULL, CLSCTX_ALL, |
| 165 IID_IShellWindows, reinterpret_cast<void**>(windows.Receive())); |
| 166 DCHECK(SUCCEEDED(hr)) << "CoCreateInstance"; |
| 167 |
| 168 if (SUCCEEDED(hr)) { |
| 169 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); |
| 170 long count = 0; // NOLINT |
| 171 windows->get_Count(&count); |
| 172 VARIANT i = { VT_I4 }; |
| 173 for (i.lVal = 0; i.lVal < count; ++i.lVal) { |
| 174 ScopedComPtr<IDispatch> folder; |
| 175 windows->Item(i, folder.Receive()); |
| 176 if (folder != NULL) { |
| 177 ScopedComPtr<IWebBrowser2> browser; |
| 178 if (SUCCEEDED(browser.QueryFrom(folder))) { |
| 179 found = true; |
| 180 browser->Stop(); |
| 181 Sleep(1000); |
| 182 VARIANT empty = ScopedVariant::kEmptyVariant; |
| 183 hr = browser->Navigate(url, &empty, &empty, &empty, &empty); |
| 184 DCHECK(SUCCEEDED(hr)) << "Failed to navigate"; |
| 185 break; |
| 186 } |
| 187 } |
| 188 } |
| 189 } |
| 190 if (!found) { |
| 191 DLOG(INFO) << "Waiting for browser to initialize..."; |
| 192 ::Sleep(100); |
| 193 retries++; |
| 194 } |
| 195 } |
| 196 |
| 197 DCHECK(retries < kMaxRetries); |
| 198 DCHECK(found); |
| 199 |
| 200 ::SysFreeString(url); |
| 201 |
| 202 return 0; |
| 203 } |
| 204 |
| 205 void CFUrlRequestUnittestRunner::StartChromeFrameInHostBrowser() { |
| 206 if (!ShouldLaunchBrowser()) |
| 207 return; |
| 208 |
| 209 win_util::ScopedCOMInitializer com; |
| 210 chrome_frame_test::CloseAllIEWindows(); |
| 211 |
| 212 test_http_server_.reset(new test_server::SimpleWebServer(kTestServerPort)); |
| 213 test_http_server_->AddResponse(&chrome_frame_html_); |
| 214 std::wstring url(StringPrintf(L"http://localhost:%i/chrome_frame", |
| 215 kTestServerPort).c_str()); |
| 216 |
| 217 // Launch IE. This launches IE correctly on Vista too. |
| 218 ScopedHandle ie_process(chrome_frame_test::LaunchIE(url)); |
| 219 EXPECT_TRUE(ie_process.IsValid()); |
| 220 |
| 221 // NOTE: If you're running IE8 and CF is not being loaded, you need to |
| 222 // disable IE8's prebinding until CF properly handles that situation. |
| 223 // |
| 224 // HKCU\Software\Microsoft\Internet Explorer\Main |
| 225 // Value name: EnablePreBinding (REG_DWORD) |
| 226 // Value: 0 |
| 227 } |
| 228 |
| 229 void CFUrlRequestUnittestRunner::ShutDownHostBrowser() { |
| 230 if (ShouldLaunchBrowser()) { |
| 231 win_util::ScopedCOMInitializer com; |
| 232 chrome_frame_test::CloseAllIEWindows(); |
| 233 } |
| 234 } |
| 235 |
| 236 // Override virtual void Initialize to not call icu initialize |
| 237 void CFUrlRequestUnittestRunner::Initialize() { |
| 238 DCHECK(::GetCurrentThreadId() == test_thread_id_); |
| 239 |
| 240 // Start by replicating some of the steps that would otherwise be |
| 241 // done by TestSuite::Initialize. We can't call the base class |
| 242 // directly because it will attempt to initialize some things such as |
| 243 // ICU that have already been initialized for this process. |
| 244 InitializeLogging(); |
| 245 base::Time::EnableHiResClockForTests(); |
| 246 |
| 247 #if !defined(PURIFY) && defined(OS_WIN) |
| 248 logging::SetLogAssertHandler(UnitTestAssertHandler); |
| 249 #endif // !defined(PURIFY) |
| 250 |
| 251 // Next, do some initialization for NetTestSuite. |
| 252 NetTestSuite::InitializeTestThread(); |
| 253 } |
| 254 |
| 255 void CFUrlRequestUnittestRunner::Shutdown() { |
| 256 DCHECK(::GetCurrentThreadId() == test_thread_id_); |
| 257 NetTestSuite::Shutdown(); |
| 258 } |
| 259 |
| 260 void CFUrlRequestUnittestRunner::OnConnectAutomationProviderToChannel( |
| 261 const std::string& channel_id) { |
| 262 Profile* profile = g_browser_process->profile_manager()-> |
| 263 GetDefaultProfile(fake_chrome_.user_data()); |
| 264 |
| 265 AutomationProviderList* list = |
| 266 g_browser_process->InitAutomationProviderList(); |
| 267 DCHECK(list); |
| 268 list->AddProvider(TestAutomationProvider::NewAutomationProvider(profile, |
| 269 channel_id, this)); |
| 270 } |
| 271 |
| 272 void CFUrlRequestUnittestRunner::OnInitialTabLoaded() { |
| 273 test_http_server_.reset(); |
| 274 StartTests(); |
| 275 } |
| 276 |
| 277 void CFUrlRequestUnittestRunner::RunMainUIThread() { |
| 278 DCHECK(MessageLoop::current()); |
| 279 DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
| 280 |
| 281 // Register the main thread by instantiating it, but don't call any methods. |
| 282 ChromeThread main_thread; |
| 283 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 284 |
| 285 MessageLoop::current()->Run(); |
| 286 } |
| 287 |
| 288 void CFUrlRequestUnittestRunner::StartTests() { |
| 289 if (PromptAfterSetup()) |
| 290 MessageBoxA(NULL, "click ok to run", "", MB_OK); |
| 291 |
| 292 DCHECK_EQ(test_thread_.IsValid(), false); |
| 293 test_thread_.Set(::CreateThread(NULL, 0, RunAllUnittests, this, 0, |
| 294 &test_thread_id_)); |
| 295 DCHECK(test_thread_.IsValid()); |
| 296 } |
| 297 |
| 298 // static |
| 299 DWORD CFUrlRequestUnittestRunner::RunAllUnittests(void* param) { |
| 300 PlatformThread::SetName("CFUrlRequestUnittestRunner"); |
| 301 CFUrlRequestUnittestRunner* me = |
| 302 reinterpret_cast<CFUrlRequestUnittestRunner*>(param); |
| 303 me->Run(); |
| 304 me->fake_chrome_.ui_loop()->PostTask(FROM_HERE, |
| 305 NewRunnableFunction(TakeDownBrowser, me)); |
| 306 return 0; |
| 307 } |
| 308 |
| 309 // static |
| 310 void CFUrlRequestUnittestRunner::TakeDownBrowser( |
| 311 CFUrlRequestUnittestRunner* me) { |
| 312 if (PromptAfterSetup()) |
| 313 MessageBoxA(NULL, "click ok to exit", "", MB_OK); |
| 314 |
| 315 me->ShutDownHostBrowser(); |
| 316 } |
| 317 |
| 318 void CFUrlRequestUnittestRunner::InitializeLogging() { |
| 319 FilePath exe; |
| 320 PathService::Get(base::FILE_EXE, &exe); |
| 321 FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); |
| 322 logging::InitLogging(log_filename.value().c_str(), |
| 323 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, |
| 324 logging::LOCK_LOG_FILE, |
| 325 logging::DELETE_OLD_LOG_FILE); |
| 326 // We want process and thread IDs because we may have multiple processes. |
| 327 // Note: temporarily enabled timestamps in an effort to catch bug 6361. |
| 328 logging::SetLogItems(true, true, true, true); |
| 329 } |
| 330 |
| 331 void FilterDisabledTests() { |
| 332 if (::testing::FLAGS_gtest_filter.GetLength() && |
| 333 ::testing::FLAGS_gtest_filter.Compare("*") != 0) { |
| 334 // Don't override user specified filters. |
| 335 return; |
| 336 } |
| 337 |
| 338 const char* disabled_tests[] = { |
| 339 // Tests disabled since they're testing the same functionality used |
| 340 // by the TestAutomationProvider. |
| 341 "URLRequestTest.InterceptNetworkError", |
| 342 "URLRequestTest.InterceptRestartRequired", |
| 343 "URLRequestTest.InterceptRespectsCancelMain", |
| 344 "URLRequestTest.InterceptRespectsCancelRedirect", |
| 345 "URLRequestTest.InterceptRespectsCancelFinal", |
| 346 "URLRequestTest.InterceptRespectsCancelInRestart", |
| 347 "URLRequestTest.InterceptRedirect", |
| 348 "URLRequestTest.InterceptServerError", |
| 349 "URLRequestTestFTP.*", |
| 350 |
| 351 // Tests that are currently not working: |
| 352 |
| 353 // Temporarily disabled because they needs user input (login dialog). |
| 354 "URLRequestTestHTTP.BasicAuth", |
| 355 "URLRequestTestHTTP.BasicAuthWithCookies", |
| 356 |
| 357 // HTTPS tests temporarily disabled due to the certificate error dialog. |
| 358 // TODO(tommi): The tests currently fail though, so need to fix. |
| 359 "HTTPSRequestTest.HTTPSMismatchedTest", |
| 360 "HTTPSRequestTest.HTTPSExpiredTest", |
| 361 |
| 362 // Tests chrome's network stack's cache (might not apply to CF). |
| 363 "URLRequestTestHTTP.VaryHeader", |
| 364 |
| 365 // I suspect we can only get this one to work (if at all) on IE8 and |
| 366 // later by using the new INTERNET_OPTION_SUPPRESS_BEHAVIOR flags |
| 367 // See http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx |
| 368 "URLRequestTest.DoNotSaveCookies", |
| 369 }; |
| 370 |
| 371 std::string filter("-"); // All following filters will be negative. |
| 372 for (int i = 0; i < arraysize(disabled_tests); ++i) { |
| 373 if (i > 0) |
| 374 filter += ":"; |
| 375 filter += disabled_tests[i]; |
| 376 } |
| 377 |
| 378 ::testing::FLAGS_gtest_filter = filter; |
| 379 } |
| 380 |
| 381 int main(int argc, char** argv) { |
| 382 DialogWatchdog watchdog; |
| 383 // See url_request_unittest.cc for these credentials. |
| 384 SupplyProxyCredentials credentials("user", "secret"); |
| 385 watchdog.AddObserver(&credentials); |
| 386 testing::InitGoogleTest(&argc, argv); |
| 387 FilterDisabledTests(); |
| 388 CFUrlRequestUnittestRunner test_suite(argc, argv); |
| 389 test_suite.RunMainUIThread(); |
| 390 return 0; |
| 391 } |
OLD | NEW |