background_application_list_model_unittest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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.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 34using extensions::APIPermission; 35using extensions::Extension; 36 37// For ExtensionService interface when it requires a path that is not used. 38base::FilePath bogus_file_path() { 39 return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent")); 40} 41 42class 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. 62static 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 85namespace { 86std::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 94void 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 109void RemoveBackgroundPermission(ExtensionService* service, 110 Extension* extension) { 111 if (!BackgroundApplicationListModel::IsBackgroundApp(*extension, 112 service->profile())) { 113 return; 114 } 115 extensions::PermissionsUpdater(service->profile()).RemovePermissions( 116 extension, extension->GetActivePermissions()); 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. 129TEST_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)); 152 service->AddExtension(ext1); 153 ASSERT_EQ(1U, service->extensions()->size()); 154 ASSERT_EQ(0U, model->size()); 155 ASSERT_TRUE(IsBackgroundApp(*bgapp1)); 156 service->AddExtension(bgapp1); 157 ASSERT_EQ(2U, service->extensions()->size()); 158 ASSERT_EQ(1U, model->size()); 159 ASSERT_FALSE(IsBackgroundApp(*ext2)); 160 service->AddExtension(ext2); 161 ASSERT_EQ(3U, service->extensions()->size()); 162 ASSERT_EQ(1U, model->size()); 163 ASSERT_TRUE(IsBackgroundApp(*bgapp2)); 164 service->AddExtension(bgapp2); 165 ASSERT_EQ(4U, service->extensions()->size()); 166 ASSERT_EQ(2U, model->size()); 167 ASSERT_FALSE(IsBackgroundApp(*ext3)); 168 service->AddExtension(ext3); 169 ASSERT_EQ(5U, service->extensions()->size()); 170 ASSERT_EQ(2U, model->size()); 171 172 // Remove in FIFO order. 173 ASSERT_FALSE(IsBackgroundApp(*ext1)); 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)); 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)); 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)); 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)); 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. 196TEST_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)); 218 service->AddExtension(ext); 219 ASSERT_EQ(1U, service->extensions()->size()); 220 ASSERT_EQ(0U, model->size()); 221 ASSERT_TRUE(IsBackgroundApp(*bgapp)); 222 service->AddExtension(bgapp); 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 245typedef std::set<scoped_refptr<Extension> > ExtensionCollection; 246 247namespace { 248void 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, 261 service->profile()), 262 create_background); 263 extensions->insert(extension); 264 ++*count; 265 ASSERT_EQ(*count, extensions->size()); 266 service->AddExtension(extension); 267 ASSERT_EQ(*count, service->extensions()->size()); 268 ASSERT_EQ(*expected, model->size()); 269} 270 271void 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, 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 305void 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, 327 service->profile())) { 328 --*expected; 329 ASSERT_EQ(*count, extensions->size()); 330 RemoveBackgroundPermission(service, extension); 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); 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. 346TEST_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 = 500; 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