Home | History | Annotate | Download | only in background
      1 // Copyright (c) 2012 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/background_application_list_model.h"
     11 
     12 #include "base/command_line.h"
     13 #include "base/files/file_path.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/stl_util.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_service_unittest.h"
     19 #include "chrome/browser/extensions/extension_system.h"
     20 #include "chrome/browser/extensions/permissions_updater.h"
     21 #include "chrome/common/extensions/extension.h"
     22 #include "chrome/common/extensions/extension_manifest_constants.h"
     23 #include "chrome/common/extensions/permissions/api_permission.h"
     24 #include "chrome/common/extensions/permissions/permission_set.h"
     25 #include "chrome/test/base/testing_profile.h"
     26 #include "content/public/browser/notification_registrar.h"
     27 #include "content/public/browser/notification_types.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 // This value is used to seed the PRNG at the beginning of a sequence of
     31 // operations to produce a repeatable sequence.
     32 #define RANDOM_SEED (0x33F7A7A7)
     33 
     34 using extensions::APIPermission;
     35 using extensions::Extension;
     36 
     37 // For ExtensionService interface when it requires a path that is not used.
     38 base::FilePath bogus_file_path() {
     39   return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"));
     40 }
     41 
     42 class BackgroundApplicationListModelTest : public ExtensionServiceTestBase {
     43  public:
     44   BackgroundApplicationListModelTest() {}
     45   virtual ~BackgroundApplicationListModelTest() {}
     46 
     47  protected:
     48   void InitializeAndLoadEmptyExtensionService() {
     49     InitializeEmptyExtensionService();
     50     service_->Init(); /* Sends EXTENSIONS_READY */
     51   }
     52 
     53   bool IsBackgroundApp(const Extension& app) {
     54     return BackgroundApplicationListModel::IsBackgroundApp(app,
     55                                                            profile_.get());
     56   }
     57 };
     58 
     59 // Returns a barebones test Extension object with the specified |name|.  The
     60 // returned extension will include background permission iff
     61 // |background_permission| is true.
     62 static scoped_refptr<Extension> CreateExtension(const std::string& name,
     63                                                 bool background_permission) {
     64   DictionaryValue manifest;
     65   manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
     66   manifest.SetString(extension_manifest_keys::kName, name);
     67   if (background_permission) {
     68     ListValue* permissions = new ListValue();
     69     manifest.Set(extension_manifest_keys::kPermissions, permissions);
     70     permissions->Append(Value::CreateStringValue("background"));
     71   }
     72   std::string error;
     73   scoped_refptr<Extension> extension = Extension::Create(
     74       bogus_file_path().AppendASCII(name),
     75       extensions::Manifest::INVALID_LOCATION,
     76       manifest,
     77       Extension::NO_FLAGS,
     78       &error);
     79   // Cannot ASSERT_* here because that attempts an illegitimate return.
     80   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
     81   EXPECT_TRUE(extension.get() != NULL) << error;
     82   return extension;
     83 }
     84 
     85 namespace {
     86 std::string GenerateUniqueExtensionName() {
     87   static int uniqueness = 0;
     88   std::ostringstream output;
     89   output << "Unique Named Extension " << uniqueness;
     90   ++uniqueness;
     91   return output.str();
     92 }
     93 
     94 void AddBackgroundPermission(ExtensionService* service,
     95                              Extension* extension) {
     96   if (BackgroundApplicationListModel::IsBackgroundApp(*extension,
     97                                                       service->profile())) {
     98     return;
     99   }
    100 
    101   scoped_refptr<Extension> temporary =
    102       CreateExtension(GenerateUniqueExtensionName(), true);
    103   scoped_refptr<const extensions::PermissionSet> permissions =
    104       temporary->GetActivePermissions();
    105   extensions::PermissionsUpdater(service->profile()).AddPermissions(
    106       extension, permissions.get());
    107 }
    108 
    109 void RemoveBackgroundPermission(ExtensionService* service,
    110                                 Extension* extension) {
    111   if (!BackgroundApplicationListModel::IsBackgroundApp(*extension,
    112                                                        service->profile())) {
    113     return;
    114   }
    115   extensions::PermissionsUpdater(service->profile())
    116       .RemovePermissions(extension, extension->GetActivePermissions().get());
    117 }
    118 }  // namespace
    119 
    120 // Crashes on Mac tryslaves.
    121 // http://crbug.com/165458
    122 #if defined(OS_MACOSX) || defined(OS_LINUX)
    123 #define MAYBE_ExplicitTest DISABLED_ExplicitTest
    124 #else
    125 #define MAYBE_ExplicitTest ExplicitTest
    126 #endif
    127 // With minimal test logic, verifies behavior over an explicit set of
    128 // extensions, of which some are Background Apps and others are not.
    129 TEST_F(BackgroundApplicationListModelTest, MAYBE_ExplicitTest) {
    130   InitializeAndLoadEmptyExtensionService();
    131   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    132       extension_service();
    133   ASSERT_TRUE(service);
    134   ASSERT_TRUE(service->is_ready());
    135   ASSERT_TRUE(service->extensions());
    136   ASSERT_TRUE(service->extensions()->is_empty());
    137   scoped_ptr<BackgroundApplicationListModel> model(
    138       new BackgroundApplicationListModel(profile_.get()));
    139   ASSERT_EQ(0U, model->size());
    140 
    141   scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
    142   scoped_refptr<Extension> ext2 = CreateExtension("bravo", false);
    143   scoped_refptr<Extension> ext3 = CreateExtension("charlie", false);
    144   scoped_refptr<Extension> bgapp1 = CreateExtension("delta", true);
    145   scoped_refptr<Extension> bgapp2 = CreateExtension("echo", true);
    146   ASSERT_TRUE(service->extensions() != NULL);
    147   ASSERT_EQ(0U, service->extensions()->size());
    148   ASSERT_EQ(0U, model->size());
    149 
    150   // Add alternating Extensions and Background Apps
    151   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    152   service->AddExtension(ext1.get());
    153   ASSERT_EQ(1U, service->extensions()->size());
    154   ASSERT_EQ(0U, model->size());
    155   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    156   service->AddExtension(bgapp1.get());
    157   ASSERT_EQ(2U, service->extensions()->size());
    158   ASSERT_EQ(1U, model->size());
    159   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    160   service->AddExtension(ext2.get());
    161   ASSERT_EQ(3U, service->extensions()->size());
    162   ASSERT_EQ(1U, model->size());
    163   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    164   service->AddExtension(bgapp2.get());
    165   ASSERT_EQ(4U, service->extensions()->size());
    166   ASSERT_EQ(2U, model->size());
    167   ASSERT_FALSE(IsBackgroundApp(*ext3.get()));
    168   service->AddExtension(ext3.get());
    169   ASSERT_EQ(5U, service->extensions()->size());
    170   ASSERT_EQ(2U, model->size());
    171 
    172   // Remove in FIFO order.
    173   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    174   service->UninstallExtension(ext1->id(), false, NULL);
    175   ASSERT_EQ(4U, service->extensions()->size());
    176   ASSERT_EQ(2U, model->size());
    177   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    178   service->UninstallExtension(bgapp1->id(), false, NULL);
    179   ASSERT_EQ(3U, service->extensions()->size());
    180   ASSERT_EQ(1U, model->size());
    181   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    182   service->UninstallExtension(ext2->id(), false, NULL);
    183   ASSERT_EQ(2U, service->extensions()->size());
    184   ASSERT_EQ(1U, model->size());
    185   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    186   service->UninstallExtension(bgapp2->id(), false, NULL);
    187   ASSERT_EQ(1U, service->extensions()->size());
    188   ASSERT_EQ(0U, model->size());
    189   ASSERT_FALSE(IsBackgroundApp(*ext3.get()));
    190   service->UninstallExtension(ext3->id(), false, NULL);
    191   ASSERT_EQ(0U, service->extensions()->size());
    192   ASSERT_EQ(0U, model->size());
    193 }
    194 
    195 // With minimal test logic, verifies behavior with dynamic permissions.
    196 TEST_F(BackgroundApplicationListModelTest, AddRemovePermissionsTest) {
    197   InitializeAndLoadEmptyExtensionService();
    198   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    199       extension_service();
    200   ASSERT_TRUE(service);
    201   ASSERT_TRUE(service->is_ready());
    202   ASSERT_TRUE(service->extensions());
    203   ASSERT_TRUE(service->extensions()->is_empty());
    204   scoped_ptr<BackgroundApplicationListModel> model(
    205       new BackgroundApplicationListModel(profile_.get()));
    206   ASSERT_EQ(0U, model->size());
    207 
    208   scoped_refptr<Extension> ext = CreateExtension("extension", false);
    209   ASSERT_FALSE(ext->HasAPIPermission(APIPermission::kBackground));
    210   scoped_refptr<Extension> bgapp = CreateExtension("application", true);
    211   ASSERT_TRUE(bgapp->HasAPIPermission(APIPermission::kBackground));
    212   ASSERT_TRUE(service->extensions() != NULL);
    213   ASSERT_EQ(0U, service->extensions()->size());
    214   ASSERT_EQ(0U, model->size());
    215 
    216   // Add one (non-background) extension and one background application
    217   ASSERT_FALSE(IsBackgroundApp(*ext.get()));
    218   service->AddExtension(ext.get());
    219   ASSERT_EQ(1U, service->extensions()->size());
    220   ASSERT_EQ(0U, model->size());
    221   ASSERT_TRUE(IsBackgroundApp(*bgapp.get()));
    222   service->AddExtension(bgapp.get());
    223   ASSERT_EQ(2U, service->extensions()->size());
    224   ASSERT_EQ(1U, model->size());
    225 
    226   // Change permissions back and forth
    227   AddBackgroundPermission(service, ext.get());
    228   ASSERT_TRUE(ext->HasAPIPermission(APIPermission::kBackground));
    229   ASSERT_EQ(2U, service->extensions()->size());
    230   ASSERT_EQ(2U, model->size());
    231   RemoveBackgroundPermission(service, bgapp.get());
    232   ASSERT_FALSE(bgapp->HasAPIPermission(APIPermission::kBackground));
    233   ASSERT_EQ(2U, service->extensions()->size());
    234   ASSERT_EQ(1U, model->size());
    235   RemoveBackgroundPermission(service, ext.get());
    236   ASSERT_FALSE(ext->HasAPIPermission(APIPermission::kBackground));
    237   ASSERT_EQ(2U, service->extensions()->size());
    238   ASSERT_EQ(0U, model->size());
    239   AddBackgroundPermission(service, bgapp.get());
    240   ASSERT_TRUE(bgapp->HasAPIPermission(APIPermission::kBackground));
    241   ASSERT_EQ(2U, service->extensions()->size());
    242   ASSERT_EQ(1U, model->size());
    243 }
    244 
    245 typedef std::set<scoped_refptr<Extension> > ExtensionCollection;
    246 
    247 namespace {
    248 void AddExtension(ExtensionService* service,
    249                   ExtensionCollection* extensions,
    250                   BackgroundApplicationListModel* model,
    251                   size_t* expected,
    252                   size_t* count) {
    253   bool create_background = false;
    254   if (rand() % 2) {
    255     create_background = true;
    256     ++*expected;
    257   }
    258   scoped_refptr<Extension> extension =
    259       CreateExtension(GenerateUniqueExtensionName(), create_background);
    260   ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    261                                                             service->profile()),
    262             create_background);
    263   extensions->insert(extension);
    264   ++*count;
    265   ASSERT_EQ(*count, extensions->size());
    266   service->AddExtension(extension.get());
    267   ASSERT_EQ(*count, service->extensions()->size());
    268   ASSERT_EQ(*expected, model->size());
    269 }
    270 
    271 void RemoveExtension(ExtensionService* service,
    272                      ExtensionCollection* extensions,
    273                      BackgroundApplicationListModel* model,
    274                      size_t* expected,
    275                      size_t* count) {  // Maybe remove an extension.
    276   ExtensionCollection::iterator cursor = extensions->begin();
    277   if (cursor == extensions->end()) {
    278     // Nothing to remove.  Just verify accounting.
    279     ASSERT_EQ(0U, *count);
    280     ASSERT_EQ(0U, *expected);
    281     ASSERT_EQ(0U, service->extensions()->size());
    282     ASSERT_EQ(0U, model->size());
    283   } else {
    284     // Randomly select which extension to remove
    285     if (extensions->size() > 1) {
    286       int offset = rand() % (extensions->size() - 1);
    287       for (int index = 0; index < offset; ++index)
    288         ++cursor;
    289     }
    290     scoped_refptr<Extension> extension = cursor->get();
    291     std::string id = extension->id();
    292     if (BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    293                                                         service->profile())) {
    294       --*expected;
    295     }
    296     extensions->erase(cursor);
    297     --*count;
    298     ASSERT_EQ(*count, extensions->size());
    299     service->UninstallExtension(extension->id(), false, NULL);
    300     ASSERT_EQ(*count, service->extensions()->size());
    301     ASSERT_EQ(*expected, model->size());
    302   }
    303 }
    304 
    305 void TogglePermission(ExtensionService* service,
    306                       ExtensionCollection* extensions,
    307                       BackgroundApplicationListModel* model,
    308                       size_t* expected,
    309                       size_t* count) {
    310   ExtensionCollection::iterator cursor = extensions->begin();
    311   if (cursor == extensions->end()) {
    312     // Nothing to toggle.  Just verify accounting.
    313     ASSERT_EQ(0U, *count);
    314     ASSERT_EQ(0U, *expected);
    315     ASSERT_EQ(0U, service->extensions()->size());
    316     ASSERT_EQ(0U, model->size());
    317   } else {
    318     // Randomly select which extension to toggle.
    319     if (extensions->size() > 1) {
    320       int offset = rand() % (extensions->size() - 1);
    321       for (int index = 0; index < offset; ++index)
    322         ++cursor;
    323     }
    324     scoped_refptr<Extension> extension = cursor->get();
    325     std::string id = extension->id();
    326     if (BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    327                                                         service->profile())) {
    328       --*expected;
    329       ASSERT_EQ(*count, extensions->size());
    330       RemoveBackgroundPermission(service, extension.get());
    331       ASSERT_EQ(*count, service->extensions()->size());
    332       ASSERT_EQ(*expected, model->size());
    333     } else {
    334       ++*expected;
    335       ASSERT_EQ(*count, extensions->size());
    336       AddBackgroundPermission(service, extension.get());
    337       ASSERT_EQ(*count, service->extensions()->size());
    338       ASSERT_EQ(*expected, model->size());
    339     }
    340   }
    341 }
    342 }  // namespace
    343 
    344 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
    345 // removing extensions, of which some are Background Apps and others are not.
    346 TEST_F(BackgroundApplicationListModelTest, RandomTest) {
    347   InitializeAndLoadEmptyExtensionService();
    348   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    349       extension_service();
    350   ASSERT_TRUE(service);
    351   ASSERT_TRUE(service->is_ready());
    352   ASSERT_TRUE(service->extensions());
    353   ASSERT_TRUE(service->extensions()->is_empty());
    354   scoped_ptr<BackgroundApplicationListModel> model(
    355       new BackgroundApplicationListModel(profile_.get()));
    356   ASSERT_EQ(0U, model->size());
    357 
    358   static const int kIterations = 20;
    359   ExtensionCollection extensions;
    360   size_t count = 0;
    361   size_t expected = 0;
    362   srand(RANDOM_SEED);
    363   for (int index = 0; index < kIterations; ++index) {
    364     switch (rand() % 3) {
    365       case 0:
    366         AddExtension(service, &extensions, model.get(), &expected, &count);
    367         break;
    368       case 1:
    369         RemoveExtension(service, &extensions, model.get(), &expected, &count);
    370         break;
    371       case 2:
    372         TogglePermission(service, &extensions, model.get(), &expected, &count);
    373         break;
    374       default:
    375         NOTREACHED();
    376         break;
    377     }
    378   }
    379 }
    380