Home | History | Annotate | Download | only in browser
      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