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