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
18using content::BrowserContext;
19using content::SiteInstance;
20using content::TestBrowserContext;
21
22namespace extensions {
23
24namespace {
25
26// An incognito version of a TestBrowserContext.
27class 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.
40class 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
62class 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.
101TEST_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.
157TEST_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).
172TEST_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.
185TEST_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.
210TEST_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.
230TEST_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