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 "base/command_line.h" 6 #include "base/files/file_path.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/bookmarks/bookmark_model.h" 9 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 10 #include "chrome/browser/bookmarks/bookmark_utils.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/browser_action_test_util.h" 13 #include "chrome/browser/extensions/extension_apitest.h" 14 #include "chrome/browser/extensions/extension_host.h" 15 #include "chrome/browser/extensions/extension_service.h" 16 #include "chrome/browser/extensions/extension_system.h" 17 #include "chrome/browser/extensions/extension_test_message_listener.h" 18 #include "chrome/browser/extensions/lazy_background_page_test_util.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/ui/browser.h" 21 #include "chrome/browser/ui/browser_window.h" 22 #include "chrome/browser/ui/omnibox/location_bar.h" 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/extensions/extension.h" 26 #include "chrome/common/url_constants.h" 27 #include "chrome/test/base/ui_test_utils.h" 28 #include "content/public/browser/notification_service.h" 29 #include "content/public/browser/web_contents.h" 30 #include "content/public/test/browser_test_utils.h" 31 #include "net/dns/mock_host_resolver.h" 32 #include "net/test/embedded_test_server/embedded_test_server.h" 33 #include "url/gurl.h" 34 35 using extensions::Extension; 36 37 namespace { 38 39 // This unfortunate bit of silliness is necessary when loading an extension in 40 // incognito. The goal is to load the extension, enable incognito, then wait 41 // for both background pages to load and close. The problem is that enabling 42 // incognito involves reloading the extension - and the background pages may 43 // have already loaded once before then. So we wait until the extension is 44 // unloaded before listening to the background page notifications. 45 class LoadedIncognitoObserver : public content::NotificationObserver { 46 public: 47 explicit LoadedIncognitoObserver(Profile* profile) : profile_(profile) { 48 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 49 content::Source<Profile>(profile)); 50 } 51 52 void Wait() { 53 ASSERT_TRUE(original_complete_.get()); 54 original_complete_->Wait(); 55 incognito_complete_->Wait(); 56 } 57 58 private: 59 60 virtual void Observe( 61 int type, 62 const content::NotificationSource& source, 63 const content::NotificationDetails& details) OVERRIDE { 64 original_complete_.reset(new LazyBackgroundObserver(profile_)); 65 incognito_complete_.reset( 66 new LazyBackgroundObserver(profile_->GetOffTheRecordProfile())); 67 } 68 69 Profile* profile_; 70 content::NotificationRegistrar registrar_; 71 scoped_ptr<LazyBackgroundObserver> original_complete_; 72 scoped_ptr<LazyBackgroundObserver> incognito_complete_; 73 }; 74 75 } // namespace 76 77 class LazyBackgroundPageApiTest : public ExtensionApiTest { 78 public: 79 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 80 ExtensionApiTest::SetUpCommandLine(command_line); 81 // Set shorter delays to prevent test timeouts. 82 command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1"); 83 command_line->AppendSwitchASCII(switches::kEventPageSuspendingTime, "1"); 84 } 85 86 // Loads the extension, which temporarily starts the lazy background page 87 // to dispatch the onInstalled event. We wait until it shuts down again. 88 const Extension* LoadExtensionAndWait(const std::string& test_name) { 89 LazyBackgroundObserver page_complete; 90 base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). 91 AppendASCII(test_name); 92 const Extension* extension = LoadExtension(extdir); 93 if (extension) 94 page_complete.Wait(); 95 return extension; 96 } 97 }; 98 99 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BrowserActionCreateTab) { 100 ASSERT_TRUE(LoadExtensionAndWait("browser_action_create_tab")); 101 102 // Lazy Background Page doesn't exist yet. 103 ExtensionProcessManager* pm = 104 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 105 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 106 int num_tabs_before = browser()->tab_strip_model()->count(); 107 108 // Observe background page being created and closed after 109 // the browser action is clicked. 110 LazyBackgroundObserver page_complete; 111 BrowserActionTestUtil(browser()).Press(0); 112 page_complete.Wait(); 113 114 // Background page created a new tab before it closed. 115 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 116 EXPECT_EQ(num_tabs_before + 1, browser()->tab_strip_model()->count()); 117 EXPECT_EQ(std::string(chrome::kChromeUIExtensionsURL), 118 browser()->tab_strip_model()->GetActiveWebContents()-> 119 GetURL().spec()); 120 } 121 122 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, 123 BrowserActionCreateTabAfterCallback) { 124 ASSERT_TRUE(LoadExtensionAndWait("browser_action_with_callback")); 125 126 // Lazy Background Page doesn't exist yet. 127 ExtensionProcessManager* pm = 128 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 129 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 130 int num_tabs_before = browser()->tab_strip_model()->count(); 131 132 // Observe background page being created and closed after 133 // the browser action is clicked. 134 LazyBackgroundObserver page_complete; 135 BrowserActionTestUtil(browser()).Press(0); 136 page_complete.Wait(); 137 138 // Background page is closed after creating a new tab. 139 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 140 EXPECT_EQ(num_tabs_before + 1, browser()->tab_strip_model()->count()); 141 } 142 143 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BroadcastEvent) { 144 ASSERT_TRUE(StartEmbeddedTestServer()); 145 146 const Extension* extension = LoadExtensionAndWait("broadcast_event"); 147 ASSERT_TRUE(extension); 148 149 // Lazy Background Page doesn't exist yet. 150 ExtensionProcessManager* pm = 151 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 152 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 153 int num_page_actions = browser()->window()->GetLocationBar()-> 154 GetLocationBarForTesting()->PageActionVisibleCount(); 155 156 // Open a tab to a URL that will trigger the page action to show. 157 LazyBackgroundObserver page_complete; 158 content::WindowedNotificationObserver page_action_changed( 159 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, 160 content::NotificationService::AllSources()); 161 ui_test_utils::NavigateToURL( 162 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 163 page_complete.Wait(); 164 165 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 166 167 // Page action is shown. 168 page_action_changed.Wait(); 169 EXPECT_EQ(num_page_actions + 1, 170 browser()->window()->GetLocationBar()-> 171 GetLocationBarForTesting()->PageActionVisibleCount()); 172 } 173 174 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Filters) { 175 const Extension* extension = LoadExtensionAndWait("filters"); 176 ASSERT_TRUE(extension); 177 178 // Lazy Background Page doesn't exist yet. 179 ExtensionProcessManager* pm = 180 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 181 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 182 183 // Open a tab to a URL that will fire a webNavigation event. 184 LazyBackgroundObserver page_complete; 185 ui_test_utils::NavigateToURL( 186 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 187 page_complete.Wait(); 188 } 189 190 // Tests that the lazy background page receives the onInstalled event and shuts 191 // down. 192 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, OnInstalled) { 193 ResultCatcher catcher; 194 ASSERT_TRUE(LoadExtensionAndWait("on_installed")); 195 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 196 197 // Lazy Background Page has been shut down. 198 ExtensionProcessManager* pm = 199 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 200 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 201 } 202 203 // Tests that the lazy background page stays alive until all visible views are 204 // closed. 205 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForView) { 206 LazyBackgroundObserver page_complete; 207 ResultCatcher catcher; 208 base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). 209 AppendASCII("wait_for_view"); 210 const Extension* extension = LoadExtension(extdir); 211 ASSERT_TRUE(extension); 212 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 213 214 // The extension should've opened a new tab to an extension page. 215 EXPECT_EQ(extension->GetResourceURL("extension_page.html").spec(), 216 browser()->tab_strip_model()->GetActiveWebContents()-> 217 GetURL().spec()); 218 219 // Lazy Background Page still exists, because the extension created a new tab 220 // to an extension page. 221 ExtensionProcessManager* pm = 222 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 223 EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 224 225 // Close the new tab. 226 browser()->tab_strip_model()->CloseWebContentsAt( 227 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE); 228 page_complete.Wait(); 229 230 // Lazy Background Page has been shut down. 231 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 232 } 233 234 // Tests that the lazy background page stays alive until all network requests 235 // are complete. 236 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForRequest) { 237 host_resolver()->AddRule("*", "127.0.0.1"); 238 ASSERT_TRUE(StartEmbeddedTestServer()); 239 240 LazyBackgroundObserver page_complete; 241 ResultCatcher catcher; 242 base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). 243 AppendASCII("wait_for_request"); 244 const Extension* extension = LoadExtension(extdir); 245 ASSERT_TRUE(extension); 246 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 247 248 // Lazy Background Page still exists, because the extension started a request. 249 ExtensionProcessManager* pm = 250 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 251 extensions::ExtensionHost* host = 252 pm->GetBackgroundHostForExtension(last_loaded_extension_id_); 253 ASSERT_TRUE(host); 254 255 // Abort the request. 256 bool result = false; 257 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( 258 host->render_view_host(), "abortRequest()", &result)); 259 EXPECT_TRUE(result); 260 page_complete.Wait(); 261 262 // Lazy Background Page has been shut down. 263 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 264 } 265 266 // Tests that the lazy background page stays alive until all visible views are 267 // closed. 268 // http://crbug.com/175778; test fails frequently on OS X 269 #if defined(OS_MACOSX) 270 #define MAYBE_WaitForNTP DISABLED_WaitForNTP 271 #else 272 #define MAYBE_WaitForNTP WaitForNTP 273 #endif 274 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_WaitForNTP) { 275 LazyBackgroundObserver lazybg; 276 ResultCatcher catcher; 277 base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). 278 AppendASCII("wait_for_ntp"); 279 const Extension* extension = LoadExtension(extdir); 280 ASSERT_TRUE(extension); 281 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 282 283 // The extension should've opened a new tab to an extension page. 284 EXPECT_EQ(std::string(chrome::kChromeUINewTabURL), 285 browser()->tab_strip_model()->GetActiveWebContents()-> 286 GetURL().spec()); 287 288 // Lazy Background Page still exists, because the extension created a new tab 289 // to an extension page. 290 ExtensionProcessManager* pm = 291 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 292 EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 293 294 // Navigate away from the NTP, which should close the event page. 295 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); 296 lazybg.Wait(); 297 298 // Lazy Background Page has been shut down. 299 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 300 } 301 302 // See crbug.com/248437 303 #if defined(OS_WIN) 304 #define MAYBE_IncognitoSplitMode DISABLED_IncognitoSplitMode 305 #else 306 #define MAYBE_IncognitoSplitMode IncognitoSplitMode 307 #endif 308 309 // Tests that an incognito split mode extension gets 2 lazy background pages, 310 // and they each load and unload at the proper times. 311 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_IncognitoSplitMode) { 312 // Open incognito window. 313 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord( 314 browser()->profile(), GURL("about:blank")); 315 316 // Load the extension with incognito enabled. 317 { 318 LoadedIncognitoObserver loaded(browser()->profile()); 319 base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). 320 AppendASCII("incognito_split"); 321 ASSERT_TRUE(LoadExtensionIncognito(extdir)); 322 loaded.Wait(); 323 } 324 325 // Lazy Background Page doesn't exist yet. 326 ExtensionProcessManager* pm = 327 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 328 ExtensionProcessManager* pmi = 329 extensions::ExtensionSystem::Get(incognito_browser->profile())-> 330 process_manager(); 331 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 332 EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_)); 333 334 // Trigger a browserAction event in the original profile and ensure only 335 // the original event page received it (since the event is scoped to the 336 // profile). 337 { 338 ExtensionTestMessageListener listener("waiting", false); 339 ExtensionTestMessageListener listener_incognito("waiting_incognito", false); 340 341 LazyBackgroundObserver page_complete(browser()->profile()); 342 BrowserActionTestUtil(browser()).Press(0); 343 page_complete.Wait(); 344 345 // Only the original event page received the message. 346 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 347 EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_)); 348 EXPECT_TRUE(listener.was_satisfied()); 349 EXPECT_FALSE(listener_incognito.was_satisfied()); 350 } 351 352 // Trigger a bookmark created event and ensure both pages receive it. 353 { 354 ExtensionTestMessageListener listener("waiting", false); 355 ExtensionTestMessageListener listener_incognito("waiting_incognito", false); 356 357 LazyBackgroundObserver page_complete(browser()->profile()), 358 page2_complete(incognito_browser->profile()); 359 BookmarkModel* bookmark_model = 360 BookmarkModelFactory::GetForProfile(browser()->profile()); 361 ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model); 362 const BookmarkNode* parent = bookmark_model->bookmark_bar_node(); 363 bookmark_model->AddURL( 364 parent, 0, ASCIIToUTF16("Title"), GURL("about:blank")); 365 page_complete.Wait(); 366 page2_complete.Wait(); 367 368 // Both pages received the message. 369 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 370 EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_)); 371 EXPECT_TRUE(listener.was_satisfied()); 372 EXPECT_TRUE(listener_incognito.was_satisfied()); 373 } 374 } 375 376 // Tests that messages from the content script activate the lazy background 377 // page, and keep it alive until all channels are closed. 378 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Messaging) { 379 ASSERT_TRUE(StartEmbeddedTestServer()); 380 ASSERT_TRUE(LoadExtensionAndWait("messaging")); 381 382 // Lazy Background Page doesn't exist yet. 383 ExtensionProcessManager* pm = 384 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 385 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 386 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 387 388 // Navigate to a page that opens a message channel to the background page. 389 ResultCatcher catcher; 390 LazyBackgroundObserver lazybg; 391 ui_test_utils::NavigateToURL( 392 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 393 lazybg.WaitUntilLoaded(); 394 395 // Background page got the content script's message and is still loaded 396 // until we close the channel. 397 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 398 EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 399 400 // Navigate away, closing the message channel and therefore the background 401 // page. 402 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); 403 lazybg.WaitUntilClosed(); 404 405 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 406 } 407 408 // Tests that the lazy background page receives the unload event when we 409 // close it, and that it can execute simple API calls that don't require an 410 // asynchronous response. 411 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, OnUnload) { 412 ASSERT_TRUE(LoadExtensionAndWait("on_unload")); 413 414 // Lazy Background Page has been shut down. 415 ExtensionProcessManager* pm = 416 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 417 EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); 418 419 // The browser action has a new title. 420 BrowserActionTestUtil browser_action(browser()); 421 ASSERT_EQ(1, browser_action.NumberOfBrowserActions()); 422 EXPECT_EQ("Success", browser_action.GetTooltip(0)); 423 } 424 425 // Tests that both a regular page and an event page will receive events when 426 // the event page is not loaded. 427 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, EventDispatchToTab) { 428 ResultCatcher catcher; 429 catcher.RestrictToProfile(browser()->profile()); 430 431 const extensions::Extension* extension = 432 LoadExtensionAndWait("event_dispatch_to_tab"); 433 434 ExtensionTestMessageListener page_ready("ready", true); 435 GURL page_url = extension->GetResourceURL("page.html"); 436 ui_test_utils::NavigateToURL(browser(), page_url); 437 EXPECT_TRUE(page_ready.WaitUntilSatisfied()); 438 439 // After the event is sent below, wait for the event page to have received 440 // the event before proceeding with the test. This allows the regular page 441 // to test that the event page received the event, which makes the pass/fail 442 // logic simpler. 443 ExtensionTestMessageListener event_page_ready("ready", true); 444 445 // Send an event by making a bookmark. 446 BookmarkModel* bookmark_model = 447 BookmarkModelFactory::GetForProfile(browser()->profile()); 448 ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model); 449 bookmark_utils::AddIfNotBookmarked( 450 bookmark_model, 451 GURL("http://www.google.com"), 452 UTF8ToUTF16("Google")); 453 454 EXPECT_TRUE(event_page_ready.WaitUntilSatisfied()); 455 456 page_ready.Reply("go"); 457 458 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 459 } 460 461 // TODO: background page with timer. 462 // TODO: background page that interacts with popup. 463