// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/lazy_background_task_queue.h" #include "base/bind.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_context.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_factory.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system_provider.h" #include "extensions/browser/extensions_test.h" #include "extensions/browser/mock_extension_system.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/test_extensions_browser_client.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "testing/gtest/include/gtest/gtest.h" using content::BrowserContext; namespace extensions { namespace { // A ProcessManager that doesn't create background host pages. class TestProcessManager : public ProcessManager { public: explicit TestProcessManager(BrowserContext* context) : ProcessManager(context, context, ExtensionRegistry::Get(context)), create_count_(0) { // ProcessManager constructor above assumes non-incognito. DCHECK(!context->IsOffTheRecord()); } virtual ~TestProcessManager() {} int create_count() { return create_count_; } // ProcessManager overrides: virtual bool CreateBackgroundHost(const Extension* extension, const GURL& url) OVERRIDE { // Don't actually try to create a web contents. create_count_++; return false; } private: int create_count_; DISALLOW_COPY_AND_ASSIGN(TestProcessManager); }; // A simple ExtensionSystem that returns a TestProcessManager. class MockExtensionSystemWithProcessManager : public MockExtensionSystem { public: explicit MockExtensionSystemWithProcessManager(BrowserContext* context) : MockExtensionSystem(context), test_process_manager_(context) {} virtual ~MockExtensionSystemWithProcessManager() {} virtual ProcessManager* process_manager() OVERRIDE { return &test_process_manager_; } private: TestProcessManager test_process_manager_; }; } // namespace // Derives from ExtensionsTest to provide content module and keyed service // initialization. class LazyBackgroundTaskQueueTest : public ExtensionsTest { public: LazyBackgroundTaskQueueTest() : notification_service_(content::NotificationService::Create()), task_run_count_(0) { extensions_browser_client()->set_extension_system_factory( &extension_system_factory_); } virtual ~LazyBackgroundTaskQueueTest() {} int task_run_count() { return task_run_count_; } // A simple callback for AddPendingTask. void RunPendingTask(ExtensionHost* host) { task_run_count_++; } // Creates and registers an extension without a background page. scoped_refptr CreateSimpleExtension() { scoped_refptr extension = ExtensionBuilder() .SetManifest(DictionaryBuilder() .Set("name", "No background") .Set("version", "1") .Set("manifest_version", 2)) .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") .Build(); ExtensionRegistry::Get(browser_context())->AddEnabled(extension); return extension; } // Creates and registers an extension with a lazy background page. scoped_refptr CreateLazyBackgroundExtension() { scoped_refptr extension = ExtensionBuilder() .SetManifest(DictionaryBuilder() .Set("name", "Lazy background") .Set("version", "1") .Set("manifest_version", 2) .Set("background", DictionaryBuilder() .Set("page", "background.html") .SetBoolean("persistent", false))) .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") .Build(); ExtensionRegistry::Get(browser_context())->AddEnabled(extension); return extension; } private: scoped_ptr notification_service_; MockExtensionSystemFactory extension_system_factory_; // The total number of pending tasks that have been executed. int task_run_count_; DISALLOW_COPY_AND_ASSIGN(LazyBackgroundTaskQueueTest); }; // Tests that only extensions with background pages should have tasks queued. TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) { LazyBackgroundTaskQueue queue(browser_context()); // Build a simple extension with no background page. scoped_refptr no_background = CreateSimpleExtension(); EXPECT_FALSE(queue.ShouldEnqueueTask(browser_context(), no_background.get())); // Build another extension with a background page. scoped_refptr with_background = CreateLazyBackgroundExtension(); EXPECT_TRUE( queue.ShouldEnqueueTask(browser_context(), with_background.get())); } // Tests that adding tasks actually increases the pending task count, and that // multiple extensions can have pending tasks. TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) { // Get our TestProcessManager. MockExtensionSystem* extension_system = static_cast( ExtensionSystem::Get(browser_context())); TestProcessManager* process_manager = static_cast(extension_system->process_manager()); LazyBackgroundTaskQueue queue(browser_context()); // Build a simple extension with no background page. scoped_refptr no_background = CreateSimpleExtension(); // Adding a pending task increases the number of extensions with tasks, but // doesn't run the task. queue.AddPendingTask(browser_context(), no_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); EXPECT_EQ(0, task_run_count()); // Another task on the same extension doesn't increase the number of // extensions that have tasks and doesn't run any tasks. queue.AddPendingTask(browser_context(), no_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); EXPECT_EQ(0, task_run_count()); // Adding a task on an extension with a lazy background page tries to create // a background host, and if that fails, runs the task immediately. scoped_refptr lazy_background = CreateLazyBackgroundExtension(); queue.AddPendingTask(browser_context(), lazy_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); EXPECT_EQ(2u, queue.extensions_with_pending_tasks()); // The process manager tried to create a background host. EXPECT_EQ(1, process_manager->create_count()); // The task ran immediately because the creation failed. EXPECT_EQ(1, task_run_count()); } // Tests that pending tasks are actually run. TEST_F(LazyBackgroundTaskQueueTest, ProcessPendingTasks) { LazyBackgroundTaskQueue queue(browser_context()); // ProcessPendingTasks is a no-op if there are no tasks. scoped_refptr extension = CreateSimpleExtension(); queue.ProcessPendingTasks(NULL, browser_context(), extension.get()); EXPECT_EQ(0, task_run_count()); // Schedule a task to run. queue.AddPendingTask(browser_context(), extension->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); EXPECT_EQ(0, task_run_count()); EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); // Trying to run tasks for an unrelated BrowserContext should do nothing. content::TestBrowserContext unrelated_context; queue.ProcessPendingTasks(NULL, &unrelated_context, extension.get()); EXPECT_EQ(0, task_run_count()); EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); // Processing tasks when there is one pending runs the task and removes the // extension from the list of extensions with pending tasks. queue.ProcessPendingTasks(NULL, browser_context(), extension.get()); EXPECT_EQ(1, task_run_count()); EXPECT_EQ(0u, queue.extensions_with_pending_tasks()); } } // namespace extensions