blob: 7c76036dde738a5020063e36a18900023edde10e [file] [log] [blame]
// 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 <memory>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_prefs/user_prefs.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/extensions_test.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_manager_factory.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());
}
~TestProcessManager() override {}
int create_count() { return create_count_; }
// ProcessManager overrides:
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);
};
std::unique_ptr<KeyedService> CreateTestProcessManager(
BrowserContext* context) {
return std::make_unique<TestProcessManager>(context);
}
} // namespace
// Derives from ExtensionsTest to provide content module and keyed service
// initialization.
class LazyBackgroundTaskQueueTest : public ExtensionsTest {
public:
LazyBackgroundTaskQueueTest() : task_run_count_(0) {}
~LazyBackgroundTaskQueueTest() override {}
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<Extension> CreateSimpleExtension() {
scoped_refptr<Extension> extension =
ExtensionBuilder()
.SetManifest(DictionaryBuilder()
.Set("name", "No background")
.Set("version", "1")
.Set("manifest_version", 2)
.Build())
.SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
.Build();
ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
return extension;
}
// Creates and registers an extension with a lazy background page.
scoped_refptr<Extension> CreateLazyBackgroundExtension() {
scoped_refptr<Extension> 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)
.Build())
.Build())
.SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
.Build();
ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
return extension;
}
protected:
void SetUp() override {
ExtensionsTest::SetUp();
user_prefs::UserPrefs::Set(browser_context(), &testing_pref_service_);
}
private:
sync_preferences::TestingPrefServiceSyncable testing_pref_service_;
// 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<Extension> no_background = CreateSimpleExtension();
EXPECT_FALSE(queue.ShouldEnqueueTask(browser_context(), no_background.get()));
// Build another extension with a background page.
scoped_refptr<Extension> 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.
TestProcessManager* process_manager = static_cast<TestProcessManager*>(
ProcessManagerFactory::GetInstance()->SetTestingFactoryAndUse(
browser_context(), CreateTestProcessManager));
LazyBackgroundTaskQueue queue(browser_context());
// Build a simple extension with no background page.
scoped_refptr<Extension> 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.pending_tasks_.size());
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.pending_tasks_.size());
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<Extension> lazy_background = CreateLazyBackgroundExtension();
queue.AddPendingTask(browser_context(),
lazy_background->id(),
base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
base::Unretained(this)));
EXPECT_EQ(2u, queue.pending_tasks_.size());
// 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> 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.pending_tasks_.size());
// 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.pending_tasks_.size());
// 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.pending_tasks_.size());
}
} // namespace extensions