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_test_base.h"
     19 #include "chrome/browser/extensions/permissions_updater.h"
     20 #include "chrome/test/base/testing_profile.h"
     21 #include "content/public/browser/notification_registrar.h"
     22 #include "content/public/browser/notification_types.h"
     23 #include "extensions/browser/extension_prefs.h"
     24 #include "extensions/browser/extension_system.h"
     25 #include "extensions/browser/uninstall_reason.h"
     26 #include "extensions/common/extension.h"
     27 #include "extensions/common/manifest_constants.h"
     28 #include "extensions/common/permissions/api_permission.h"
     29 #include "extensions/common/permissions/permission_set.h"
     30 #include "extensions/common/permissions/permissions_data.h"
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 
     33 // This value is used to seed the PRNG at the beginning of a sequence of
     34 // operations to produce a repeatable sequence.
     35 #define RANDOM_SEED (0x33F7A7A7)
     36 
     37 using extensions::APIPermission;
     38 using extensions::Extension;
     39 
     40 // For ExtensionService interface when it requires a path that is not used.
     41 base::FilePath bogus_file_pathname(const std::string& name) {
     42   return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"))
     43       .AppendASCII(name);
     44 }
     45 
     46 class BackgroundApplicationListModelTest
     47     : public extensions::ExtensionServiceTestBase {
     48  public:
     49   BackgroundApplicationListModelTest() {}
     50   virtual ~BackgroundApplicationListModelTest() {}
     51 
     52  protected:
     53   void InitializeAndLoadEmptyExtensionService() {
     54     InitializeEmptyExtensionService();
     55     service_->Init(); /* Sends EXTENSIONS_READY */
     56   }
     57 
     58   bool IsBackgroundApp(const Extension& app) {
     59     return BackgroundApplicationListModel::IsBackgroundApp(app,
     60                                                            profile_.get());
     61   }
     62 };
     63 
     64 enum PushMessagingOption {
     65   NO_PUSH_MESSAGING,
     66   PUSH_MESSAGING_PERMISSION,
     67   PUSH_MESSAGING_BUT_NOT_BACKGROUND
     68 };
     69 
     70 // Returns a barebones test Extension object with the specified |name|.  The
     71 // returned extension will include background permission iff
     72 // |background_permission| is true and pushMessaging permission if requested
     73 // by |push_messaging| value. Also the extension may have a specific id set
     74 // to test the case when it has a pushMessaging permission but is not
     75 // considered a background app based on a whitelist.
     76 static scoped_refptr<Extension> CreateExtensionBase(
     77     const std::string& name,
     78     bool background_permission,
     79     PushMessagingOption push_messaging) {
     80   base::DictionaryValue manifest;
     81   manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
     82   manifest.SetString(extensions::manifest_keys::kName, name);
     83   base::ListValue* permissions = new base::ListValue();
     84   manifest.Set(extensions::manifest_keys::kPermissions, permissions);
     85   if (background_permission) {
     86     permissions->Append(new base::StringValue("background"));
     87   }
     88   if (push_messaging == PUSH_MESSAGING_PERMISSION ||
     89       push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) {
     90     permissions->Append(new base::StringValue("pushMessaging"));
     91   }
     92 
     93   std::string error;
     94   scoped_refptr<Extension> extension;
     95 
     96   // There is a whitelist for extensions that have pushMessaging permission but
     97   // are not considered a background app. Create a test extension with a known
     98   // test id if needed.
     99   if (push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) {
    100     extension = Extension::Create(
    101         bogus_file_pathname(name),
    102         extensions::Manifest::INVALID_LOCATION,
    103         manifest,
    104         Extension::NO_FLAGS,
    105         "aaaabbbbccccddddeeeeffffgggghhhh",
    106         &error);
    107   } else {
    108     extension = Extension::Create(
    109         bogus_file_pathname(name),
    110         extensions::Manifest::INVALID_LOCATION,
    111         manifest,
    112         Extension::NO_FLAGS,
    113         &error);
    114   }
    115 
    116   // Cannot ASSERT_* here because that attempts an illegitimate return.
    117   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
    118   EXPECT_TRUE(extension.get() != NULL) << error;
    119   return extension;
    120 }
    121 
    122 static scoped_refptr<Extension> CreateExtension(const std::string& name,
    123                                                 bool background_permission) {
    124   return CreateExtensionBase(name, background_permission, NO_PUSH_MESSAGING);
    125 }
    126 
    127 namespace {
    128 std::string GenerateUniqueExtensionName() {
    129   static int uniqueness = 0;
    130   std::ostringstream output;
    131   output << "Unique Named Extension " << uniqueness;
    132   ++uniqueness;
    133   return output.str();
    134 }
    135 
    136 void AddBackgroundPermission(ExtensionService* service,
    137                              Extension* extension) {
    138   if (BackgroundApplicationListModel::IsBackgroundApp(*extension,
    139                                                       service->profile())) {
    140     return;
    141   }
    142 
    143   scoped_refptr<Extension> temporary =
    144       CreateExtension(GenerateUniqueExtensionName(), true);
    145   scoped_refptr<const extensions::PermissionSet> permissions =
    146       temporary->permissions_data()->active_permissions();
    147   extensions::PermissionsUpdater(service->profile()).AddPermissions(
    148       extension, permissions.get());
    149 }
    150 
    151 void RemoveBackgroundPermission(ExtensionService* service,
    152                                 Extension* extension) {
    153   if (!BackgroundApplicationListModel::IsBackgroundApp(*extension,
    154                                                        service->profile())) {
    155     return;
    156   }
    157   extensions::PermissionsUpdater(service->profile()).RemovePermissions(
    158       extension, extension->permissions_data()->active_permissions().get());
    159 }
    160 
    161 void AddEphemeralApp(const Extension* extension, ExtensionService* service) {
    162   extensions::ExtensionPrefs* prefs =
    163       extensions::ExtensionPrefs::Get(service->profile());
    164   ASSERT_TRUE(prefs);
    165   prefs->OnExtensionInstalled(extension,
    166                               extensions::Extension::ENABLED,
    167                               syncer::StringOrdinal(),
    168                               extensions::kInstallFlagIsEphemeral,
    169                               std::string());
    170 
    171   service->AddExtension(extension);
    172 }
    173 
    174 }  // namespace
    175 
    176 // Crashes on Mac tryslaves.
    177 // http://crbug.com/165458
    178 #if defined(OS_MACOSX) || defined(OS_LINUX)
    179 #define MAYBE_ExplicitTest DISABLED_ExplicitTest
    180 #else
    181 #define MAYBE_ExplicitTest ExplicitTest
    182 #endif
    183 // With minimal test logic, verifies behavior over an explicit set of
    184 // extensions, of which some are Background Apps and others are not.
    185 TEST_F(BackgroundApplicationListModelTest, MAYBE_ExplicitTest) {
    186   InitializeAndLoadEmptyExtensionService();
    187   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    188       extension_service();
    189   ASSERT_TRUE(service);
    190   ASSERT_TRUE(service->is_ready());
    191   ASSERT_TRUE(service->extensions());
    192   ASSERT_TRUE(service->extensions()->is_empty());
    193   scoped_ptr<BackgroundApplicationListModel> model(
    194       new BackgroundApplicationListModel(profile_.get()));
    195   ASSERT_EQ(0U, model->size());
    196 
    197   scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
    198   scoped_refptr<Extension> ext2 = CreateExtension("bravo", false);
    199   scoped_refptr<Extension> ext3 = CreateExtension("charlie", false);
    200   scoped_refptr<Extension> bgapp1 = CreateExtension("delta", true);
    201   scoped_refptr<Extension> bgapp2 = CreateExtension("echo", true);
    202   ASSERT_TRUE(service->extensions() != NULL);
    203   ASSERT_EQ(0U, service->extensions()->size());
    204   ASSERT_EQ(0U, model->size());
    205 
    206   // Add alternating Extensions and Background Apps
    207   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    208   service->AddExtension(ext1.get());
    209   ASSERT_EQ(1U, service->extensions()->size());
    210   ASSERT_EQ(0U, model->size());
    211   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    212   service->AddExtension(bgapp1.get());
    213   ASSERT_EQ(2U, service->extensions()->size());
    214   ASSERT_EQ(1U, model->size());
    215   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    216   service->AddExtension(ext2.get());
    217   ASSERT_EQ(3U, service->extensions()->size());
    218   ASSERT_EQ(1U, model->size());
    219   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    220   service->AddExtension(bgapp2.get());
    221   ASSERT_EQ(4U, service->extensions()->size());
    222   ASSERT_EQ(2U, model->size());
    223   ASSERT_FALSE(IsBackgroundApp(*ext3.get()));
    224   service->AddExtension(ext3.get());
    225   ASSERT_EQ(5U, service->extensions()->size());
    226   ASSERT_EQ(2U, model->size());
    227 
    228   // Remove in FIFO order.
    229   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    230   service->UninstallExtension(ext1->id(),
    231                               extensions::UNINSTALL_REASON_FOR_TESTING,
    232                               base::Bind(&base::DoNothing),
    233                               NULL);
    234   ASSERT_EQ(4U, service->extensions()->size());
    235   ASSERT_EQ(2U, model->size());
    236   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    237   service->UninstallExtension(bgapp1->id(),
    238                               extensions::UNINSTALL_REASON_FOR_TESTING,
    239                               base::Bind(&base::DoNothing),
    240                               NULL);
    241   ASSERT_EQ(3U, service->extensions()->size());
    242   ASSERT_EQ(1U, model->size());
    243   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    244   service->UninstallExtension(ext2->id(),
    245                               extensions::UNINSTALL_REASON_FOR_TESTING,
    246                               base::Bind(&base::DoNothing),
    247                               NULL);
    248   ASSERT_EQ(2U, service->extensions()->size());
    249   ASSERT_EQ(1U, model->size());
    250   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    251   service->UninstallExtension(bgapp2->id(),
    252                               extensions::UNINSTALL_REASON_FOR_TESTING,
    253                               base::Bind(&base::DoNothing),
    254                               NULL);
    255   ASSERT_EQ(1U, service->extensions()->size());
    256   ASSERT_EQ(0U, model->size());
    257   ASSERT_FALSE(IsBackgroundApp(*ext3.get()));
    258   service->UninstallExtension(ext3->id(),
    259                               extensions::UNINSTALL_REASON_FOR_TESTING,
    260                               base::Bind(&base::DoNothing),
    261                               NULL);
    262   ASSERT_EQ(0U, service->extensions()->size());
    263   ASSERT_EQ(0U, model->size());
    264 }
    265 
    266 // Verifies that pushMessaging also triggers background detection, except
    267 // when extension is in a whitelist.
    268 TEST_F(BackgroundApplicationListModelTest, PushMessagingTest) {
    269   InitializeAndLoadEmptyExtensionService();
    270   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    271       extension_service();
    272   ASSERT_TRUE(service);
    273   ASSERT_TRUE(service->is_ready());
    274   ASSERT_TRUE(service->extensions());
    275   ASSERT_TRUE(service->extensions()->is_empty());
    276   scoped_ptr<BackgroundApplicationListModel> model(
    277       new BackgroundApplicationListModel(profile_.get()));
    278   ASSERT_EQ(0U, model->size());
    279 
    280   scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
    281   scoped_refptr<Extension> ext2 =
    282       CreateExtensionBase("charlie", false, PUSH_MESSAGING_BUT_NOT_BACKGROUND);
    283   scoped_refptr<Extension> bgapp1 =
    284       CreateExtensionBase("bravo", false, PUSH_MESSAGING_PERMISSION);
    285   scoped_refptr<Extension> bgapp2 =
    286       CreateExtensionBase("delta", true, PUSH_MESSAGING_PERMISSION);
    287   scoped_refptr<Extension> bgapp3 =
    288       CreateExtensionBase("echo", true, PUSH_MESSAGING_BUT_NOT_BACKGROUND);
    289   ASSERT_TRUE(service->extensions() != NULL);
    290   ASSERT_EQ(0U, service->extensions()->size());
    291   ASSERT_EQ(0U, model->size());
    292 
    293   // Add alternating Extensions and Background Apps
    294   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    295   service->AddExtension(ext1.get());
    296   ASSERT_EQ(1U, service->extensions()->size());
    297   ASSERT_EQ(0U, model->size());
    298   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    299   service->AddExtension(bgapp1.get());
    300   ASSERT_EQ(2U, service->extensions()->size());
    301   ASSERT_EQ(1U, model->size());
    302   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    303   service->AddExtension(ext2.get());
    304   ASSERT_EQ(3U, service->extensions()->size());
    305   ASSERT_EQ(1U, model->size());
    306   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    307   service->AddExtension(bgapp2.get());
    308   ASSERT_EQ(4U, service->extensions()->size());
    309   ASSERT_EQ(2U, model->size());
    310   // Need to remove ext2 because it uses same id as bgapp3.
    311   ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
    312   service->UninstallExtension(ext2->id(),
    313                               extensions::UNINSTALL_REASON_FOR_TESTING,
    314                               base::Bind(&base::DoNothing),
    315                               NULL);
    316   ASSERT_EQ(3U, service->extensions()->size());
    317   ASSERT_EQ(2U, model->size());
    318   ASSERT_TRUE(IsBackgroundApp(*bgapp3.get()));
    319   service->AddExtension(bgapp3.get());
    320   ASSERT_EQ(4U, service->extensions()->size());
    321   ASSERT_EQ(3U, model->size());
    322 
    323   // Remove in FIFO order.
    324   ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
    325   service->UninstallExtension(ext1->id(),
    326                               extensions::UNINSTALL_REASON_FOR_TESTING,
    327                               base::Bind(&base::DoNothing),
    328                               NULL);
    329   ASSERT_EQ(3U, service->extensions()->size());
    330   ASSERT_EQ(3U, model->size());
    331   ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
    332   service->UninstallExtension(bgapp1->id(),
    333                               extensions::UNINSTALL_REASON_FOR_TESTING,
    334                               base::Bind(&base::DoNothing),
    335                               NULL);
    336   ASSERT_EQ(2U, service->extensions()->size());
    337   ASSERT_EQ(2U, model->size());
    338   ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
    339   service->UninstallExtension(bgapp2->id(),
    340                               extensions::UNINSTALL_REASON_FOR_TESTING,
    341                               base::Bind(&base::DoNothing),
    342                               NULL);
    343   ASSERT_EQ(1U, service->extensions()->size());
    344   ASSERT_EQ(1U, model->size());
    345   ASSERT_TRUE(IsBackgroundApp(*bgapp3.get()));
    346   service->UninstallExtension(bgapp3->id(),
    347                               extensions::UNINSTALL_REASON_FOR_TESTING,
    348                               base::Bind(&base::DoNothing),
    349                               NULL);
    350   ASSERT_EQ(0U, service->extensions()->size());
    351   ASSERT_EQ(0U, model->size());
    352 }
    353 
    354 // Verifies that an ephemeral app cannot trigger background mode.
    355 TEST_F(BackgroundApplicationListModelTest, EphemeralAppTest) {
    356   InitializeAndLoadEmptyExtensionService();
    357   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    358       extension_service();
    359   ASSERT_TRUE(service);
    360   ASSERT_TRUE(service->is_ready());
    361   ASSERT_TRUE(service->extensions());
    362   ASSERT_TRUE(service->extensions()->is_empty());
    363   scoped_ptr<BackgroundApplicationListModel> model(
    364       new BackgroundApplicationListModel(profile_.get()));
    365   ASSERT_EQ(0U, model->size());
    366 
    367   scoped_refptr<Extension> installed =
    368       CreateExtensionBase("installed", false, PUSH_MESSAGING_PERMISSION);
    369   scoped_refptr<Extension> ephemeral =
    370       CreateExtensionBase("ephemeral", false, PUSH_MESSAGING_PERMISSION);
    371   scoped_refptr<Extension> background = CreateExtension("background", true);
    372 
    373   // Installed app with push messaging permissions can trigger background mode.
    374   ASSERT_TRUE(IsBackgroundApp(*installed.get()));
    375   service->AddExtension(installed.get());
    376   ASSERT_EQ(1U, service->extensions()->size());
    377   ASSERT_EQ(1U, model->size());
    378   // An ephemeral app with push messaging permissions should not trigger
    379   // background mode.
    380   AddEphemeralApp(ephemeral.get(), service);
    381   ASSERT_FALSE(IsBackgroundApp(*ephemeral.get()));
    382   ASSERT_EQ(2U, service->extensions()->size());
    383   ASSERT_EQ(1U, model->size());
    384   // An ephemeral app with the background permission should not trigger
    385   // background mode.
    386   AddEphemeralApp(background.get(), service);
    387   ASSERT_FALSE(IsBackgroundApp(*background.get()));
    388   ASSERT_EQ(3U, service->extensions()->size());
    389   ASSERT_EQ(1U, model->size());
    390 
    391   // If the ephemeral app becomes promoted to an installed app, it can now
    392   // trigger background mode.
    393   service->PromoteEphemeralApp(ephemeral.get(), false /*from sync*/);
    394   ASSERT_TRUE(IsBackgroundApp(*ephemeral.get()));
    395   ASSERT_EQ(3U, service->extensions()->size());
    396   ASSERT_EQ(2U, model->size());
    397 }
    398 
    399 // With minimal test logic, verifies behavior with dynamic permissions.
    400 TEST_F(BackgroundApplicationListModelTest, AddRemovePermissionsTest) {
    401   InitializeAndLoadEmptyExtensionService();
    402   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    403       extension_service();
    404   ASSERT_TRUE(service);
    405   ASSERT_TRUE(service->is_ready());
    406   ASSERT_TRUE(service->extensions());
    407   ASSERT_TRUE(service->extensions()->is_empty());
    408   scoped_ptr<BackgroundApplicationListModel> model(
    409       new BackgroundApplicationListModel(profile_.get()));
    410   ASSERT_EQ(0U, model->size());
    411 
    412   scoped_refptr<Extension> ext = CreateExtension("extension", false);
    413   ASSERT_FALSE(
    414       ext->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    415   scoped_refptr<Extension> bgapp = CreateExtension("application", true);
    416   ASSERT_TRUE(
    417       bgapp->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    418   ASSERT_TRUE(service->extensions() != NULL);
    419   ASSERT_EQ(0U, service->extensions()->size());
    420   ASSERT_EQ(0U, model->size());
    421 
    422   // Add one (non-background) extension and one background application
    423   ASSERT_FALSE(IsBackgroundApp(*ext.get()));
    424   service->AddExtension(ext.get());
    425   ASSERT_EQ(1U, service->extensions()->size());
    426   ASSERT_EQ(0U, model->size());
    427   ASSERT_TRUE(IsBackgroundApp(*bgapp.get()));
    428   service->AddExtension(bgapp.get());
    429   ASSERT_EQ(2U, service->extensions()->size());
    430   ASSERT_EQ(1U, model->size());
    431 
    432   // Change permissions back and forth
    433   AddBackgroundPermission(service, ext.get());
    434   ASSERT_TRUE(
    435       ext->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    436   ASSERT_EQ(2U, service->extensions()->size());
    437   ASSERT_EQ(2U, model->size());
    438   RemoveBackgroundPermission(service, bgapp.get());
    439   ASSERT_FALSE(
    440       bgapp->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    441   ASSERT_EQ(2U, service->extensions()->size());
    442   ASSERT_EQ(1U, model->size());
    443   RemoveBackgroundPermission(service, ext.get());
    444   ASSERT_FALSE(
    445       ext->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    446   ASSERT_EQ(2U, service->extensions()->size());
    447   ASSERT_EQ(0U, model->size());
    448   AddBackgroundPermission(service, bgapp.get());
    449   ASSERT_TRUE(
    450       bgapp->permissions_data()->HasAPIPermission(APIPermission::kBackground));
    451   ASSERT_EQ(2U, service->extensions()->size());
    452   ASSERT_EQ(1U, model->size());
    453 }
    454 
    455 typedef std::set<scoped_refptr<Extension> > ExtensionCollection;
    456 
    457 namespace {
    458 void AddExtension(ExtensionService* service,
    459                   ExtensionCollection* extensions,
    460                   BackgroundApplicationListModel* model,
    461                   size_t* expected,
    462                   size_t* count) {
    463   bool create_background = false;
    464   if (rand() % 2) {
    465     create_background = true;
    466     ++*expected;
    467   }
    468   scoped_refptr<Extension> extension =
    469       CreateExtension(GenerateUniqueExtensionName(), create_background);
    470   ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    471                                                             service->profile()),
    472             create_background);
    473   extensions->insert(extension);
    474   ++*count;
    475   ASSERT_EQ(*count, extensions->size());
    476   service->AddExtension(extension.get());
    477   ASSERT_EQ(*count, service->extensions()->size());
    478   ASSERT_EQ(*expected, model->size());
    479 }
    480 
    481 void RemoveExtension(ExtensionService* service,
    482                      ExtensionCollection* extensions,
    483                      BackgroundApplicationListModel* model,
    484                      size_t* expected,
    485                      size_t* count) {  // Maybe remove an extension.
    486   ExtensionCollection::iterator cursor = extensions->begin();
    487   if (cursor == extensions->end()) {
    488     // Nothing to remove.  Just verify accounting.
    489     ASSERT_EQ(0U, *count);
    490     ASSERT_EQ(0U, *expected);
    491     ASSERT_EQ(0U, service->extensions()->size());
    492     ASSERT_EQ(0U, model->size());
    493   } else {
    494     // Randomly select which extension to remove
    495     if (extensions->size() > 1) {
    496       int offset = rand() % (extensions->size() - 1);
    497       for (int index = 0; index < offset; ++index)
    498         ++cursor;
    499     }
    500     scoped_refptr<Extension> extension = cursor->get();
    501     std::string id = extension->id();
    502     if (BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    503                                                         service->profile())) {
    504       --*expected;
    505     }
    506     extensions->erase(cursor);
    507     --*count;
    508     ASSERT_EQ(*count, extensions->size());
    509     service->UninstallExtension(extension->id(),
    510                                 extensions::UNINSTALL_REASON_FOR_TESTING,
    511                                 base::Bind(&base::DoNothing),
    512                                 NULL);
    513     ASSERT_EQ(*count, service->extensions()->size());
    514     ASSERT_EQ(*expected, model->size());
    515   }
    516 }
    517 
    518 void TogglePermission(ExtensionService* service,
    519                       ExtensionCollection* extensions,
    520                       BackgroundApplicationListModel* model,
    521                       size_t* expected,
    522                       size_t* count) {
    523   ExtensionCollection::iterator cursor = extensions->begin();
    524   if (cursor == extensions->end()) {
    525     // Nothing to toggle.  Just verify accounting.
    526     ASSERT_EQ(0U, *count);
    527     ASSERT_EQ(0U, *expected);
    528     ASSERT_EQ(0U, service->extensions()->size());
    529     ASSERT_EQ(0U, model->size());
    530   } else {
    531     // Randomly select which extension to toggle.
    532     if (extensions->size() > 1) {
    533       int offset = rand() % (extensions->size() - 1);
    534       for (int index = 0; index < offset; ++index)
    535         ++cursor;
    536     }
    537     scoped_refptr<Extension> extension = cursor->get();
    538     std::string id = extension->id();
    539     if (BackgroundApplicationListModel::IsBackgroundApp(*extension.get(),
    540                                                         service->profile())) {
    541       --*expected;
    542       ASSERT_EQ(*count, extensions->size());
    543       RemoveBackgroundPermission(service, extension.get());
    544       ASSERT_EQ(*count, service->extensions()->size());
    545       ASSERT_EQ(*expected, model->size());
    546     } else {
    547       ++*expected;
    548       ASSERT_EQ(*count, extensions->size());
    549       AddBackgroundPermission(service, extension.get());
    550       ASSERT_EQ(*count, service->extensions()->size());
    551       ASSERT_EQ(*expected, model->size());
    552     }
    553   }
    554 }
    555 }  // namespace
    556 
    557 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
    558 // removing extensions, of which some are Background Apps and others are not.
    559 TEST_F(BackgroundApplicationListModelTest, RandomTest) {
    560   InitializeAndLoadEmptyExtensionService();
    561   ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
    562       extension_service();
    563   ASSERT_TRUE(service);
    564   ASSERT_TRUE(service->is_ready());
    565   ASSERT_TRUE(service->extensions());
    566   ASSERT_TRUE(service->extensions()->is_empty());
    567   scoped_ptr<BackgroundApplicationListModel> model(
    568       new BackgroundApplicationListModel(profile_.get()));
    569   ASSERT_EQ(0U, model->size());
    570 
    571   static const int kIterations = 20;
    572   ExtensionCollection extensions;
    573   size_t count = 0;
    574   size_t expected = 0;
    575   srand(RANDOM_SEED);
    576   for (int index = 0; index < kIterations; ++index) {
    577     switch (rand() % 3) {
    578       case 0:
    579         AddExtension(service, &extensions, model.get(), &expected, &count);
    580         break;
    581       case 1:
    582         RemoveExtension(service, &extensions, model.get(), &expected, &count);
    583         break;
    584       case 2:
    585         TogglePermission(service, &extensions, model.get(), &expected, &count);
    586         break;
    587       default:
    588         NOTREACHED();
    589         break;
    590     }
    591   }
    592 }
    593