1 // Copyright 2013 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/lazy_background_task_queue.h" 6 7 #include "base/bind.h" 8 #include "components/keyed_service/content/browser_context_dependency_manager.h" 9 #include "content/public/browser/notification_service.h" 10 #include "content/public/test/test_browser_context.h" 11 #include "extensions/browser/extension_registry.h" 12 #include "extensions/browser/extension_registry_factory.h" 13 #include "extensions/browser/extension_system.h" 14 #include "extensions/browser/extension_system_provider.h" 15 #include "extensions/browser/extensions_test.h" 16 #include "extensions/browser/mock_extension_system.h" 17 #include "extensions/browser/process_manager.h" 18 #include "extensions/browser/test_extensions_browser_client.h" 19 #include "extensions/common/extension.h" 20 #include "extensions/common/extension_builder.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 using content::BrowserContext; 24 25 namespace extensions { 26 namespace { 27 28 // A ProcessManager that doesn't create background host pages. 29 class TestProcessManager : public ProcessManager { 30 public: 31 explicit TestProcessManager(BrowserContext* context) 32 : ProcessManager(context, context, ExtensionRegistry::Get(context)), 33 create_count_(0) { 34 // ProcessManager constructor above assumes non-incognito. 35 DCHECK(!context->IsOffTheRecord()); 36 } 37 virtual ~TestProcessManager() {} 38 39 int create_count() { return create_count_; } 40 41 // ProcessManager overrides: 42 virtual bool CreateBackgroundHost(const Extension* extension, 43 const GURL& url) OVERRIDE { 44 // Don't actually try to create a web contents. 45 create_count_++; 46 return false; 47 } 48 49 private: 50 int create_count_; 51 52 DISALLOW_COPY_AND_ASSIGN(TestProcessManager); 53 }; 54 55 // A simple ExtensionSystem that returns a TestProcessManager. 56 class MockExtensionSystemWithProcessManager : public MockExtensionSystem { 57 public: 58 explicit MockExtensionSystemWithProcessManager(BrowserContext* context) 59 : MockExtensionSystem(context), test_process_manager_(context) {} 60 virtual ~MockExtensionSystemWithProcessManager() {} 61 62 virtual ProcessManager* process_manager() OVERRIDE { 63 return &test_process_manager_; 64 } 65 66 private: 67 TestProcessManager test_process_manager_; 68 }; 69 70 } // namespace 71 72 // Derives from ExtensionsTest to provide content module and keyed service 73 // initialization. 74 class LazyBackgroundTaskQueueTest : public ExtensionsTest { 75 public: 76 LazyBackgroundTaskQueueTest() 77 : notification_service_(content::NotificationService::Create()), 78 task_run_count_(0) { 79 extensions_browser_client()->set_extension_system_factory( 80 &extension_system_factory_); 81 } 82 virtual ~LazyBackgroundTaskQueueTest() {} 83 84 int task_run_count() { return task_run_count_; } 85 86 // A simple callback for AddPendingTask. 87 void RunPendingTask(ExtensionHost* host) { 88 task_run_count_++; 89 } 90 91 // Creates and registers an extension without a background page. 92 scoped_refptr<Extension> CreateSimpleExtension() { 93 scoped_refptr<Extension> extension = ExtensionBuilder() 94 .SetManifest(DictionaryBuilder() 95 .Set("name", "No background") 96 .Set("version", "1") 97 .Set("manifest_version", 2)) 98 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 99 .Build(); 100 ExtensionRegistry::Get(browser_context())->AddEnabled(extension); 101 return extension; 102 } 103 104 // Creates and registers an extension with a lazy background page. 105 scoped_refptr<Extension> CreateLazyBackgroundExtension() { 106 scoped_refptr<Extension> extension = ExtensionBuilder() 107 .SetManifest(DictionaryBuilder() 108 .Set("name", "Lazy background") 109 .Set("version", "1") 110 .Set("manifest_version", 2) 111 .Set("background", 112 DictionaryBuilder() 113 .Set("page", "background.html") 114 .SetBoolean("persistent", false))) 115 .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") 116 .Build(); 117 ExtensionRegistry::Get(browser_context())->AddEnabled(extension); 118 return extension; 119 } 120 121 private: 122 scoped_ptr<content::NotificationService> notification_service_; 123 MockExtensionSystemFactory<MockExtensionSystemWithProcessManager> 124 extension_system_factory_; 125 126 // The total number of pending tasks that have been executed. 127 int task_run_count_; 128 129 DISALLOW_COPY_AND_ASSIGN(LazyBackgroundTaskQueueTest); 130 }; 131 132 // Tests that only extensions with background pages should have tasks queued. 133 TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) { 134 LazyBackgroundTaskQueue queue(browser_context()); 135 136 // Build a simple extension with no background page. 137 scoped_refptr<Extension> no_background = CreateSimpleExtension(); 138 EXPECT_FALSE(queue.ShouldEnqueueTask(browser_context(), no_background.get())); 139 140 // Build another extension with a background page. 141 scoped_refptr<Extension> with_background = CreateLazyBackgroundExtension(); 142 EXPECT_TRUE( 143 queue.ShouldEnqueueTask(browser_context(), with_background.get())); 144 } 145 146 // Tests that adding tasks actually increases the pending task count, and that 147 // multiple extensions can have pending tasks. 148 TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) { 149 // Get our TestProcessManager. 150 MockExtensionSystem* extension_system = static_cast<MockExtensionSystem*>( 151 ExtensionSystem::Get(browser_context())); 152 TestProcessManager* process_manager = 153 static_cast<TestProcessManager*>(extension_system->process_manager()); 154 155 LazyBackgroundTaskQueue queue(browser_context()); 156 157 // Build a simple extension with no background page. 158 scoped_refptr<Extension> no_background = CreateSimpleExtension(); 159 160 // Adding a pending task increases the number of extensions with tasks, but 161 // doesn't run the task. 162 queue.AddPendingTask(browser_context(), 163 no_background->id(), 164 base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, 165 base::Unretained(this))); 166 EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); 167 EXPECT_EQ(0, task_run_count()); 168 169 // Another task on the same extension doesn't increase the number of 170 // extensions that have tasks and doesn't run any tasks. 171 queue.AddPendingTask(browser_context(), 172 no_background->id(), 173 base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, 174 base::Unretained(this))); 175 EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); 176 EXPECT_EQ(0, task_run_count()); 177 178 // Adding a task on an extension with a lazy background page tries to create 179 // a background host, and if that fails, runs the task immediately. 180 scoped_refptr<Extension> lazy_background = CreateLazyBackgroundExtension(); 181 queue.AddPendingTask(browser_context(), 182 lazy_background->id(), 183 base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, 184 base::Unretained(this))); 185 EXPECT_EQ(2u, queue.extensions_with_pending_tasks()); 186 // The process manager tried to create a background host. 187 EXPECT_EQ(1, process_manager->create_count()); 188 // The task ran immediately because the creation failed. 189 EXPECT_EQ(1, task_run_count()); 190 } 191 192 // Tests that pending tasks are actually run. 193 TEST_F(LazyBackgroundTaskQueueTest, ProcessPendingTasks) { 194 LazyBackgroundTaskQueue queue(browser_context()); 195 196 // ProcessPendingTasks is a no-op if there are no tasks. 197 scoped_refptr<Extension> extension = CreateSimpleExtension(); 198 queue.ProcessPendingTasks(NULL, browser_context(), extension.get()); 199 EXPECT_EQ(0, task_run_count()); 200 201 // Schedule a task to run. 202 queue.AddPendingTask(browser_context(), 203 extension->id(), 204 base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, 205 base::Unretained(this))); 206 EXPECT_EQ(0, task_run_count()); 207 EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); 208 209 // Trying to run tasks for an unrelated BrowserContext should do nothing. 210 content::TestBrowserContext unrelated_context; 211 queue.ProcessPendingTasks(NULL, &unrelated_context, extension.get()); 212 EXPECT_EQ(0, task_run_count()); 213 EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); 214 215 // Processing tasks when there is one pending runs the task and removes the 216 // extension from the list of extensions with pending tasks. 217 queue.ProcessPendingTasks(NULL, browser_context(), extension.get()); 218 EXPECT_EQ(1, task_run_count()); 219 EXPECT_EQ(0u, queue.extensions_with_pending_tasks()); 220 } 221 222 } // namespace extensions 223