Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/extension_browsertest.h"
      6 #include "chrome/browser/ui/browser.h"
      7 #include "chrome/browser/ui/tabs/tab_strip_model.h"
      8 #include "chrome/common/url_constants.h"
      9 #include "chrome/test/base/ui_test_utils.h"
     10 #include "content/public/browser/web_contents.h"
     11 #include "content/public/test/browser_test_utils.h"
     12 #include "extensions/common/constants.h"
     13 #include "extensions/common/extension.h"
     14 
     15 using content::WebContents;
     16 using extensions::Extension;
     17 
     18 namespace {
     19 
     20 const char kSubscribePage[] = "/subscribe.html";
     21 const char kFeedPageMultiRel[] = "files/feeds/feed_multi_rel.html";
     22 const char kValidFeedNoLinks[] = "files/feeds/feed_nolinks.xml";
     23 const char kValidFeed0[] = "files/feeds/feed_script.xml";
     24 const char kValidFeed1[] = "files/feeds/feed1.xml";
     25 const char kValidFeed2[] = "files/feeds/feed2.xml";
     26 const char kValidFeed3[] = "files/feeds/feed3.xml";
     27 const char kValidFeed4[] = "files/feeds/feed4.xml";
     28 const char kValidFeed5[] = "files/feeds/feed5.xml";
     29 const char kValidFeed6[] = "files/feeds/feed6.xml";
     30 const char kInvalidFeed1[] = "files/feeds/feed_invalid1.xml";
     31 const char kInvalidFeed2[] = "files/feeds/feed_invalid2.xml";
     32 // We need a triple encoded string to prove that we are not decoding twice in
     33 // subscribe.js because one layer is also stripped off when subscribe.js passes
     34 // it to the XMLHttpRequest object.
     35 const char kFeedTripleEncoded[] = "files/feeds/url%25255Fdecoding.html";
     36 
     37 static const char kScriptFeedTitle[] =
     38     "window.domAutomationController.send("
     39     "  document.getElementById('title') ? "
     40     "    document.getElementById('title').textContent : "
     41     "    \"element 'title' not found\""
     42     ");";
     43 static const char kScriptAnchor[] =
     44     "window.domAutomationController.send("
     45     "  document.getElementById('anchor_0') ? "
     46     "    document.getElementById('anchor_0').textContent : "
     47     "    \"element 'anchor_0' not found\""
     48     ");";
     49 static const char kScriptDesc[] =
     50     "window.domAutomationController.send("
     51     "  document.getElementById('desc_0') ? "
     52     "    document.getElementById('desc_0').textContent : "
     53     "    \"element 'desc_0' not found\""
     54     ");";
     55 static const char kScriptError[] =
     56     "window.domAutomationController.send("
     57     "  document.getElementById('error') ? "
     58     "    document.getElementById('error').textContent : "
     59     "    \"No error\""
     60     ");";
     61 
     62 GURL GetFeedUrl(net::SpawnedTestServer* server, const std::string& feed_page,
     63                 bool direct_url, std::string extension_id) {
     64   GURL feed_url = server->GetURL(feed_page);
     65   if (direct_url) {
     66     // We navigate directly to the subscribe page for feeds where the feed
     67     // sniffing won't work, in other words, as is the case for malformed feeds.
     68     return GURL(std::string(extensions::kExtensionScheme) +
     69         url::kStandardSchemeSeparator +
     70         extension_id + std::string(kSubscribePage) + std::string("?") +
     71         feed_url.spec() + std::string("&synchronous"));
     72   } else {
     73     // Navigate to the feed content (which will cause the extension to try to
     74     // sniff the type and display the subscribe page in another tab.
     75     return GURL(feed_url.spec());
     76   }
     77 }
     78 
     79 bool ValidatePageElement(content::RenderFrameHost* frame,
     80                          const std::string& javascript,
     81                          const std::string& expected_value) {
     82   std::string returned_value;
     83 
     84   if (!content::ExecuteScriptAndExtractString(frame,
     85                                               javascript,
     86                                               &returned_value))
     87     return false;
     88 
     89   EXPECT_STREQ(expected_value.c_str(), returned_value.c_str());
     90   return expected_value == returned_value;
     91 }
     92 
     93 // Navigates to a feed page and, if |sniff_xml_type| is set, wait for the
     94 // extension to kick in, detect the feed and redirect to a feed preview page.
     95 // |sniff_xml_type| is generally set to true if the feed is sniffable and false
     96 // for invalid feeds.
     97 void NavigateToFeedAndValidate(net::SpawnedTestServer* server,
     98                                const std::string& url,
     99                                Browser* browser,
    100                                std::string extension_id,
    101                                bool sniff_xml_type,
    102                                const std::string& expected_feed_title,
    103                                const std::string& expected_item_title,
    104                                const std::string& expected_item_desc,
    105                                const std::string& expected_error) {
    106   if (sniff_xml_type) {
    107     // TODO(finnur): Implement this is a non-flaky way.
    108   }
    109 
    110   // Navigate to the subscribe page directly.
    111   ui_test_utils::NavigateToURL(browser,
    112                                GetFeedUrl(server, url, true, extension_id));
    113 
    114   WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
    115   content::RenderFrameHost* frame = content::FrameMatchingPredicate(
    116       tab, base::Bind(&content::FrameIsChildOfMainFrame));
    117   ASSERT_TRUE(ValidatePageElement(
    118       tab->GetMainFrame(), kScriptFeedTitle, expected_feed_title));
    119   ASSERT_TRUE(ValidatePageElement(frame, kScriptAnchor, expected_item_title));
    120   ASSERT_TRUE(ValidatePageElement(frame, kScriptDesc, expected_item_desc));
    121   ASSERT_TRUE(ValidatePageElement(frame, kScriptError, expected_error));
    122 }
    123 
    124 } // namespace
    125 
    126 // Makes sure that the RSS detects RSS feed links, even when rel tag contains
    127 // more than just "alternate".
    128 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
    129   ASSERT_TRUE(test_server()->Start());
    130 
    131   ASSERT_TRUE(LoadExtension(
    132     test_data_dir_.AppendASCII("subscribe_page_action")));
    133 
    134   ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
    135 
    136   // Navigate to the feed page.
    137   GURL feed_url = test_server()->GetURL(kFeedPageMultiRel);
    138   ui_test_utils::NavigateToURL(browser(), feed_url);
    139   // We should now have one page action ready to go in the LocationBar.
    140   ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
    141 }
    142 
    143 // This test is flaky on all platforms; see http://crbug.com/340354
    144 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed1) {
    145   ASSERT_TRUE(test_server()->Start());
    146 
    147   const Extension* extension = LoadExtension(
    148       test_data_dir_.AppendASCII("subscribe_page_action"));
    149   ASSERT_TRUE(extension);
    150   std::string id = extension->id();
    151 
    152   NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), id, true,
    153                             "Feed for MyFeedTitle",
    154                             "Title 1",
    155                             "Desc",
    156                             "No error");
    157 }
    158 
    159 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed2) {
    160   ASSERT_TRUE(test_server()->Start());
    161 
    162   const Extension* extension = LoadExtension(
    163       test_data_dir_.AppendASCII("subscribe_page_action"));
    164   ASSERT_TRUE(extension);
    165   std::string id = extension->id();
    166 
    167   NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), id, true,
    168                             "Feed for MyFeed2",
    169                             "My item title1",
    170                             "This is a summary.",
    171                             "No error");
    172 }
    173 
    174 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed3) {
    175   ASSERT_TRUE(test_server()->Start());
    176 
    177   const Extension* extension = LoadExtension(
    178       test_data_dir_.AppendASCII("subscribe_page_action"));
    179   ASSERT_TRUE(extension);
    180   std::string id = extension->id();
    181 
    182   NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), id, true,
    183                             "Feed for Google Code buglist rss feed",
    184                             "My dear title",
    185                             "My dear content",
    186                             "No error");
    187 }
    188 
    189 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed4) {
    190   ASSERT_TRUE(test_server()->Start());
    191 
    192   const Extension* extension = LoadExtension(
    193       test_data_dir_.AppendASCII("subscribe_page_action"));
    194   ASSERT_TRUE(extension);
    195   std::string id = extension->id();
    196 
    197   NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), id, true,
    198                             "Feed for Title chars <script> %23 stop",
    199                             "Title chars  %23 stop",
    200                             "My dear content %23 stop",
    201                             "No error");
    202 }
    203 
    204 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed0) {
    205   ASSERT_TRUE(test_server()->Start());
    206 
    207   const Extension* extension = LoadExtension(
    208       test_data_dir_.AppendASCII("subscribe_page_action"));
    209   ASSERT_TRUE(extension);
    210   std::string id = extension->id();
    211 
    212   // Try a feed with a link with an onclick handler (before r27440 this would
    213   // trigger a NOTREACHED).
    214   NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), id, true,
    215                             "Feed for MyFeedTitle",
    216                             "Title 1",
    217                             "Desc VIDEO",
    218                             "No error");
    219 }
    220 
    221 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed5) {
    222   ASSERT_TRUE(test_server()->Start());
    223 
    224   const Extension* extension = LoadExtension(
    225       test_data_dir_.AppendASCII("subscribe_page_action"));
    226   ASSERT_TRUE(extension);
    227   std::string id = extension->id();
    228 
    229   // Feed with valid but mostly empty xml.
    230   NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), id, true,
    231                             "Feed for Unknown feed name",
    232                             "element 'anchor_0' not found",
    233                             "element 'desc_0' not found",
    234                             "This feed contains no entries.");
    235 }
    236 
    237 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed6) {
    238   ASSERT_TRUE(test_server()->Start());
    239 
    240   const Extension* extension = LoadExtension(
    241       test_data_dir_.AppendASCII("subscribe_page_action"));
    242   ASSERT_TRUE(extension);
    243   std::string id = extension->id();
    244 
    245   // Feed that is technically invalid but still parseable.
    246   NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), id, true,
    247                             "Feed for MyFeedTitle",
    248                             "Title 1",
    249                             "Desc",
    250                             "No error");
    251 }
    252 
    253 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed1) {
    254   ASSERT_TRUE(test_server()->Start());
    255 
    256   const Extension* extension = LoadExtension(
    257       test_data_dir_.AppendASCII("subscribe_page_action"));
    258   ASSERT_TRUE(extension);
    259   std::string id = extension->id();
    260 
    261   // Try an empty feed.
    262   NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), id, false,
    263                             "Feed for Unknown feed name",
    264                             "element 'anchor_0' not found",
    265                             "element 'desc_0' not found",
    266                             "This feed contains no entries.");
    267 }
    268 
    269 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed2) {
    270   ASSERT_TRUE(test_server()->Start());
    271 
    272   const Extension* extension = LoadExtension(
    273       test_data_dir_.AppendASCII("subscribe_page_action"));
    274   ASSERT_TRUE(extension);
    275   std::string id = extension->id();
    276 
    277   // Try a garbage feed.
    278   NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), id, false,
    279                             "Feed for Unknown feed name",
    280                             "element 'anchor_0' not found",
    281                             "element 'desc_0' not found",
    282                             "This feed contains no entries.");
    283 }
    284 
    285 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed3) {
    286   ASSERT_TRUE(test_server()->Start());
    287 
    288   const Extension* extension = LoadExtension(
    289       test_data_dir_.AppendASCII("subscribe_page_action"));
    290   ASSERT_TRUE(extension);
    291   std::string id = extension->id();
    292 
    293   // Try a feed that doesn't exist.
    294   NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), id, false,
    295                             "Feed for Unknown feed name",
    296                             "element 'anchor_0' not found",
    297                             "element 'desc_0' not found",
    298                             "This feed contains no entries.");
    299 }
    300 
    301 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed4) {
    302   ASSERT_TRUE(test_server()->Start());
    303 
    304   const Extension* extension = LoadExtension(
    305       test_data_dir_.AppendASCII("subscribe_page_action"));
    306   ASSERT_TRUE(extension);
    307   std::string id = extension->id();
    308 
    309   // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed
    310   // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome
    311   // will result in no feed being downloaded because %23 gets decoded to # and
    312   // therefore #chrome is not treated as part of the Twitter query. This test
    313   // uses an underscore instead of a hash, but the principle is the same. If
    314   // we start erroneously double decoding again, the path (and the feed) will
    315   // become valid resulting in a failure for this test.
    316   NavigateToFeedAndValidate(
    317       test_server(), kFeedTripleEncoded, browser(), id, true,
    318       "Feed for Unknown feed name",
    319       "element 'anchor_0' not found",
    320       "element 'desc_0' not found",
    321       "This feed contains no entries.");
    322 }
    323 
    324 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeedNoLinks) {
    325   ASSERT_TRUE(test_server()->Start());
    326 
    327   const Extension* extension = LoadExtension(
    328       test_data_dir_.AppendASCII("subscribe_page_action"));
    329   ASSERT_TRUE(extension);
    330   std::string id = extension->id();
    331 
    332   // Valid feed but containing no links.
    333   NavigateToFeedAndValidate(
    334       test_server(), kValidFeedNoLinks, browser(), id, true,
    335       "Feed for MyFeedTitle",
    336       "Title with no link",
    337       "Desc",
    338       "No error");
    339 }
    340