OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 #include <windows.h> | 4 #include <windows.h> |
5 #include <stdarg.h> | 5 #include <stdarg.h> |
6 | 6 |
7 // IShellWindows includes. Unfortunately we can't keep these in | 7 // IShellWindows includes. Unfortunately we can't keep these in |
8 // alphabetic order since exdisp will bark if some interfaces aren't fully | 8 // alphabetic order since exdisp will bark if some interfaces aren't fully |
9 // defined. | 9 // defined. |
10 #include <mshtml.h> | 10 #include <mshtml.h> |
11 #include <exdisp.h> | 11 #include <exdisp.h> |
12 | 12 |
13 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
14 #include "base/file_version_info.h" | 14 #include "base/file_version_info.h" |
15 #include "base/file_util.h" | 15 #include "base/file_util.h" |
16 #include "base/scoped_bstr_win.h" | 16 #include "base/scoped_bstr_win.h" |
17 #include "base/scoped_comptr_win.h" | |
18 #include "base/scoped_variant_win.h" | 17 #include "base/scoped_variant_win.h" |
19 #include "base/sys_info.h" | 18 #include "base/sys_info.h" |
20 #include "gmock/gmock.h" | 19 #include "gmock/gmock.h" |
21 #include "net/url_request/url_request_unittest.h" | 20 #include "net/url_request/url_request_unittest.h" |
22 #include "chrome_frame/test/chrome_frame_unittests.h" | 21 #include "chrome_frame/test/chrome_frame_unittests.h" |
23 #include "chrome_frame/chrome_frame_automation.h" | 22 #include "chrome_frame/chrome_frame_automation.h" |
24 #include "chrome_frame/chrome_frame_delegate.h" | 23 #include "chrome_frame/chrome_frame_delegate.h" |
25 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" | 24 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" |
26 #include "chrome_frame/test/chrome_frame_test_utils.h" | 25 #include "chrome_frame/test/chrome_frame_test_utils.h" |
27 #include "chrome_frame/test_utils.h" | 26 #include "chrome_frame/test_utils.h" |
(...skipping 29 matching lines...) Expand all Loading... |
57 VT_DISPATCH, | 56 VT_DISPATCH, |
58 VT_VARIANT | VT_BYREF, | 57 VT_VARIANT | VT_BYREF, |
59 VT_VARIANT | VT_BYREF, | 58 VT_VARIANT | VT_BYREF, |
60 VT_VARIANT | VT_BYREF, | 59 VT_VARIANT | VT_BYREF, |
61 VT_VARIANT | VT_BYREF, | 60 VT_VARIANT | VT_BYREF, |
62 VT_VARIANT | VT_BYREF, | 61 VT_VARIANT | VT_BYREF, |
63 VT_BOOL | VT_BYREF | 62 VT_BOOL | VT_BYREF |
64 } | 63 } |
65 }; | 64 }; |
66 | 65 |
| 66 _ATL_FUNC_INFO WebBrowserEventSink::kNewWindow3Info = { |
| 67 CC_STDCALL, VT_EMPTY, 5, { |
| 68 VT_DISPATCH | VT_BYREF, |
| 69 VT_BOOL | VT_BYREF, |
| 70 VT_UINT, |
| 71 VT_BSTR, |
| 72 VT_BSTR |
| 73 } |
| 74 }; |
| 75 |
67 | 76 |
68 | |
69 void ChromeFrameTestWithWebServer::SetUp() { | 77 void ChromeFrameTestWithWebServer::SetUp() { |
70 server_.SetUp(); | 78 server_.SetUp(); |
71 results_dir_ = server_.GetDataDir(); | 79 results_dir_ = server_.GetDataDir(); |
72 file_util::AppendToPath(&results_dir_, L"dump"); | 80 file_util::AppendToPath(&results_dir_, L"dump"); |
73 } | 81 } |
74 | 82 |
75 void ChromeFrameTestWithWebServer::TearDown() { | 83 void ChromeFrameTestWithWebServer::TearDown() { |
76 CloseBrowser(); | 84 CloseBrowser(); |
77 | 85 |
78 // Web browsers tend to relaunch themselves in other processes, meaning the | 86 // Web browsers tend to relaunch themselves in other processes, meaning the |
(...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 template <> struct RunnableMethodTraits<ChromeFrameAutomationClient> { | 831 template <> struct RunnableMethodTraits<ChromeFrameAutomationClient> { |
824 void RetainCallee(ChromeFrameAutomationClient* obj) {} | 832 void RetainCallee(ChromeFrameAutomationClient* obj) {} |
825 void ReleaseCallee(ChromeFrameAutomationClient* obj) {} | 833 void ReleaseCallee(ChromeFrameAutomationClient* obj) {} |
826 }; | 834 }; |
827 | 835 |
828 // MessageLoopForUI wrapper that runs only for a limited time. | 836 // MessageLoopForUI wrapper that runs only for a limited time. |
829 // We need a UI message loop in the main thread. | 837 // We need a UI message loop in the main thread. |
830 struct TimedMsgLoop { | 838 struct TimedMsgLoop { |
831 public: | 839 public: |
832 void RunFor(int seconds) { | 840 void RunFor(int seconds) { |
833 loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds); | 841 QuitAfter(seconds); |
834 loop_.MessageLoop::Run(); | 842 loop_.MessageLoop::Run(); |
835 } | 843 } |
836 | 844 |
837 void Quit() { | 845 void Quit() { |
838 loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask); | 846 loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask); |
839 } | 847 } |
840 | 848 |
| 849 void QuitAfter(int seconds) { |
| 850 loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds); |
| 851 } |
| 852 |
841 MessageLoopForUI loop_; | 853 MessageLoopForUI loop_; |
842 }; | 854 }; |
843 | 855 |
844 template <> struct RunnableMethodTraits<TimedMsgLoop> { | 856 template <> struct RunnableMethodTraits<TimedMsgLoop> { |
845 void RetainCallee(TimedMsgLoop* obj) {} | 857 void RetainCallee(TimedMsgLoop* obj) {} |
846 void ReleaseCallee(TimedMsgLoop* obj) {} | 858 void ReleaseCallee(TimedMsgLoop* obj) {} |
847 }; | 859 }; |
848 | 860 |
849 // Saves typing. It's somewhat hard to create a wrapper around | 861 // Saves typing. It's somewhat hard to create a wrapper around |
850 // testing::InvokeWithoutArgs since it returns a | 862 // testing::InvokeWithoutArgs since it returns a |
851 // non-public (testing::internal) type. | 863 // non-public (testing::internal) type. |
852 #define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\ | 864 #define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\ |
853 CreateFunctor(&loop, &TimedMsgLoop::Quit)) | 865 CreateFunctor(&loop, &TimedMsgLoop::Quit)) |
854 | 866 |
| 867 #define QUIT_LOOP_SOON(loop, seconds) testing::InvokeWithoutArgs(\ |
| 868 CreateFunctor(&loop, &TimedMsgLoop::QuitAfter, seconds)) |
| 869 |
855 // We mock ChromeFrameDelegate only. The rest is with real AutomationProxy | 870 // We mock ChromeFrameDelegate only. The rest is with real AutomationProxy |
856 TEST(CFACWithChrome, CreateTooFast) { | 871 TEST(CFACWithChrome, CreateTooFast) { |
857 MockCFDelegate cfd; | 872 MockCFDelegate cfd; |
858 TimedMsgLoop loop; | 873 TimedMsgLoop loop; |
859 int timeout = 0; // Chrome cannot send Hello message so fast. | 874 int timeout = 0; // Chrome cannot send Hello message so fast. |
860 const std::wstring profile = L"Adam.N.Epilinter"; | 875 const std::wstring profile = L"Adam.N.Epilinter"; |
861 | 876 |
862 scoped_ptr<ChromeFrameAutomationClient> client; | 877 scoped_ptr<ChromeFrameAutomationClient> client; |
863 client.reset(new ChromeFrameAutomationClient()); | 878 client.reset(new ChromeFrameAutomationClient()); |
864 | 879 |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, | 1288 CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, |
1274 reinterpret_cast<void**>(web_browser2.Receive())); | 1289 reinterpret_cast<void**>(web_browser2.Receive())); |
1275 | 1290 |
1276 if (SUCCEEDED(hr)) { | 1291 if (SUCCEEDED(hr)) { |
1277 *web_browser = web_browser2.Detach(); | 1292 *web_browser = web_browser2.Detach(); |
1278 } | 1293 } |
1279 | 1294 |
1280 return hr; | 1295 return hr; |
1281 } | 1296 } |
1282 | 1297 |
1283 TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) { | 1298 // WebBrowserEventSink member defines |
| 1299 HRESULT WebBrowserEventSink::LaunchIEAndNavigate( |
| 1300 const std::wstring& navigate_url, _IDispEvent* sink) { |
1284 int major_version = 0; | 1301 int major_version = 0; |
1285 int minor_version = 0; | 1302 int minor_version = 0; |
1286 int bugfix_version = 0; | 1303 int bugfix_version = 0; |
1287 | 1304 |
1288 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, | 1305 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, |
1289 &bugfix_version); | 1306 &bugfix_version); |
1290 if (major_version > 5) { | 1307 if (major_version > 5) { |
1291 DLOG(INFO) << __FUNCTION__ << " Not running test on Windows version: " | 1308 DLOG(INFO) << __FUNCTION__ << " Not running test on Windows version: " |
1292 << major_version; | 1309 << major_version; |
1293 return; | 1310 return S_FALSE; |
1294 } | 1311 } |
1295 | 1312 |
1296 IEVersion ie_version = GetIEVersion(); | 1313 IEVersion ie_version = GetIEVersion(); |
1297 if (ie_version == IE_8) { | 1314 if (ie_version == IE_8) { |
1298 DLOG(INFO) << __FUNCTION__ << " Not running test on IE8"; | 1315 DLOG(INFO) << __FUNCTION__ << " Not running test on IE8"; |
1299 return; | 1316 return S_FALSE; |
1300 } | 1317 } |
1301 | 1318 |
1302 HRESULT hr = CoInitialize(NULL); | 1319 EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2_.Receive())); |
1303 bool should_uninit = SUCCEEDED(hr); | 1320 web_browser2_->put_Visible(VARIANT_TRUE); |
1304 | 1321 |
1305 ScopedComPtr<IWebBrowser2> web_browser2; | 1322 HRESULT hr = sink->DispEventAdvise(web_browser2_, |
1306 EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2.Receive())); | 1323 &DIID_DWebBrowserEvents2); |
1307 web_browser2->put_Visible(VARIANT_TRUE); | |
1308 | |
1309 CComObject<WebBrowserEventSink>* web_browser_sink = NULL; | |
1310 CComObject<WebBrowserEventSink>::CreateInstance(&web_browser_sink); | |
1311 | |
1312 // Pass the main thread id to the browser sink so that it can notify | |
1313 // us about test completion. | |
1314 web_browser_sink->set_main_thread_id(GetCurrentThreadId()); | |
1315 | |
1316 hr = web_browser_sink->DispEventAdvise(web_browser2, | |
1317 &DIID_DWebBrowserEvents2); | |
1318 EXPECT_TRUE(hr == S_OK); | 1324 EXPECT_TRUE(hr == S_OK); |
1319 | 1325 |
1320 VARIANT empty = ScopedVariant::kEmptyVariant; | 1326 VARIANT empty = ScopedVariant::kEmptyVariant; |
1321 ScopedVariant url; | 1327 ScopedVariant url; |
1322 url.Set(L"cf:file:///C:/"); | 1328 url.Set(navigate_url.c_str()); |
1323 | 1329 |
| 1330 hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty); |
| 1331 EXPECT_TRUE(hr == S_OK); |
| 1332 return hr; |
| 1333 } |
| 1334 |
| 1335 const int kChromeFrameLongNavigationTimeoutInSeconds = 10; |
| 1336 |
| 1337 // This class provides functionality to add expectations to IE full tab mode |
| 1338 // tests. |
| 1339 class MockWebBrowserEventSink : public WebBrowserEventSink { |
| 1340 public: |
| 1341 // Needed to support PostTask. |
| 1342 static bool ImplementsThreadSafeReferenceCounting() { |
| 1343 return true; |
| 1344 } |
| 1345 |
| 1346 MOCK_METHOD7_WITH_CALLTYPE(__stdcall, OnBeforeNavigate2, |
| 1347 HRESULT (IDispatch* dispatch, |
| 1348 VARIANT* url, |
| 1349 VARIANT* flags, |
| 1350 VARIANT* target_frame_name, |
| 1351 VARIANT* post_data, |
| 1352 VARIANT* headers, |
| 1353 VARIANT_BOOL* cancel)); |
| 1354 |
| 1355 MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnNavigateComplete2, |
| 1356 void (IDispatch* dispatch, VARIANT* url)); |
| 1357 |
| 1358 MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNewWindow3, |
| 1359 void (IDispatch** dispatch, |
| 1360 VARIANT_BOOL* Cancel, |
| 1361 DWORD flags, |
| 1362 BSTR url_context, |
| 1363 BSTR url)); |
| 1364 |
| 1365 MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNavigateError, |
| 1366 void (IDispatch* dispatch, |
| 1367 VARIANT* url, |
| 1368 VARIANT* frame_name, |
| 1369 VARIANT* status_code, |
| 1370 VARIANT* cancel)); |
| 1371 }; |
| 1372 |
| 1373 using testing::_; |
| 1374 |
| 1375 const wchar_t kChromeFrameFileUrl[] = L"cf:file:///C:/"; |
| 1376 |
| 1377 TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) { |
1324 TimedMsgLoop loop; | 1378 TimedMsgLoop loop; |
1325 | 1379 // If a navigation fails then IE issues a navigation to an interstitial |
1326 hr = web_browser2->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty); | 1380 // page. Catch this to track navigation errors as the NavigateError |
1327 EXPECT_TRUE(hr == S_OK); | 1381 // notification does not seem to fire reliably. |
1328 | 1382 CComObjectStackEx<MockWebBrowserEventSink> mock; |
1329 loop.RunFor(10); | 1383 |
1330 | 1384 EXPECT_CALL(mock, |
1331 EXPECT_TRUE(web_browser_sink->navigation_failed()); | 1385 OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, |
1332 | 1386 testing::StrCaseEq(kChromeFrameFileUrl)), |
1333 hr = web_browser_sink->DispEventUnadvise(web_browser2); | 1387 _, _, _, _, _)) |
1334 EXPECT_TRUE(hr == S_OK); | 1388 .Times(1) |
1335 | 1389 .WillOnce(testing::Return(S_OK)); |
1336 web_browser2.Release(); | 1390 |
| 1391 EXPECT_CALL(mock, |
| 1392 OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, |
| 1393 testing::StartsWith(L"res:")), |
| 1394 _, _, _, _, _)) |
| 1395 .Times(1) |
| 1396 .WillOnce(testing::DoAll( |
| 1397 QUIT_LOOP(loop), |
| 1398 testing::Return(S_OK))); |
| 1399 |
| 1400 HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFileUrl, &mock); |
| 1401 ASSERT_HRESULT_SUCCEEDED(hr); |
| 1402 if (hr == S_FALSE) |
| 1403 return; |
| 1404 |
| 1405 ASSERT_TRUE(mock.web_browser2() != NULL); |
| 1406 |
| 1407 loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); |
| 1408 |
| 1409 mock.Uninitialize(); |
1337 chrome_frame_test::CloseAllIEWindows(); | 1410 chrome_frame_test::CloseAllIEWindows(); |
1338 | 1411 } |
1339 if (should_uninit) { | 1412 |
1340 CoUninitialize(); | 1413 const wchar_t kChromeFrameFullTabWindowOpenTestUrl[] = |
1341 } | 1414 L"http://localhost:1337/files/chrome_frame_window_open.html"; |
1342 } | 1415 |
1343 | 1416 const wchar_t kChromeFrameFullTabWindowOpenPopupUrl[] = |
| 1417 L"http://localhost:1337/files/chrome_frame_window_open_popup.html"; |
| 1418 |
| 1419 // This test checks if window.open calls issued by a full tab mode ChromeFrame |
| 1420 // instance make it back to IE and then transitions back to Chrome as the |
| 1421 // window.open target page is supposed to render within Chrome. |
| 1422 TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowOpen) { |
| 1423 TimedMsgLoop loop; |
| 1424 |
| 1425 CComObjectStackEx<MockWebBrowserEventSink> mock; |
| 1426 |
| 1427 EXPECT_CALL(mock, |
| 1428 OnBeforeNavigate2( |
| 1429 _, testing::Field(&VARIANT::bstrVal, |
| 1430 testing::StrCaseEq(kChromeFrameFullTabWindowOpenTestUrl)), |
| 1431 _, _, _, _, _)) |
| 1432 .Times(1) |
| 1433 .WillOnce(testing::Return(S_OK)); |
| 1434 |
| 1435 EXPECT_CALL(mock, |
| 1436 OnBeforeNavigate2( |
| 1437 _, testing::Field(&VARIANT::bstrVal, |
| 1438 testing::StrCaseEq(kChromeFrameFullTabWindowOpenPopupUrl)), |
| 1439 _, _, _, _, _)) |
| 1440 .Times(1) |
| 1441 .WillOnce(testing::DoAll( |
| 1442 QUIT_LOOP_SOON(loop, 2), |
| 1443 testing::Return(S_OK))); |
| 1444 |
| 1445 HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFullTabWindowOpenTestUrl, |
| 1446 &mock); |
| 1447 ASSERT_HRESULT_SUCCEEDED(hr); |
| 1448 if (hr == S_FALSE) |
| 1449 return; |
| 1450 |
| 1451 ASSERT_TRUE(mock.web_browser2() != NULL); |
| 1452 |
| 1453 loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); |
| 1454 |
| 1455 ASSERT_TRUE(CheckResultFile(L"ChromeFrameWindowOpenPopup", "OK")); |
| 1456 |
| 1457 mock.Uninitialize(); |
| 1458 chrome_frame_test::CloseAllIEWindows(); |
| 1459 } |
| 1460 |
| 1461 const wchar_t kChromeFrameAboutBlankUrl[] = |
| 1462 L"cf:about:blank"; |
| 1463 |
| 1464 const wchar_t kChromeFrameAboutVersion[] = |
| 1465 L"cf:about:version"; |
| 1466 |
| 1467 // This test launches chrome frame in full tab mode in IE by having IE navigate |
| 1468 // to cf:about:blank. It then looks for the chrome renderer window and posts |
| 1469 // the WM_RBUTTONDOWN/WM_RBUTTONUP messages to it, which bring up the context |
| 1470 // menu. This is followed by keyboard messages sent via SendInput to select |
| 1471 // the About chrome frame menu option, which would then bring up a new window |
| 1472 // with the chrome revision. The test finally checks for success by comparing |
| 1473 // the URL of the window being opened with cf:about:version, which indicates |
| 1474 // that the operation succeeded. |
| 1475 TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_AboutChromeFrame) { |
| 1476 TimedMsgLoop loop; |
| 1477 |
| 1478 CComObjectStackEx<MockWebBrowserEventSink> mock; |
| 1479 |
| 1480 EXPECT_CALL(mock, |
| 1481 OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, |
| 1482 testing::StrCaseEq(kChromeFrameAboutBlankUrl)), |
| 1483 _, _, _, _, _)) |
| 1484 .Times(1) |
| 1485 .WillOnce(testing::Return(S_OK)); |
| 1486 |
| 1487 EXPECT_CALL(mock, OnNavigateComplete2(_, _)) |
| 1488 .Times(1) |
| 1489 .WillOnce(testing::InvokeWithoutArgs( |
| 1490 &chrome_frame_test::ShowChromeFrameContextMenu)); |
| 1491 |
| 1492 EXPECT_CALL(mock, |
| 1493 OnNewWindow3(_, _, _, _, |
| 1494 testing::StrCaseEq(kChromeFrameAboutVersion))) |
| 1495 .Times(1) |
| 1496 .WillOnce(QUIT_LOOP(loop)); |
| 1497 |
| 1498 HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameAboutBlankUrl, &mock); |
| 1499 ASSERT_HRESULT_SUCCEEDED(hr); |
| 1500 if (hr == S_FALSE) |
| 1501 return; |
| 1502 |
| 1503 ASSERT_TRUE(mock.web_browser2() != NULL); |
| 1504 |
| 1505 loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); |
| 1506 |
| 1507 mock.Uninitialize(); |
| 1508 chrome_frame_test::CloseAllIEWindows(); |
| 1509 } |
| 1510 |
OLD | NEW |