Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2011 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 // TODO(rickcam): Bug 73183: Add unit tests for image loading
      6 
      7 #include <cstdlib>
      8 #include <set>
      9 
     10 #include "chrome/browser/background_application_list_model.h"
     11 
     12 #include "base/command_line.h"
     13 #include "base/file_path.h"
     14 #include "base/file_util.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/message_loop.h"
     17 #include "base/stl_util-inl.h"
     18 #include "chrome/browser/extensions/extension_service.h"
     19 #include "chrome/common/extensions/extension.h"
     20 #include "chrome/test/testing_profile.h"
     21 #include "content/browser/browser_thread.h"
     22 #include "content/common/notification_registrar.h"
     23 #include "content/common/notification_service.h"
     24 #include "content/common/notification_type.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 // This value is used to seed the PRNG at the beginning of a sequence of
     28 // operations to produce a repeatable sequence.
     29 #define RANDOM_SEED (0x33F7A7A7)
     30 
     31 // For ExtensionService interface when it requires a path that is not used.
     32 FilePath bogus_file_path() {
     33   return FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"));
     34 }
     35 
     36 class BackgroundApplicationListModelTest : public testing::Test {
     37  public:
     38   BackgroundApplicationListModelTest();
     39   ~BackgroundApplicationListModelTest();
     40 
     41   virtual void InitializeEmptyExtensionService();
     42 
     43  protected:
     44   scoped_ptr<Profile> profile_;
     45   scoped_refptr<ExtensionService> service_;
     46   MessageLoop loop_;
     47   BrowserThread ui_thread_;
     48 };
     49 
     50 // The message loop may be used in tests which require it to be an IO loop.
     51 BackgroundApplicationListModelTest::BackgroundApplicationListModelTest()
     52     : loop_(MessageLoop::TYPE_IO),
     53       ui_thread_(BrowserThread::UI, &loop_) {
     54 }
     55 
     56 BackgroundApplicationListModelTest::~BackgroundApplicationListModelTest() {
     57   // Drop reference to ExtensionService and TestingProfile, so that they can be
     58   // destroyed while BrowserThreads and MessageLoop are still around.  They
     59   // are used in the destruction process.
     60   service_ = NULL;
     61   profile_.reset(NULL);
     62   MessageLoop::current()->RunAllPending();
     63 }
     64 
     65 // This is modeled on a similar routine in ExtensionServiceTestBase.
     66 void BackgroundApplicationListModelTest::InitializeEmptyExtensionService() {
     67   TestingProfile* profile = new TestingProfile();
     68   profile_.reset(profile);
     69   service_ = profile->CreateExtensionService(
     70       CommandLine::ForCurrentProcess(),
     71       bogus_file_path(), false);
     72   service_->set_extensions_enabled(true);
     73   service_->set_show_extensions_prompts(false);
     74   service_->OnLoadedInstalledExtensions(); /* Sends EXTENSIONS_READY */
     75 }
     76 
     77 // Returns a barebones test Extension object with the specified |name|.  The
     78 // returned extension will include background permission iff
     79 // |background_permission| is true.
     80 static scoped_refptr<Extension> CreateExtension(const std::string& name,
     81                                                 bool background_permission) {
     82   DictionaryValue manifest;
     83   manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
     84   manifest.SetString(extension_manifest_keys::kName, name);
     85   if (background_permission) {
     86     ListValue* permissions = new ListValue();
     87     manifest.Set(extension_manifest_keys::kPermissions, permissions);
     88     permissions->Append(Value::CreateStringValue("background"));
     89   }
     90   std::string error;
     91   scoped_refptr<Extension> extension = Extension::Create(
     92       bogus_file_path().AppendASCII(name), Extension::INVALID, manifest,
     93       Extension::STRICT_ERROR_CHECKS, &error);
     94   // Cannot ASSERT_* here because that attempts an illegitimate return.
     95   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
     96   EXPECT_TRUE(extension.get() != NULL) << error;
     97   return extension;
     98 }
     99 
    100 // With minimal test logic, verifies behavior over an explicit set of
    101 // extensions, of which some are Background Apps and others are not.
    102 TEST_F(BackgroundApplicationListModelTest, LoadExplicitExtensions) {
    103   InitializeEmptyExtensionService();
    104   ExtensionService* service = profile_->GetExtensionService();
    105   ASSERT_TRUE(service);
    106   ASSERT_TRUE(service->is_ready());
    107   ASSERT_TRUE(service->extensions());
    108   ASSERT_TRUE(service->extensions()->empty());
    109   scoped_ptr<BackgroundApplicationListModel> model(
    110       new BackgroundApplicationListModel(profile_.get()));
    111   ASSERT_EQ(0U, model->size());
    112 
    113   scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
    114   scoped_refptr<Extension> ext2 = CreateExtension("bravo", false);
    115   scoped_refptr<Extension> ext3 = CreateExtension("charlie", false);
    116   scoped_refptr<Extension> bgapp1 = CreateExtension("delta", true);
    117   scoped_refptr<Extension> bgapp2 = CreateExtension("echo", true);
    118   ASSERT_TRUE(service->extensions() != NULL);
    119   ASSERT_EQ(0U, service->extensions()->size());
    120   ASSERT_EQ(0U, model->size());
    121   // Add alternating Extensions and Background Apps
    122   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext1));
    123   service->AddExtension(ext1);
    124   ASSERT_EQ(1U, service->extensions()->size());
    125   ASSERT_EQ(0U, model->size());
    126   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp1));
    127   service->AddExtension(bgapp1);
    128   ASSERT_EQ(2U, service->extensions()->size());
    129   ASSERT_EQ(1U, model->size());
    130   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext2));
    131   service->AddExtension(ext2);
    132   ASSERT_EQ(3U, service->extensions()->size());
    133   ASSERT_EQ(1U, model->size());
    134   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp2));
    135   service->AddExtension(bgapp2);
    136   ASSERT_EQ(4U, service->extensions()->size());
    137   ASSERT_EQ(2U, model->size());
    138   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext3));
    139   service->AddExtension(ext3);
    140   ASSERT_EQ(5U, service->extensions()->size());
    141   ASSERT_EQ(2U, model->size());
    142   // Remove in FIFO order.
    143   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext1));
    144   service->UninstallExtension(ext1->id(), false, NULL);
    145   ASSERT_EQ(4U, service->extensions()->size());
    146   ASSERT_EQ(2U, model->size());
    147   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp1));
    148   service->UninstallExtension(bgapp1->id(), false, NULL);
    149   ASSERT_EQ(3U, service->extensions()->size());
    150   ASSERT_EQ(1U, model->size());
    151   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext2));
    152   service->UninstallExtension(ext2->id(), false, NULL);
    153   ASSERT_EQ(2U, service->extensions()->size());
    154   ASSERT_EQ(1U, model->size());
    155   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp2));
    156   service->UninstallExtension(bgapp2->id(), false, NULL);
    157   ASSERT_EQ(1U, service->extensions()->size());
    158   ASSERT_EQ(0U, model->size());
    159   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext3));
    160   service->UninstallExtension(ext3->id(), false, NULL);
    161   ASSERT_EQ(0U, service->extensions()->size());
    162   ASSERT_EQ(0U, model->size());
    163 }
    164 
    165 typedef std::set<scoped_refptr<Extension> > ExtensionSet;
    166 
    167 namespace {
    168 std::string GenerateUniqueExtensionName() {
    169   static int uniqueness = 0;
    170   std::ostringstream output;
    171   output << "Unique Named Extension " << uniqueness;
    172   ++uniqueness;
    173   return output.str();
    174 }
    175 }
    176 
    177 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
    178 // removing extensions, of which some are Background Apps and others are not.
    179 TEST_F(BackgroundApplicationListModelTest, LoadRandomExtension) {
    180   InitializeEmptyExtensionService();
    181   ExtensionService* service = profile_->GetExtensionService();
    182   ASSERT_TRUE(service);
    183   ASSERT_TRUE(service->is_ready());
    184   ASSERT_TRUE(service->extensions());
    185   ASSERT_TRUE(service->extensions()->empty());
    186   scoped_ptr<BackgroundApplicationListModel> model(
    187       new BackgroundApplicationListModel(profile_.get()));
    188   ASSERT_EQ(0U, model->size());
    189 
    190   static const int kIterations = 500;
    191   ExtensionSet extensions;
    192   size_t count = 0;
    193   size_t expected = 0;
    194   srand(RANDOM_SEED);
    195   for (int index = 0; index < kIterations; ++index) {
    196     if (rand() % 2) {  // Add an extension
    197       std::string name = GenerateUniqueExtensionName();
    198       bool create_background = false;
    199       if (rand() % 2) {
    200         create_background = true;
    201         ++expected;
    202       }
    203       scoped_refptr<Extension> extension =
    204           CreateExtension(name, create_background);
    205       ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension),
    206                 create_background);
    207       extensions.insert(extension);
    208       ++count;
    209       ASSERT_EQ(count, extensions.size());
    210       service->AddExtension(extension);
    211       ASSERT_EQ(count, service->extensions()->size());
    212       ASSERT_EQ(expected, model->size());
    213     } else {  // Maybe remove an extension.
    214       ExtensionSet::iterator cursor = extensions.begin();
    215       if (cursor == extensions.end()) {
    216         // Nothing to remove.  Just verify accounting.
    217         ASSERT_EQ(0U, count);
    218         ASSERT_EQ(0U, expected);
    219         ASSERT_EQ(0U, service->extensions()->size());
    220         ASSERT_EQ(0U, model->size());
    221       } else {
    222         // Randomly select which extension to remove
    223         if (extensions.size() > 1) {
    224           int offset = rand() % (extensions.size() - 1);
    225           for (int index = 0; index < offset; ++index)
    226             ++cursor;
    227         }
    228         scoped_refptr<Extension> extension = cursor->get();
    229         std::string id = extension->id();
    230         if (BackgroundApplicationListModel::IsBackgroundApp(*extension))
    231           --expected;
    232         extensions.erase(cursor);
    233         --count;
    234         ASSERT_EQ(count, extensions.size());
    235         service->UninstallExtension(extension->id(), false, NULL);
    236         ASSERT_EQ(count, service->extensions()->size());
    237         ASSERT_EQ(expected, model->size());
    238       }
    239     }
    240   }
    241 }
    242