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         content::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(WebContents* tab,
     80                          const std::string& frame_xpath,
     81                          const std::string& javascript,
     82                          const std::string& expected_value) {
     83   std::string returned_value;
     84 
     85   if (!content::ExecuteScriptInFrameAndExtractString(tab, frame_xpath,
     86                                                      javascript,
     87                                                      &returned_value))
     88     return false;
     89 
     90   EXPECT_STREQ(expected_value.c_str(), returned_value.c_str());
     91   return expected_value == returned_value;
     92 }
     93 
     94 // Navigates to a feed page and, if |sniff_xml_type| is set, wait for the
     95 // extension to kick in, detect the feed and redirect to a feed preview page.
     96 // |sniff_xml_type| is generally set to true if the feed is sniffable and false
     97 // for invalid feeds.
     98 void NavigateToFeedAndValidate(net::SpawnedTestServer* server,
     99                                const std::string& url,
    100                                Browser* browser,
    101                                std::string extension_id,
    102                                bool sniff_xml_type,
    103                                const std::string& expected_feed_title,
    104                                const std::string& expected_item_title,
    105                                const std::string& expected_item_desc,
    106                                const std::string& expected_error) {
    107   if (sniff_xml_type) {
    108     // TODO(finnur): Implement this is a non-flaky way.
    109   }
    110 
    111   // Navigate to the subscribe page directly.
    112   ui_test_utils::NavigateToURL(browser,
    113                                GetFeedUrl(server, url, true, extension_id));
    114 
    115   WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
    116   ASSERT_TRUE(ValidatePageElement(
    117       tab, std::string(), kScriptFeedTitle, expected_feed_title));
    118   ASSERT_TRUE(ValidatePageElement(tab,
    119                                   "//html/body/div/iframe[1]",
    120                                   kScriptAnchor,
    121                                   expected_item_title));
    122   ASSERT_TRUE(ValidatePageElement(tab,
    123                                   "//html/body/div/iframe[1]",
    124                                   kScriptDesc,
    125                                   expected_item_desc));
    126   ASSERT_TRUE(ValidatePageElement(tab,
    127                                   "//html/body/div/iframe[1]",
    128                                   kScriptError,
    129                                   expected_error));
    130 }
    131 
    132 } // namespace
    133 
    134 // Makes sure that the RSS detects RSS feed links, even when rel tag contains
    135 // more than just "alternate".
    136 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
    137   ASSERT_TRUE(test_server()->Start());
    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(kFeedPageMultiRel);
    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 
    151 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed1) {
    152   ASSERT_TRUE(test_server()->Start());
    153 
    154   const Extension* extension = LoadExtension(
    155       test_data_dir_.AppendASCII("subscribe_page_action"));
    156   ASSERT_TRUE(extension);
    157   std::string id = extension->id();
    158 
    159   NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), id, true,
    160                             "Feed for MyFeedTitle",
    161                             "Title 1",
    162                             "Desc",
    163                             "No error");
    164 }
    165 
    166 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed2) {
    167   ASSERT_TRUE(test_server()->Start());
    168 
    169   const Extension* extension = LoadExtension(
    170       test_data_dir_.AppendASCII("subscribe_page_action"));
    171   ASSERT_TRUE(extension);
    172   std::string id = extension->id();
    173 
    174   NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), id, true,
    175                             "Feed for MyFeed2",
    176                             "My item title1",
    177                             "This is a summary.",
    178                             "No error");
    179 }
    180 
    181 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed3) {
    182   ASSERT_TRUE(test_server()->Start());
    183 
    184   const Extension* extension = LoadExtension(
    185       test_data_dir_.AppendASCII("subscribe_page_action"));
    186   ASSERT_TRUE(extension);
    187   std::string id = extension->id();
    188 
    189   NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), id, true,
    190                             "Feed for Google Code buglist rss feed",
    191                             "My dear title",
    192                             "My dear content",
    193                             "No error");
    194 }
    195 
    196 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed4) {
    197   ASSERT_TRUE(test_server()->Start());
    198 
    199   const Extension* extension = LoadExtension(
    200       test_data_dir_.AppendASCII("subscribe_page_action"));
    201   ASSERT_TRUE(extension);
    202   std::string id = extension->id();
    203 
    204   NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), id, true,
    205                             "Feed for Title chars <script> %23 stop",
    206                             "Title chars  %23 stop",
    207                             "My dear content %23 stop",
    208                             "No error");
    209 }
    210 
    211 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed0) {
    212   ASSERT_TRUE(test_server()->Start());
    213 
    214   const Extension* extension = LoadExtension(
    215       test_data_dir_.AppendASCII("subscribe_page_action"));
    216   ASSERT_TRUE(extension);
    217   std::string id = extension->id();
    218 
    219   // Try a feed with a link with an onclick handler (before r27440 this would
    220   // trigger a NOTREACHED).
    221   NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), id, true,
    222                             "Feed for MyFeedTitle",
    223                             "Title 1",
    224                             "Desc VIDEO",
    225                             "No error");
    226 }
    227 
    228 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed5) {
    229   ASSERT_TRUE(test_server()->Start());
    230 
    231   const Extension* extension = LoadExtension(
    232       test_data_dir_.AppendASCII("subscribe_page_action"));
    233   ASSERT_TRUE(extension);
    234   std::string id = extension->id();
    235 
    236   // Feed with valid but mostly empty xml.
    237   NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), id, true,
    238                             "Feed for Unknown feed name",
    239                             "element 'anchor_0' not found",
    240                             "element 'desc_0' not found",
    241                             "This feed contains no entries.");
    242 }
    243 
    244 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed6) {
    245   ASSERT_TRUE(test_server()->Start());
    246 
    247   const Extension* extension = LoadExtension(
    248       test_data_dir_.AppendASCII("subscribe_page_action"));
    249   ASSERT_TRUE(extension);
    250   std::string id = extension->id();
    251 
    252   // Feed that is technically invalid but still parseable.
    253   NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), id, true,
    254                             "Feed for MyFeedTitle",
    255                             "Title 1",
    256                             "Desc",
    257                             "No error");
    258 }
    259 
    260 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed1) {
    261   ASSERT_TRUE(test_server()->Start());
    262 
    263   const Extension* extension = LoadExtension(
    264       test_data_dir_.AppendASCII("subscribe_page_action"));
    265   ASSERT_TRUE(extension);
    266   std::string id = extension->id();
    267 
    268   // Try an empty feed.
    269   NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), id, false,
    270                             "Feed for Unknown feed name",
    271                             "element 'anchor_0' not found",
    272                             "element 'desc_0' not found",
    273                             "This feed contains no entries.");
    274 }
    275 
    276 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed2) {
    277   ASSERT_TRUE(test_server()->Start());
    278 
    279   const Extension* extension = LoadExtension(
    280       test_data_dir_.AppendASCII("subscribe_page_action"));
    281   ASSERT_TRUE(extension);
    282   std::string id = extension->id();
    283 
    284   // Try a garbage feed.
    285   NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), id, false,
    286                             "Feed for Unknown feed name",
    287                             "element 'anchor_0' not found",
    288                             "element 'desc_0' not found",
    289                             "This feed contains no entries.");
    290 }
    291 
    292 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed3) {
    293   ASSERT_TRUE(test_server()->Start());
    294 
    295   const Extension* extension = LoadExtension(
    296       test_data_dir_.AppendASCII("subscribe_page_action"));
    297   ASSERT_TRUE(extension);
    298   std::string id = extension->id();
    299 
    300   // Try a feed that doesn't exist.
    301   NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), id, false,
    302                             "Feed for Unknown feed name",
    303                             "element 'anchor_0' not found",
    304                             "element 'desc_0' not found",
    305                             "This feed contains no entries.");
    306 }
    307 
    308 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed4) {
    309   ASSERT_TRUE(test_server()->Start());
    310 
    311   const Extension* extension = LoadExtension(
    312       test_data_dir_.AppendASCII("subscribe_page_action"));
    313   ASSERT_TRUE(extension);
    314   std::string id = extension->id();
    315 
    316   // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed
    317   // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome
    318   // will result in no feed being downloaded because %23 gets decoded to # and
    319   // therefore #chrome is not treated as part of the Twitter query. This test
    320   // uses an underscore instead of a hash, but the principle is the same. If
    321   // we start erroneously double decoding again, the path (and the feed) will
    322   // become valid resulting in a failure for this test.
    323   NavigateToFeedAndValidate(
    324       test_server(), kFeedTripleEncoded, browser(), id, true,
    325       "Feed for Unknown feed name",
    326       "element 'anchor_0' not found",
    327       "element 'desc_0' not found",
    328       "This feed contains no entries.");
    329 }
    330 
    331 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeedNoLinks) {
    332   ASSERT_TRUE(test_server()->Start());
    333 
    334   const Extension* extension = LoadExtension(
    335       test_data_dir_.AppendASCII("subscribe_page_action"));
    336   ASSERT_TRUE(extension);
    337   std::string id = extension->id();
    338 
    339   // Valid feed but containing no links.
    340   NavigateToFeedAndValidate(
    341       test_server(), kValidFeedNoLinks, browser(), id, true,
    342       "Feed for MyFeedTitle",
    343       "Title with no link",
    344       "Desc",
    345       "No error");
    346 }
    347