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