1 // Copyright (c) 2011 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 "base/file_util.h" 6 #include "base/memory/ref_counted.h" 7 #include "base/utf_string_conversions.h" 8 #include "chrome/browser/extensions/autoupdate_interceptor.h" 9 #include "chrome/browser/extensions/extension_apitest.h" 10 #include "chrome/browser/extensions/extension_browsertest.h" 11 #include "chrome/browser/extensions/extension_error_reporter.h" 12 #include "chrome/browser/extensions/extension_host.h" 13 #include "chrome/browser/extensions/extension_process_manager.h" 14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_tabs_module.h" 16 #include "chrome/browser/extensions/extension_updater.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/tabs/tab_strip_model.h" 19 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser_list.h" 21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 22 #include "chrome/common/chrome_paths.h" 23 #include "chrome/common/extensions/extension_action.h" 24 #include "chrome/common/url_constants.h" 25 #include "chrome/test/ui_test_utils.h" 26 #include "content/browser/renderer_host/render_view_host.h" 27 #include "content/browser/site_instance.h" 28 #include "content/browser/tab_contents/tab_contents.h" 29 #include "net/base/net_util.h" 30 #include "net/test/test_server.h" 31 32 #if defined(TOOLKIT_VIEWS) 33 #include "chrome/browser/ui/views/frame/browser_view.h" 34 #endif 35 36 const std::string kSubscribePage = "/subscribe.html"; 37 const std::string kFeedPage = "files/feeds/feed.html"; 38 const std::string kFeedPageMultiRel = "files/feeds/feed_multi_rel.html"; 39 const std::string kNoFeedPage = "files/feeds/no_feed.html"; 40 const std::string kValidFeed0 = "files/feeds/feed_script.xml"; 41 const std::string kValidFeed1 = "files/feeds/feed1.xml"; 42 const std::string kValidFeed2 = "files/feeds/feed2.xml"; 43 const std::string kValidFeed3 = "files/feeds/feed3.xml"; 44 const std::string kValidFeed4 = "files/feeds/feed4.xml"; 45 const std::string kValidFeed5 = "files/feeds/feed5.xml"; 46 const std::string kValidFeed6 = "files/feeds/feed6.xml"; 47 const std::string kValidFeedNoLinks = "files/feeds/feed_nolinks.xml"; 48 const std::string kInvalidFeed1 = "files/feeds/feed_invalid1.xml"; 49 const std::string kInvalidFeed2 = "files/feeds/feed_invalid2.xml"; 50 const std::string kLocalization = 51 "files/extensions/browsertest/title_localized_pa/simple.html"; 52 // We need a triple encoded string to prove that we are not decoding twice in 53 // subscribe.js because one layer is also stripped off when subscribe.js passes 54 // it to the XMLHttpRequest object. 55 const std::string kFeedTripleEncoded = "files/feeds/url%25255Fdecoding.html"; 56 const std::string kHashPageA = 57 "files/extensions/api_test/page_action/hash_change/test_page_A.html"; 58 const std::string kHashPageAHash = kHashPageA + "#asdf"; 59 const std::string kHashPageB = 60 "files/extensions/api_test/page_action/hash_change/test_page_B.html"; 61 62 // Looks for an ExtensionHost whose URL has the given path component (including 63 // leading slash). Also verifies that the expected number of hosts are loaded. 64 static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager, 65 const std::string& path, 66 int expected_hosts) { 67 ExtensionHost* host = NULL; 68 int num_hosts = 0; 69 for (ExtensionProcessManager::const_iterator iter = manager->begin(); 70 iter != manager->end(); ++iter) { 71 if ((*iter)->GetURL().path() == path) { 72 EXPECT_FALSE(host); 73 host = *iter; 74 } 75 num_hosts++; 76 } 77 EXPECT_EQ(expected_hosts, num_hosts); 78 return host; 79 } 80 81 // Tests that we can load extension pages into the tab area and they can call 82 // extension APIs. 83 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) { 84 ASSERT_TRUE(LoadExtension( 85 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 86 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 87 .AppendASCII("1.0.0.0"))); 88 89 ui_test_utils::NavigateToURL( 90 browser(), 91 GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html")); 92 93 bool result = false; 94 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 95 browser()->GetSelectedTabContents()->render_view_host(), L"", 96 L"testTabsAPI()", &result)); 97 EXPECT_TRUE(result); 98 99 // There was a bug where we would crash if we navigated to a page in the same 100 // extension because no new render view was getting created, so we would not 101 // do some setup. 102 ui_test_utils::NavigateToURL( 103 browser(), 104 GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html")); 105 result = false; 106 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 107 browser()->GetSelectedTabContents()->render_view_host(), L"", 108 L"testTabsAPI()", &result)); 109 EXPECT_TRUE(result); 110 } 111 112 // Tests that GPU-related WebKit preferences are set for extension background 113 // pages. See http://crbug.com/64512. 114 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WebKitPrefsBackgroundPage) { 115 ASSERT_TRUE(LoadExtension( 116 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 117 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 118 .AppendASCII("1.0.0.0"))); 119 120 ExtensionProcessManager* manager = 121 browser()->profile()->GetExtensionProcessManager(); 122 ExtensionHost* host = FindHostWithPath(manager, "/backgroundpage.html", 1); 123 WebPreferences prefs = host->GetWebkitPrefs(); 124 ASSERT_FALSE(prefs.experimental_webgl_enabled); 125 ASSERT_FALSE(prefs.accelerated_compositing_enabled); 126 ASSERT_FALSE(prefs.accelerated_2d_canvas_enabled); 127 } 128 129 // Tests that we can load page actions in the Omnibox. 130 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) { 131 ASSERT_TRUE(test_server()->Start()); 132 133 // This page action will not show an icon, since it doesn't specify one but 134 // is included here to test for a crash (http://crbug.com/25562). 135 ASSERT_TRUE(LoadExtension( 136 test_data_dir_.AppendASCII("browsertest") 137 .AppendASCII("crash_25562"))); 138 139 ASSERT_TRUE(LoadExtension( 140 test_data_dir_.AppendASCII("subscribe_page_action"))); 141 142 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 143 144 // Navigate to the feed page. 145 GURL feed_url = test_server()->GetURL(kFeedPage); 146 ui_test_utils::NavigateToURL(browser(), feed_url); 147 // We should now have one page action ready to go in the LocationBar. 148 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 149 150 // Navigate to a page with no feed. 151 GURL no_feed = test_server()->GetURL(kNoFeedPage); 152 ui_test_utils::NavigateToURL(browser(), no_feed); 153 // Make sure the page action goes away. 154 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 155 } 156 157 // Tests that we don't lose the page action icon on in-page navigations. 158 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionInPageNavigation) { 159 ASSERT_TRUE(test_server()->Start()); 160 161 FilePath extension_path(test_data_dir_.AppendASCII("api_test") 162 .AppendASCII("page_action") 163 .AppendASCII("hash_change")); 164 ASSERT_TRUE(LoadExtension(extension_path)); 165 166 // Page action should become visible when we navigate here. 167 GURL feed_url = test_server()->GetURL(kHashPageA); 168 ui_test_utils::NavigateToURL(browser(), feed_url); 169 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 170 171 // In-page navigation, page action should remain. 172 feed_url = test_server()->GetURL(kHashPageAHash); 173 ui_test_utils::NavigateToURL(browser(), feed_url); 174 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 175 176 // Not an in-page navigation, page action should go away. 177 feed_url = test_server()->GetURL(kHashPageB); 178 ui_test_utils::NavigateToURL(browser(), feed_url); 179 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 180 } 181 182 // Tests that the location bar forgets about unloaded page actions. 183 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) { 184 ASSERT_TRUE(test_server()->Start()); 185 186 FilePath extension_path(test_data_dir_.AppendASCII("subscribe_page_action")); 187 ASSERT_TRUE(LoadExtension(extension_path)); 188 189 // Navigation prompts the location bar to load page actions. 190 GURL feed_url = test_server()->GetURL(kFeedPage); 191 ui_test_utils::NavigateToURL(browser(), feed_url); 192 ASSERT_TRUE(WaitForPageActionCountChangeTo(1)); 193 194 UnloadExtension(last_loaded_extension_id_); 195 196 // Make sure the page action goes away when it's unloaded. 197 ASSERT_TRUE(WaitForPageActionCountChangeTo(0)); 198 } 199 200 // Flaky crash on Mac debug. http://crbug.com/45079 201 #if defined(OS_MACOSX) 202 #define PageActionRefreshCrash PageActionRefreshCrash 203 #endif 204 // Tests that we can load page actions in the Omnibox. 205 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) { 206 base::TimeTicks start_time = base::TimeTicks::Now(); 207 208 ExtensionService* service = browser()->profile()->GetExtensionService(); 209 210 size_t size_before = service->extensions()->size(); 211 212 FilePath base_path = test_data_dir_.AppendASCII("browsertest") 213 .AppendASCII("crash_44415"); 214 // Load extension A. 215 ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtA"))); 216 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 217 ASSERT_EQ(size_before + 1, service->extensions()->size()); 218 const Extension* extensionA = service->extensions()->at(size_before); 219 220 LOG(INFO) << "Load extension A done : " 221 << (base::TimeTicks::Now() - start_time).InMilliseconds() 222 << " ms" << std::flush; 223 224 // Load extension B. 225 ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtB"))); 226 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(2)); 227 ASSERT_EQ(size_before + 2, service->extensions()->size()); 228 const Extension* extensionB = service->extensions()->at(size_before + 1); 229 230 LOG(INFO) << "Load extension B done : " 231 << (base::TimeTicks::Now() - start_time).InMilliseconds() 232 << " ms" << std::flush; 233 234 ReloadExtension(extensionA->id()); 235 // ExtensionA has changed, so refetch it. 236 ASSERT_EQ(size_before + 2, service->extensions()->size()); 237 extensionA = service->extensions()->at(size_before + 1); 238 239 LOG(INFO) << "Reload extension A done: " 240 << (base::TimeTicks::Now() - start_time).InMilliseconds() 241 << " ms" << std::flush; 242 243 ReloadExtension(extensionB->id()); 244 245 LOG(INFO) << "Reload extension B done: " 246 << (base::TimeTicks::Now() - start_time).InMilliseconds() 247 << " ms" << std::flush; 248 249 // This is where it would crash, before http://crbug.com/44415 was fixed. 250 ReloadExtension(extensionA->id()); 251 252 LOG(INFO) << "Test completed : " 253 << (base::TimeTicks::Now() - start_time).InMilliseconds() 254 << " ms" << std::flush; 255 } 256 257 // Makes sure that the RSS detects RSS feed links, even when rel tag contains 258 // more than just "alternate". 259 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) { 260 ASSERT_TRUE(test_server()->Start()); 261 262 ASSERT_TRUE(LoadExtension( 263 test_data_dir_.AppendASCII("subscribe_page_action"))); 264 265 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0)); 266 267 // Navigate to the feed page. 268 GURL feed_url = test_server()->GetURL(kFeedPageMultiRel); 269 ui_test_utils::NavigateToURL(browser(), feed_url); 270 // We should now have one page action ready to go in the LocationBar. 271 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 272 } 273 274 // Tests that tooltips of a browser action icon can be specified using UTF8. 275 // See http://crbug.com/25349. 276 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) { 277 ExtensionService* service = browser()->profile()->GetExtensionService(); 278 const size_t size_before = service->extensions()->size(); 279 FilePath extension_path(test_data_dir_.AppendASCII("browsertest") 280 .AppendASCII("title_localized")); 281 ASSERT_TRUE(LoadExtension(extension_path)); 282 283 ASSERT_EQ(size_before + 1, service->extensions()->size()); 284 const Extension* extension = service->extensions()->at(size_before); 285 286 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n browser action").c_str(), 287 extension->description().c_str()); 288 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur is my name").c_str(), 289 extension->name().c_str()); 290 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 291 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur").c_str(), 292 extension->browser_action()->GetTitle(tab_id).c_str()); 293 } 294 295 // Tests that tooltips of a page action icon can be specified using UTF8. 296 // See http://crbug.com/25349. 297 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) { 298 ASSERT_TRUE(test_server()->Start()); 299 300 ExtensionService* service = browser()->profile()->GetExtensionService(); 301 const size_t size_before = service->extensions()->size(); 302 303 FilePath extension_path(test_data_dir_.AppendASCII("browsertest") 304 .AppendASCII("title_localized_pa")); 305 ASSERT_TRUE(LoadExtension(extension_path)); 306 307 // Any navigation prompts the location bar to load the page action. 308 GURL url = test_server()->GetURL(kLocalization); 309 ui_test_utils::NavigateToURL(browser(), url); 310 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 311 312 ASSERT_EQ(size_before + 1, service->extensions()->size()); 313 const Extension* extension = service->extensions()->at(size_before); 314 315 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n page action").c_str(), 316 extension->description().c_str()); 317 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur is my name").c_str(), 318 extension->name().c_str()); 319 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 320 EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur").c_str(), 321 extension->page_action()->GetTitle(tab_id).c_str()); 322 } 323 324 GURL GetFeedUrl(net::TestServer* server, const std::string& feed_page, 325 bool direct_url, std::string extension_id) { 326 GURL feed_url = server->GetURL(feed_page); 327 if (direct_url) { 328 // We navigate directly to the subscribe page for feeds where the feed 329 // sniffing won't work, in other words, as is the case for malformed feeds. 330 return GURL(std::string(chrome::kExtensionScheme) + 331 chrome::kStandardSchemeSeparator + 332 extension_id + std::string(kSubscribePage) + std::string("?") + 333 feed_url.spec() + std::string("&synchronous")); 334 } else { 335 // Navigate to the feed content (which will cause the extension to try to 336 // sniff the type and display the subscribe page in another tab. 337 return GURL(feed_url.spec()); 338 } 339 } 340 341 static const wchar_t* jscript_feed_title = 342 L"window.domAutomationController.send(" 343 L" document.getElementById('title') ? " 344 L" document.getElementById('title').textContent : " 345 L" \"element 'title' not found\"" 346 L");"; 347 static const wchar_t* jscript_anchor = 348 L"window.domAutomationController.send(" 349 L" document.getElementById('anchor_0') ? " 350 L" document.getElementById('anchor_0').textContent : " 351 L" \"element 'anchor_0' not found\"" 352 L");"; 353 static const wchar_t* jscript_desc = 354 L"window.domAutomationController.send(" 355 L" document.getElementById('desc_0') ? " 356 L" document.getElementById('desc_0').textContent : " 357 L" \"element 'desc_0' not found\"" 358 L");"; 359 static const wchar_t* jscript_error = 360 L"window.domAutomationController.send(" 361 L" document.getElementById('error') ? " 362 L" document.getElementById('error').textContent : " 363 L" \"No error\"" 364 L");"; 365 366 bool ValidatePageElement(TabContents* tab, 367 const std::wstring& frame, 368 const std::wstring& javascript, 369 const std::string& expected_value) { 370 std::string returned_value; 371 std::string error; 372 373 if (!ui_test_utils::ExecuteJavaScriptAndExtractString( 374 tab->render_view_host(), 375 frame, 376 javascript, &returned_value)) 377 return false; 378 379 EXPECT_STREQ(expected_value.c_str(), returned_value.c_str()); 380 return expected_value == returned_value; 381 } 382 383 // Navigates to a feed page and, if |sniff_xml_type| is set, wait for the 384 // extension to kick in, detect the feed and redirect to a feed preview page. 385 // |sniff_xml_type| is generally set to true if the feed is sniffable and false 386 // for invalid feeds. 387 void NavigateToFeedAndValidate(net::TestServer* server, 388 const std::string& url, 389 Browser* browser, 390 bool sniff_xml_type, 391 const std::string& expected_feed_title, 392 const std::string& expected_item_title, 393 const std::string& expected_item_desc, 394 const std::string& expected_error) { 395 if (sniff_xml_type) { 396 // TODO(finnur): Implement this is a non-flaky way. 397 } 398 399 ExtensionService* service = browser->profile()->GetExtensionService(); 400 const Extension* extension = service->extensions()->back(); 401 std::string id = extension->id(); 402 403 // Navigate to the subscribe page directly. 404 ui_test_utils::NavigateToURL(browser, GetFeedUrl(server, url, true, id)); 405 406 TabContents* tab = browser->GetSelectedTabContents(); 407 ASSERT_TRUE(ValidatePageElement(tab, 408 L"", 409 jscript_feed_title, 410 expected_feed_title)); 411 ASSERT_TRUE(ValidatePageElement(tab, 412 L"//html/body/div/iframe[1]", 413 jscript_anchor, 414 expected_item_title)); 415 ASSERT_TRUE(ValidatePageElement(tab, 416 L"//html/body/div/iframe[1]", 417 jscript_desc, 418 expected_item_desc)); 419 ASSERT_TRUE(ValidatePageElement(tab, 420 L"//html/body/div/iframe[1]", 421 jscript_error, 422 expected_error)); 423 } 424 425 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed1) { 426 ASSERT_TRUE(test_server()->Start()); 427 428 ASSERT_TRUE(LoadExtension( 429 test_data_dir_.AppendASCII("subscribe_page_action"))); 430 431 NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), true, 432 "Feed for MyFeedTitle", 433 "Title 1", 434 "Desc", 435 "No error"); 436 } 437 438 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed2) { 439 ASSERT_TRUE(test_server()->Start()); 440 441 ASSERT_TRUE(LoadExtension( 442 test_data_dir_.AppendASCII("subscribe_page_action"))); 443 444 NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), true, 445 "Feed for MyFeed2", 446 "My item title1", 447 "This is a summary.", 448 "No error"); 449 } 450 451 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed3) { 452 ASSERT_TRUE(test_server()->Start()); 453 454 ASSERT_TRUE(LoadExtension( 455 test_data_dir_.AppendASCII("subscribe_page_action"))); 456 457 NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), true, 458 "Feed for Google Code buglist rss feed", 459 "My dear title", 460 "My dear content", 461 "No error"); 462 } 463 464 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed4) { 465 ASSERT_TRUE(test_server()->Start()); 466 467 ASSERT_TRUE(LoadExtension( 468 test_data_dir_.AppendASCII("subscribe_page_action"))); 469 470 NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), true, 471 "Feed for Title chars <script> %23 stop", 472 "Title chars %23 stop", 473 "My dear content %23 stop", 474 "No error"); 475 } 476 477 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed0) { 478 ASSERT_TRUE(test_server()->Start()); 479 480 ASSERT_TRUE(LoadExtension( 481 test_data_dir_.AppendASCII("subscribe_page_action"))); 482 483 // Try a feed with a link with an onclick handler (before r27440 this would 484 // trigger a NOTREACHED). 485 NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), true, 486 "Feed for MyFeedTitle", 487 "Title 1", 488 "Desc VIDEO", 489 "No error"); 490 } 491 492 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed5) { 493 ASSERT_TRUE(test_server()->Start()); 494 495 ASSERT_TRUE(LoadExtension( 496 test_data_dir_.AppendASCII("subscribe_page_action"))); 497 498 // Feed with valid but mostly empty xml. 499 NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), true, 500 "Feed for Unknown feed name", 501 "element 'anchor_0' not found", 502 "element 'desc_0' not found", 503 "This feed contains no entries."); 504 } 505 506 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed6) { 507 ASSERT_TRUE(test_server()->Start()); 508 509 ASSERT_TRUE(LoadExtension( 510 test_data_dir_.AppendASCII("subscribe_page_action"))); 511 512 // Feed that is technically invalid but still parseable. 513 NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), true, 514 "Feed for MyFeedTitle", 515 "Title 1", 516 "Desc", 517 "No error"); 518 } 519 520 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed1) { 521 ASSERT_TRUE(test_server()->Start()); 522 523 ASSERT_TRUE(LoadExtension( 524 test_data_dir_.AppendASCII("subscribe_page_action"))); 525 526 // Try an empty feed. 527 NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), false, 528 "Feed for Unknown feed name", 529 "element 'anchor_0' not found", 530 "element 'desc_0' not found", 531 "This feed contains no entries."); 532 } 533 534 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed2) { 535 ASSERT_TRUE(test_server()->Start()); 536 537 ASSERT_TRUE(LoadExtension( 538 test_data_dir_.AppendASCII("subscribe_page_action"))); 539 540 // Try a garbage feed. 541 NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), false, 542 "Feed for Unknown feed name", 543 "element 'anchor_0' not found", 544 "element 'desc_0' not found", 545 "This feed contains no entries."); 546 } 547 548 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed3) { 549 ASSERT_TRUE(test_server()->Start()); 550 551 ASSERT_TRUE(LoadExtension( 552 test_data_dir_.AppendASCII("subscribe_page_action"))); 553 554 // Try a feed that doesn't exist. 555 NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), false, 556 "Feed for Unknown feed name", 557 "element 'anchor_0' not found", 558 "element 'desc_0' not found", 559 "This feed contains no entries."); 560 } 561 562 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed4) { 563 ASSERT_TRUE(test_server()->Start()); 564 565 ASSERT_TRUE(LoadExtension( 566 test_data_dir_.AppendASCII("subscribe_page_action"))); 567 568 // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed 569 // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome 570 // will result in no feed being downloaded because %23 gets decoded to # and 571 // therefore #chrome is not treated as part of the Twitter query. This test 572 // uses an underscore instead of a hash, but the principle is the same. If 573 // we start erroneously double decoding again, the path (and the feed) will 574 // become valid resulting in a failure for this test. 575 NavigateToFeedAndValidate(test_server(), kFeedTripleEncoded, browser(), true, 576 "Feed for Unknown feed name", 577 "element 'anchor_0' not found", 578 "element 'desc_0' not found", 579 "This feed contains no entries."); 580 } 581 582 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeedNoLinks) { 583 ASSERT_TRUE(test_server()->Start()); 584 585 ASSERT_TRUE(LoadExtension( 586 test_data_dir_.AppendASCII("subscribe_page_action"))); 587 588 // Valid feed but containing no links. 589 NavigateToFeedAndValidate(test_server(), kValidFeedNoLinks, browser(), true, 590 "Feed for MyFeedTitle", 591 "Title with no link", 592 "Desc", 593 "No error"); 594 } 595 596 // Tests that an error raised during an async function still fires 597 // the callback, but sets chrome.extension.lastError. 598 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, LastError) { 599 ASSERT_TRUE(LoadExtension( 600 test_data_dir_.AppendASCII("browsertest").AppendASCII("last_error"))); 601 602 // Get the ExtensionHost that is hosting our toolstrip page. 603 ExtensionProcessManager* manager = 604 browser()->profile()->GetExtensionProcessManager(); 605 ExtensionHost* host = FindHostWithPath(manager, "/bg.html", 1); 606 607 bool result = false; 608 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 609 host->render_view_host(), L"", L"testLastError()", &result)); 610 EXPECT_TRUE(result); 611 } 612 613 // Helper function for common code shared by the 3 WindowOpen tests below. 614 static void WindowOpenHelper(Browser* browser, const GURL& start_url, 615 const std::string& newtab_url, 616 TabContents** newtab_result) { 617 ui_test_utils::NavigateToURL(browser, start_url); 618 619 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 620 browser->GetSelectedTabContents()->render_view_host(), L"", 621 L"window.open('" + UTF8ToWide(newtab_url) + L"');")); 622 623 // Now the active tab in last active window should be the new tab. 624 Browser* last_active_browser = BrowserList::GetLastActive(); 625 EXPECT_TRUE(last_active_browser); 626 TabContents* newtab = last_active_browser->GetSelectedTabContents(); 627 EXPECT_TRUE(newtab); 628 GURL expected_url = start_url.Resolve(newtab_url); 629 if (!newtab->controller().GetLastCommittedEntry() || 630 newtab->controller().GetLastCommittedEntry()->url() != expected_url) 631 ui_test_utils::WaitForNavigation(&newtab->controller()); 632 EXPECT_EQ(expected_url, 633 newtab->controller().GetLastCommittedEntry()->url()); 634 if (newtab_result) 635 *newtab_result = newtab; 636 } 637 638 // Tests that an extension page can call window.open to an extension URL and 639 // the new window has extension privileges. 640 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) { 641 ASSERT_TRUE(LoadExtension( 642 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 643 644 TabContents* newtab; 645 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 646 browser(), 647 GURL(std::string("chrome-extension://") + last_loaded_extension_id_ + 648 "/test.html"), 649 "newtab.html", &newtab)); 650 651 bool result = false; 652 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 653 newtab->render_view_host(), L"", L"testExtensionApi()", &result)); 654 EXPECT_TRUE(result); 655 } 656 657 // Tests that if an extension page calls window.open to an invalid extension 658 // URL, the browser doesn't crash. 659 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) { 660 ASSERT_TRUE(LoadExtension( 661 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 662 663 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 664 browser(), 665 GURL(std::string("chrome-extension://") + last_loaded_extension_id_ + 666 "/test.html"), 667 "chrome-extension://thisissurelynotavalidextensionid/newtab.html", NULL)); 668 669 // If we got to this point, we didn't crash, so we're good. 670 } 671 672 // Tests that calling window.open from the newtab page to an extension URL 673 // gives the new window extension privileges - even though the opening page 674 // does not have extension privileges, we break the script connection, so 675 // there is no privilege leak. 676 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) { 677 ASSERT_TRUE(LoadExtension( 678 test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); 679 680 TabContents* newtab; 681 ASSERT_NO_FATAL_FAILURE(WindowOpenHelper( 682 browser(), 683 GURL("about:blank"), 684 std::string("chrome-extension://") + last_loaded_extension_id_ + 685 "/newtab.html", 686 &newtab)); 687 688 // Extension API should succeed. 689 bool result = false; 690 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 691 newtab->render_view_host(), L"", L"testExtensionApi()", &result)); 692 EXPECT_TRUE(result); 693 } 694 695 #if defined(OS_WIN) 696 #define MAYBE_PluginLoadUnload PluginLoadUnload 697 #elif defined(OS_LINUX) 698 // http://crbug.com/47598 699 #define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload 700 #else 701 // TODO(mpcomplete): http://crbug.com/29900 need cross platform plugin support. 702 #define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload 703 #endif 704 705 // Tests that a renderer's plugin list is properly updated when we load and 706 // unload an extension that contains a plugin. 707 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginLoadUnload) { 708 FilePath extension_dir = 709 test_data_dir_.AppendASCII("uitest").AppendASCII("plugins"); 710 711 ui_test_utils::NavigateToURL(browser(), 712 net::FilePathToFileURL(extension_dir.AppendASCII("test.html"))); 713 TabContents* tab = browser()->GetSelectedTabContents(); 714 715 // With no extensions, the plugin should not be loaded. 716 bool result = false; 717 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 718 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 719 EXPECT_FALSE(result); 720 721 ExtensionService* service = browser()->profile()->GetExtensionService(); 722 const size_t size_before = service->extensions()->size(); 723 ASSERT_TRUE(LoadExtension(extension_dir)); 724 EXPECT_EQ(size_before + 1, service->extensions()->size()); 725 // Now the plugin should be in the cache, but we have to reload the page for 726 // it to work. 727 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 728 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 729 EXPECT_FALSE(result); 730 browser()->Reload(CURRENT_TAB); 731 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 732 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 733 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 734 EXPECT_TRUE(result); 735 736 EXPECT_EQ(size_before + 1, service->extensions()->size()); 737 UnloadExtension(service->extensions()->at(size_before)->id()); 738 EXPECT_EQ(size_before, service->extensions()->size()); 739 740 // Now the plugin should be unloaded, and the page should be broken. 741 742 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 743 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 744 EXPECT_FALSE(result); 745 746 // If we reload the extension and page, it should work again. 747 748 ASSERT_TRUE(LoadExtension(extension_dir)); 749 EXPECT_EQ(size_before + 1, service->extensions()->size()); 750 browser()->Reload(CURRENT_TAB); 751 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 752 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 753 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 754 EXPECT_TRUE(result); 755 } 756 757 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) 758 #define MAYBE_PluginPrivate PluginPrivate 759 #else 760 // TODO(mpcomplete): http://crbug.com/29900 need cross platform plugin support. 761 #define MAYBE_PluginPrivate DISABLED_PluginPrivate 762 #endif 763 764 // Tests that private extension plugins are only visible to the extension. 765 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginPrivate) { 766 FilePath extension_dir = 767 test_data_dir_.AppendASCII("uitest").AppendASCII("plugins_private"); 768 769 ExtensionService* service = browser()->profile()->GetExtensionService(); 770 const size_t size_before = service->extensions()->size(); 771 ASSERT_TRUE(LoadExtension(extension_dir)); 772 EXPECT_EQ(size_before + 1, service->extensions()->size()); 773 774 // Load the test page through the extension URL, and the plugin should work. 775 const Extension* extension = service->extensions()->back(); 776 ui_test_utils::NavigateToURL(browser(), 777 extension->GetResourceURL("test.html")); 778 TabContents* tab = browser()->GetSelectedTabContents(); 779 bool result = false; 780 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 781 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 782 // We don't allow extension plugins to run on ChromeOS. 783 #if defined(OS_CHROMEOS) 784 EXPECT_FALSE(result); 785 #else 786 EXPECT_TRUE(result); 787 #endif 788 789 // Now load it through a file URL. The plugin should not load. 790 ui_test_utils::NavigateToURL(browser(), 791 net::FilePathToFileURL(extension_dir.AppendASCII("test.html"))); 792 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 793 tab->render_view_host(), L"", L"testPluginWorks()", &result)); 794 EXPECT_FALSE(result); 795 } 796 797 // Used to simulate a click on the first button named 'Options'. 798 static const wchar_t* jscript_click_option_button = 799 L"(function() { " 800 L" var button = document.evaluate(\"//button[text()='Options']\"," 801 L" document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE," 802 L" null).snapshotItem(0);" 803 L" button.click();" 804 L"})();"; 805 806 // Test that an extension with an options page makes an 'Options' button appear 807 // on chrome://extensions, and that clicking the button opens a new tab with the 808 // extension's options page. 809 // Disabled. See http://crbug.com/26948 for details. 810 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) { 811 // Install an extension with an options page. 812 ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("options.crx"), 1)); 813 ExtensionService* service = browser()->profile()->GetExtensionService(); 814 const ExtensionList* extensions = service->extensions(); 815 ASSERT_EQ(1u, extensions->size()); 816 const Extension* extension = extensions->at(0); 817 818 // Go to the chrome://extensions page and click the Options button. 819 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL)); 820 TabStripModel* tab_strip = browser()->tabstrip_model(); 821 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 822 browser()->GetSelectedTabContents()->render_view_host(), L"", 823 jscript_click_option_button)); 824 825 // If the options page hasn't already come up, wait for it. 826 if (tab_strip->count() == 1) { 827 ui_test_utils::WaitForNewTab(browser()); 828 } 829 ASSERT_EQ(2, tab_strip->count()); 830 831 EXPECT_EQ(extension->GetResourceURL("options.html"), 832 tab_strip->GetTabContentsAt(1)->tab_contents()->GetURL()); 833 } 834 835 //============================================================================== 836 // STOP! Please do not add any more random-ass tests here. Create new files for 837 // your tests grouped by functionality. Also, you should strongly consider using 838 // ExtensionAPITest if possible. 839 //============================================================================== 840