// 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 "base/command_line.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/process_manager.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions { // A ProcessManager that doesn't create background host pages. class TestProcessManager : public ProcessManager { public: explicit TestProcessManager(Profile* profile) : ProcessManager(profile, profile->GetOriginalProfile()), create_count_(0) {} 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); }; // Derives from ExtensionServiceTestBase because ExtensionService is difficult // to initialize alone. class LazyBackgroundTaskQueueTest : public extensions::ExtensionServiceTestBase { public: LazyBackgroundTaskQueueTest() : task_run_count_(0) {} 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(); service_->AddExtension(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(); service_->AddExtension(extension); return extension; } private: // 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) { InitializeEmptyExtensionService(); InitializeProcessManager(); LazyBackgroundTaskQueue queue(profile_.get()); // Build a simple extension with no background page. scoped_refptr no_background = CreateSimpleExtension(); EXPECT_FALSE(queue.ShouldEnqueueTask(profile_.get(), no_background.get())); // Build another extension with a background page. scoped_refptr with_background = CreateLazyBackgroundExtension(); EXPECT_TRUE(queue.ShouldEnqueueTask(profile_.get(), 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) { InitializeEmptyExtensionService(); // Swap in our stub TestProcessManager. TestExtensionSystem* extension_system = static_cast( ExtensionSystem::Get(profile_.get())); // Owned by |extension_system|. TestProcessManager* process_manager = new TestProcessManager(profile_.get()); extension_system->SetProcessManager(process_manager); LazyBackgroundTaskQueue queue(profile_.get()); // 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(profile_.get(), 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(profile_.get(), 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(profile_.get(), 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) { InitializeEmptyExtensionService(); LazyBackgroundTaskQueue queue(profile_.get()); // ProcessPendingTasks is a no-op if there are no tasks. scoped_refptr extension = CreateSimpleExtension(); queue.ProcessPendingTasks(NULL, profile_.get(), extension); EXPECT_EQ(0, task_run_count()); // Schedule a task to run. queue.AddPendingTask(profile_.get(), 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 profile should do nothing. TestingProfile profile2; queue.ProcessPendingTasks(NULL, &profile2, extension); 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, profile_.get(), extension); EXPECT_EQ(1, task_run_count()); EXPECT_EQ(0u, queue.extensions_with_pending_tasks()); } } // namespace extensions