Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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 "extensions/browser/process_manager.h"
      6 
      7 #include "content/public/browser/content_browser_client.h"
      8 #include "content/public/browser/notification_service.h"
      9 #include "content/public/browser/site_instance.h"
     10 #include "content/public/common/content_client.h"
     11 #include "content/public/test/test_browser_context.h"
     12 #include "extensions/browser/extension_registry.h"
     13 #include "extensions/browser/extensions_test.h"
     14 #include "extensions/browser/notification_types.h"
     15 #include "extensions/browser/process_manager_delegate.h"
     16 #include "extensions/browser/test_extensions_browser_client.h"
     17 
     18 using content::BrowserContext;
     19 using content::SiteInstance;
     20 using content::TestBrowserContext;
     21 
     22 namespace extensions {
     23 
     24 namespace {
     25 
     26 // An incognito version of a TestBrowserContext.
     27 class TestBrowserContextIncognito : public TestBrowserContext {
     28  public:
     29   TestBrowserContextIncognito() {}
     30   virtual ~TestBrowserContextIncognito() {}
     31 
     32   // TestBrowserContext implementation.
     33   virtual bool IsOffTheRecord() const OVERRIDE { return true; }
     34 
     35  private:
     36   DISALLOW_COPY_AND_ASSIGN(TestBrowserContextIncognito);
     37 };
     38 
     39 // A trivial ProcessManagerDelegate.
     40 class TestProcessManagerDelegate : public ProcessManagerDelegate {
     41  public:
     42   TestProcessManagerDelegate()
     43       : is_background_page_allowed_(true),
     44         defer_creating_startup_background_hosts_(false) {}
     45   virtual ~TestProcessManagerDelegate() {}
     46 
     47   // ProcessManagerDelegate implementation.
     48   virtual bool IsBackgroundPageAllowed(BrowserContext* context) const OVERRIDE {
     49     return is_background_page_allowed_;
     50   }
     51   virtual bool DeferCreatingStartupBackgroundHosts(
     52       BrowserContext* context) const OVERRIDE {
     53     return defer_creating_startup_background_hosts_;
     54   }
     55 
     56   bool is_background_page_allowed_;
     57   bool defer_creating_startup_background_hosts_;
     58 };
     59 
     60 }  // namespace
     61 
     62 class ProcessManagerTest : public ExtensionsTest {
     63  public:
     64   ProcessManagerTest()
     65       : notification_service_(content::NotificationService::Create()),
     66         extension_registry_(browser_context()) {
     67     extensions_browser_client()->SetIncognitoContext(&incognito_context_);
     68     extensions_browser_client()->set_process_manager_delegate(
     69         &process_manager_delegate_);
     70   }
     71 
     72   virtual ~ProcessManagerTest() {}
     73 
     74   // Use original_context() to make it clear it is a non-incognito context.
     75   BrowserContext* original_context() { return browser_context(); }
     76   BrowserContext* incognito_context() { return &incognito_context_; }
     77   ExtensionRegistry* extension_registry() { return &extension_registry_; }
     78   TestProcessManagerDelegate* process_manager_delegate() {
     79     return &process_manager_delegate_;
     80   }
     81 
     82   // Returns true if the notification |type| is registered for |manager| with
     83   // source |context|. Pass NULL for |context| for all sources.
     84   static bool IsRegistered(ProcessManager* manager,
     85                            int type,
     86                            BrowserContext* context) {
     87     return manager->registrar_.IsRegistered(
     88         manager, type, content::Source<BrowserContext>(context));
     89   }
     90 
     91  private:
     92   scoped_ptr<content::NotificationService> notification_service_;
     93   TestBrowserContextIncognito incognito_context_;
     94   ExtensionRegistry extension_registry_;  // Shared between BrowserContexts.
     95   TestProcessManagerDelegate process_manager_delegate_;
     96 
     97   DISALLOW_COPY_AND_ASSIGN(ProcessManagerTest);
     98 };
     99 
    100 // Test that notification registration works properly.
    101 TEST_F(ProcessManagerTest, ExtensionNotificationRegistration) {
    102   // Test for a normal context ProcessManager.
    103   scoped_ptr<ProcessManager> manager1(ProcessManager::CreateForTesting(
    104       original_context(), extension_registry()));
    105 
    106   EXPECT_EQ(original_context(), manager1->GetBrowserContext());
    107   EXPECT_EQ(0u, manager1->background_hosts().size());
    108 
    109   // It observes other notifications from this context.
    110   EXPECT_TRUE(IsRegistered(manager1.get(),
    111                            extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
    112                            original_context()));
    113   EXPECT_TRUE(IsRegistered(manager1.get(),
    114                            extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    115                            original_context()));
    116   EXPECT_TRUE(
    117       IsRegistered(manager1.get(),
    118                    extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
    119                    original_context()));
    120   EXPECT_TRUE(IsRegistered(manager1.get(),
    121                            extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    122                            original_context()));
    123 
    124   // Test for an incognito context ProcessManager.
    125   scoped_ptr<ProcessManager> manager2(
    126       ProcessManager::CreateIncognitoForTesting(incognito_context(),
    127                                                 original_context(),
    128                                                 manager1.get(),
    129                                                 extension_registry()));
    130 
    131   EXPECT_EQ(incognito_context(), manager2->GetBrowserContext());
    132   EXPECT_EQ(0u, manager2->background_hosts().size());
    133 
    134   // Some notifications are observed for the original context.
    135   EXPECT_TRUE(IsRegistered(manager2.get(),
    136                            extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    137                            original_context()));
    138 
    139   // Some notifications are observed for the incognito context.
    140   EXPECT_TRUE(IsRegistered(manager2.get(),
    141                            extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    142                            incognito_context()));
    143 
    144   // Some are not observed at all.
    145   EXPECT_FALSE(
    146       IsRegistered(manager2.get(),
    147                    extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
    148                    original_context()));
    149 }
    150 
    151 // Test that startup background hosts are created when the extension system
    152 // becomes ready.
    153 //
    154 // NOTE: This test and those that follow do not try to create ExtensionsHosts
    155 // because ExtensionHost is tightly coupled to WebContents and can't be
    156 // constructed in unit tests.
    157 TEST_F(ProcessManagerTest, CreateBackgroundHostsOnExtensionsReady) {
    158   scoped_ptr<ProcessManager> manager(ProcessManager::CreateForTesting(
    159       original_context(), extension_registry()));
    160   ASSERT_FALSE(manager->startup_background_hosts_created_for_test());
    161 
    162   // Simulate the extension system becoming ready.
    163   content::NotificationService::current()->Notify(
    164       extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
    165       content::Source<BrowserContext>(original_context()),
    166       content::NotificationService::NoDetails());
    167   EXPECT_TRUE(manager->startup_background_hosts_created_for_test());
    168 }
    169 
    170 // Test that startup background hosts can be created explicitly before the
    171 // extension system is ready (this is the normal pattern in Chrome).
    172 TEST_F(ProcessManagerTest, CreateBackgroundHostsExplicitly) {
    173   scoped_ptr<ProcessManager> manager(ProcessManager::CreateForTesting(
    174       original_context(), extension_registry()));
    175   ASSERT_FALSE(manager->startup_background_hosts_created_for_test());
    176 
    177   // Embedder explicitly asks for hosts to be created. Chrome does this on
    178   // normal startup.
    179   manager->MaybeCreateStartupBackgroundHosts();
    180   EXPECT_TRUE(manager->startup_background_hosts_created_for_test());
    181 }
    182 
    183 // Test that the embedder can defer background host creation. Chrome does this
    184 // when the profile is created asynchronously, which may take a while.
    185 TEST_F(ProcessManagerTest, CreateBackgroundHostsDeferred) {
    186   scoped_ptr<ProcessManager> manager(ProcessManager::CreateForTesting(
    187       original_context(), extension_registry()));
    188   ASSERT_FALSE(manager->startup_background_hosts_created_for_test());
    189 
    190   // Don't create background hosts if the delegate says to defer them.
    191   process_manager_delegate()->defer_creating_startup_background_hosts_ = true;
    192   manager->MaybeCreateStartupBackgroundHosts();
    193   EXPECT_FALSE(manager->startup_background_hosts_created_for_test());
    194 
    195   // The extension system becoming ready still doesn't create the hosts.
    196   content::NotificationService::current()->Notify(
    197       extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
    198       content::Source<BrowserContext>(original_context()),
    199       content::NotificationService::NoDetails());
    200   EXPECT_FALSE(manager->startup_background_hosts_created_for_test());
    201 
    202   // Once the embedder is ready the background hosts can be created.
    203   process_manager_delegate()->defer_creating_startup_background_hosts_ = false;
    204   manager->MaybeCreateStartupBackgroundHosts();
    205   EXPECT_TRUE(manager->startup_background_hosts_created_for_test());
    206 }
    207 
    208 // Test that the embedder can disallow background host creation.
    209 // Chrome OS does this in guest mode.
    210 TEST_F(ProcessManagerTest, IsBackgroundHostAllowed) {
    211   scoped_ptr<ProcessManager> manager(ProcessManager::CreateForTesting(
    212       original_context(), extension_registry()));
    213   ASSERT_FALSE(manager->startup_background_hosts_created_for_test());
    214 
    215   // Don't create background hosts if the delegate disallows them.
    216   process_manager_delegate()->is_background_page_allowed_ = false;
    217   manager->MaybeCreateStartupBackgroundHosts();
    218   EXPECT_FALSE(manager->startup_background_hosts_created_for_test());
    219 
    220   // The extension system becoming ready still doesn't create the hosts.
    221   content::NotificationService::current()->Notify(
    222       extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
    223       content::Source<BrowserContext>(original_context()),
    224       content::NotificationService::NoDetails());
    225   EXPECT_FALSE(manager->startup_background_hosts_created_for_test());
    226 }
    227 
    228 // Test that extensions get grouped in the right SiteInstance (and therefore
    229 // process) based on their URLs.
    230 TEST_F(ProcessManagerTest, ProcessGrouping) {
    231   // Extensions in different browser contexts should always be different
    232   // SiteInstances.
    233   scoped_ptr<ProcessManager> manager1(ProcessManager::CreateForTesting(
    234       original_context(), extension_registry()));
    235   // NOTE: This context is not associated with the TestExtensionsBrowserClient.
    236   // That's OK because we're not testing regular vs. incognito behavior.
    237   TestBrowserContext another_context;
    238   ExtensionRegistry another_registry(&another_context);
    239   scoped_ptr<ProcessManager> manager2(
    240       ProcessManager::CreateForTesting(&another_context, &another_registry));
    241 
    242   // Extensions with common origins ("scheme://id/") should be grouped in the
    243   // same SiteInstance.
    244   GURL ext1_url1("chrome-extension://ext1_id/index.html");
    245   GURL ext1_url2("chrome-extension://ext1_id/monkey/monkey.html");
    246   GURL ext2_url1("chrome-extension://ext2_id/index.html");
    247 
    248   scoped_refptr<SiteInstance> site11 =
    249       manager1->GetSiteInstanceForURL(ext1_url1);
    250   scoped_refptr<SiteInstance> site12 =
    251       manager1->GetSiteInstanceForURL(ext1_url2);
    252   EXPECT_EQ(site11, site12);
    253 
    254   scoped_refptr<SiteInstance> site21 =
    255       manager1->GetSiteInstanceForURL(ext2_url1);
    256   EXPECT_NE(site11, site21);
    257 
    258   scoped_refptr<SiteInstance> other_profile_site =
    259       manager2->GetSiteInstanceForURL(ext1_url1);
    260   EXPECT_NE(site11, other_profile_site);
    261 }
    262 
    263 }  // namespace extensions
    264