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