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