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.
5 // TODO(rickcam): Bug 73183: Add unit tests for image loading
10 #include "chrome/browser/background/background_application_list_model.h"
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/test/base/testing_profile.h"
22 #include "content/public/browser/notification_registrar.h"
23 #include "content/public/browser/notification_types.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 "testing/gtest/include/gtest/gtest.h"
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)
34 using extensions::APIPermission
;
35 using extensions::Extension
;
37 // For ExtensionService interface when it requires a path that is not used.
38 base::FilePath
bogus_file_pathname(const std::string
& name
) {
39 return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"))
43 class BackgroundApplicationListModelTest
: public ExtensionServiceTestBase
{
45 BackgroundApplicationListModelTest() {}
46 virtual ~BackgroundApplicationListModelTest() {}
49 void InitializeAndLoadEmptyExtensionService() {
50 InitializeEmptyExtensionService();
51 service_
->Init(); /* Sends EXTENSIONS_READY */
54 bool IsBackgroundApp(const Extension
& app
) {
55 return BackgroundApplicationListModel::IsBackgroundApp(app
,
60 enum PushMessagingOption
{
62 PUSH_MESSAGING_PERMISSION
,
63 PUSH_MESSAGING_BUT_NOT_BACKGROUND
66 // Returns a barebones test Extension object with the specified |name|. The
67 // returned extension will include background permission iff
68 // |background_permission| is true and pushMessaging permission if requested
69 // by |push_messaging| value. Also the extension may have a specific id set
70 // to test the case when it has a pushMessaging permission but is not
71 // considered a background app based on a whitelist.
72 static scoped_refptr
<Extension
> CreateExtensionBase(
73 const std::string
& name
,
74 bool background_permission
,
75 PushMessagingOption push_messaging
) {
76 base::DictionaryValue manifest
;
77 manifest
.SetString(extensions::manifest_keys::kVersion
, "1.0.0.0");
78 manifest
.SetString(extensions::manifest_keys::kName
, name
);
79 base::ListValue
* permissions
= new base::ListValue();
80 manifest
.Set(extensions::manifest_keys::kPermissions
, permissions
);
81 if (background_permission
) {
82 permissions
->Append(base::Value::CreateStringValue("background"));
84 if (push_messaging
== PUSH_MESSAGING_PERMISSION
||
85 push_messaging
== PUSH_MESSAGING_BUT_NOT_BACKGROUND
) {
86 permissions
->Append(base::Value::CreateStringValue("pushMessaging"));
90 scoped_refptr
<Extension
> extension
;
92 // There is a whitelist for extensions that have pushMessaging permission but
93 // are not considered a background app. Create a test extension with a known
95 if (push_messaging
== PUSH_MESSAGING_BUT_NOT_BACKGROUND
) {
96 extension
= Extension::Create(
97 bogus_file_pathname(name
),
98 extensions::Manifest::INVALID_LOCATION
,
101 "aaaabbbbccccddddeeeeffffgggghhhh",
104 extension
= Extension::Create(
105 bogus_file_pathname(name
),
106 extensions::Manifest::INVALID_LOCATION
,
112 // Cannot ASSERT_* here because that attempts an illegitimate return.
113 // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
114 EXPECT_TRUE(extension
.get() != NULL
) << error
;
118 static scoped_refptr
<Extension
> CreateExtension(const std::string
& name
,
119 bool background_permission
) {
120 return CreateExtensionBase(name
, background_permission
, NO_PUSH_MESSAGING
);
124 std::string
GenerateUniqueExtensionName() {
125 static int uniqueness
= 0;
126 std::ostringstream output
;
127 output
<< "Unique Named Extension " << uniqueness
;
132 void AddBackgroundPermission(ExtensionService
* service
,
133 Extension
* extension
) {
134 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
,
135 service
->profile())) {
139 scoped_refptr
<Extension
> temporary
=
140 CreateExtension(GenerateUniqueExtensionName(), true);
141 scoped_refptr
<const extensions::PermissionSet
> permissions
=
142 temporary
->GetActivePermissions();
143 extensions::PermissionsUpdater(service
->profile()).AddPermissions(
144 extension
, permissions
.get());
147 void RemoveBackgroundPermission(ExtensionService
* service
,
148 Extension
* extension
) {
149 if (!BackgroundApplicationListModel::IsBackgroundApp(*extension
,
150 service
->profile())) {
153 extensions::PermissionsUpdater(service
->profile())
154 .RemovePermissions(extension
, extension
->GetActivePermissions().get());
158 // Crashes on Mac tryslaves.
159 // http://crbug.com/165458
160 #if defined(OS_MACOSX) || defined(OS_LINUX)
161 #define MAYBE_ExplicitTest DISABLED_ExplicitTest
163 #define MAYBE_ExplicitTest ExplicitTest
165 // With minimal test logic, verifies behavior over an explicit set of
166 // extensions, of which some are Background Apps and others are not.
167 TEST_F(BackgroundApplicationListModelTest
, MAYBE_ExplicitTest
) {
168 InitializeAndLoadEmptyExtensionService();
169 ExtensionService
* service
= extensions::ExtensionSystem::Get(profile_
.get())->
171 ASSERT_TRUE(service
);
172 ASSERT_TRUE(service
->is_ready());
173 ASSERT_TRUE(service
->extensions());
174 ASSERT_TRUE(service
->extensions()->is_empty());
175 scoped_ptr
<BackgroundApplicationListModel
> model(
176 new BackgroundApplicationListModel(profile_
.get()));
177 ASSERT_EQ(0U, model
->size());
179 scoped_refptr
<Extension
> ext1
= CreateExtension("alpha", false);
180 scoped_refptr
<Extension
> ext2
= CreateExtension("bravo", false);
181 scoped_refptr
<Extension
> ext3
= CreateExtension("charlie", false);
182 scoped_refptr
<Extension
> bgapp1
= CreateExtension("delta", true);
183 scoped_refptr
<Extension
> bgapp2
= CreateExtension("echo", true);
184 ASSERT_TRUE(service
->extensions() != NULL
);
185 ASSERT_EQ(0U, service
->extensions()->size());
186 ASSERT_EQ(0U, model
->size());
188 // Add alternating Extensions and Background Apps
189 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
190 service
->AddExtension(ext1
.get());
191 ASSERT_EQ(1U, service
->extensions()->size());
192 ASSERT_EQ(0U, model
->size());
193 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
194 service
->AddExtension(bgapp1
.get());
195 ASSERT_EQ(2U, service
->extensions()->size());
196 ASSERT_EQ(1U, model
->size());
197 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
198 service
->AddExtension(ext2
.get());
199 ASSERT_EQ(3U, service
->extensions()->size());
200 ASSERT_EQ(1U, model
->size());
201 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
202 service
->AddExtension(bgapp2
.get());
203 ASSERT_EQ(4U, service
->extensions()->size());
204 ASSERT_EQ(2U, model
->size());
205 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
206 service
->AddExtension(ext3
.get());
207 ASSERT_EQ(5U, service
->extensions()->size());
208 ASSERT_EQ(2U, model
->size());
210 // Remove in FIFO order.
211 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
212 service
->UninstallExtension(ext1
->id(), false, NULL
);
213 ASSERT_EQ(4U, service
->extensions()->size());
214 ASSERT_EQ(2U, model
->size());
215 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
216 service
->UninstallExtension(bgapp1
->id(), false, NULL
);
217 ASSERT_EQ(3U, service
->extensions()->size());
218 ASSERT_EQ(1U, model
->size());
219 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
220 service
->UninstallExtension(ext2
->id(), false, NULL
);
221 ASSERT_EQ(2U, service
->extensions()->size());
222 ASSERT_EQ(1U, model
->size());
223 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
224 service
->UninstallExtension(bgapp2
->id(), false, NULL
);
225 ASSERT_EQ(1U, service
->extensions()->size());
226 ASSERT_EQ(0U, model
->size());
227 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
228 service
->UninstallExtension(ext3
->id(), false, NULL
);
229 ASSERT_EQ(0U, service
->extensions()->size());
230 ASSERT_EQ(0U, model
->size());
233 // Verifies that pushMessaging also triggers background detection, except
234 // when extension is in a whitelist.
235 TEST_F(BackgroundApplicationListModelTest
, PushMessagingTest
) {
236 InitializeAndLoadEmptyExtensionService();
237 ExtensionService
* service
= extensions::ExtensionSystem::Get(profile_
.get())->
239 ASSERT_TRUE(service
);
240 ASSERT_TRUE(service
->is_ready());
241 ASSERT_TRUE(service
->extensions());
242 ASSERT_TRUE(service
->extensions()->is_empty());
243 scoped_ptr
<BackgroundApplicationListModel
> model(
244 new BackgroundApplicationListModel(profile_
.get()));
245 ASSERT_EQ(0U, model
->size());
247 scoped_refptr
<Extension
> ext1
= CreateExtension("alpha", false);
248 scoped_refptr
<Extension
> ext2
=
249 CreateExtensionBase("charlie", false, PUSH_MESSAGING_BUT_NOT_BACKGROUND
);
250 scoped_refptr
<Extension
> bgapp1
=
251 CreateExtensionBase("bravo", false, PUSH_MESSAGING_PERMISSION
);
252 scoped_refptr
<Extension
> bgapp2
=
253 CreateExtensionBase("delta", true, PUSH_MESSAGING_PERMISSION
);
254 scoped_refptr
<Extension
> bgapp3
=
255 CreateExtensionBase("echo", true, PUSH_MESSAGING_BUT_NOT_BACKGROUND
);
256 ASSERT_TRUE(service
->extensions() != NULL
);
257 ASSERT_EQ(0U, service
->extensions()->size());
258 ASSERT_EQ(0U, model
->size());
260 // Add alternating Extensions and Background Apps
261 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
262 service
->AddExtension(ext1
.get());
263 ASSERT_EQ(1U, service
->extensions()->size());
264 ASSERT_EQ(0U, model
->size());
265 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
266 service
->AddExtension(bgapp1
.get());
267 ASSERT_EQ(2U, service
->extensions()->size());
268 ASSERT_EQ(1U, model
->size());
269 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
270 service
->AddExtension(ext2
.get());
271 ASSERT_EQ(3U, service
->extensions()->size());
272 ASSERT_EQ(1U, model
->size());
273 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
274 service
->AddExtension(bgapp2
.get());
275 ASSERT_EQ(4U, service
->extensions()->size());
276 ASSERT_EQ(2U, model
->size());
277 // Need to remove ext2 because it uses same id as bgapp3.
278 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
279 service
->UninstallExtension(ext2
->id(), false, NULL
);
280 ASSERT_EQ(3U, service
->extensions()->size());
281 ASSERT_EQ(2U, model
->size());
282 ASSERT_TRUE(IsBackgroundApp(*bgapp3
.get()));
283 service
->AddExtension(bgapp3
.get());
284 ASSERT_EQ(4U, service
->extensions()->size());
285 ASSERT_EQ(3U, model
->size());
287 // Remove in FIFO order.
288 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
289 service
->UninstallExtension(ext1
->id(), false, NULL
);
290 ASSERT_EQ(3U, service
->extensions()->size());
291 ASSERT_EQ(3U, model
->size());
292 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
293 service
->UninstallExtension(bgapp1
->id(), false, NULL
);
294 ASSERT_EQ(2U, service
->extensions()->size());
295 ASSERT_EQ(2U, model
->size());
296 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
297 service
->UninstallExtension(bgapp2
->id(), false, NULL
);
298 ASSERT_EQ(1U, service
->extensions()->size());
299 ASSERT_EQ(1U, model
->size());
300 ASSERT_TRUE(IsBackgroundApp(*bgapp3
.get()));
301 service
->UninstallExtension(bgapp3
->id(), false, NULL
);
302 ASSERT_EQ(0U, service
->extensions()->size());
303 ASSERT_EQ(0U, model
->size());
308 // With minimal test logic, verifies behavior with dynamic permissions.
309 TEST_F(BackgroundApplicationListModelTest
, AddRemovePermissionsTest
) {
310 InitializeAndLoadEmptyExtensionService();
311 ExtensionService
* service
= extensions::ExtensionSystem::Get(profile_
.get())->
313 ASSERT_TRUE(service
);
314 ASSERT_TRUE(service
->is_ready());
315 ASSERT_TRUE(service
->extensions());
316 ASSERT_TRUE(service
->extensions()->is_empty());
317 scoped_ptr
<BackgroundApplicationListModel
> model(
318 new BackgroundApplicationListModel(profile_
.get()));
319 ASSERT_EQ(0U, model
->size());
321 scoped_refptr
<Extension
> ext
= CreateExtension("extension", false);
322 ASSERT_FALSE(ext
->HasAPIPermission(APIPermission::kBackground
));
323 scoped_refptr
<Extension
> bgapp
= CreateExtension("application", true);
324 ASSERT_TRUE(bgapp
->HasAPIPermission(APIPermission::kBackground
));
325 ASSERT_TRUE(service
->extensions() != NULL
);
326 ASSERT_EQ(0U, service
->extensions()->size());
327 ASSERT_EQ(0U, model
->size());
329 // Add one (non-background) extension and one background application
330 ASSERT_FALSE(IsBackgroundApp(*ext
.get()));
331 service
->AddExtension(ext
.get());
332 ASSERT_EQ(1U, service
->extensions()->size());
333 ASSERT_EQ(0U, model
->size());
334 ASSERT_TRUE(IsBackgroundApp(*bgapp
.get()));
335 service
->AddExtension(bgapp
.get());
336 ASSERT_EQ(2U, service
->extensions()->size());
337 ASSERT_EQ(1U, model
->size());
339 // Change permissions back and forth
340 AddBackgroundPermission(service
, ext
.get());
341 ASSERT_TRUE(ext
->HasAPIPermission(APIPermission::kBackground
));
342 ASSERT_EQ(2U, service
->extensions()->size());
343 ASSERT_EQ(2U, model
->size());
344 RemoveBackgroundPermission(service
, bgapp
.get());
345 ASSERT_FALSE(bgapp
->HasAPIPermission(APIPermission::kBackground
));
346 ASSERT_EQ(2U, service
->extensions()->size());
347 ASSERT_EQ(1U, model
->size());
348 RemoveBackgroundPermission(service
, ext
.get());
349 ASSERT_FALSE(ext
->HasAPIPermission(APIPermission::kBackground
));
350 ASSERT_EQ(2U, service
->extensions()->size());
351 ASSERT_EQ(0U, model
->size());
352 AddBackgroundPermission(service
, bgapp
.get());
353 ASSERT_TRUE(bgapp
->HasAPIPermission(APIPermission::kBackground
));
354 ASSERT_EQ(2U, service
->extensions()->size());
355 ASSERT_EQ(1U, model
->size());
358 typedef std::set
<scoped_refptr
<Extension
> > ExtensionCollection
;
361 void AddExtension(ExtensionService
* service
,
362 ExtensionCollection
* extensions
,
363 BackgroundApplicationListModel
* model
,
366 bool create_background
= false;
368 create_background
= true;
371 scoped_refptr
<Extension
> extension
=
372 CreateExtension(GenerateUniqueExtensionName(), create_background
);
373 ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
376 extensions
->insert(extension
);
378 ASSERT_EQ(*count
, extensions
->size());
379 service
->AddExtension(extension
.get());
380 ASSERT_EQ(*count
, service
->extensions()->size());
381 ASSERT_EQ(*expected
, model
->size());
384 void RemoveExtension(ExtensionService
* service
,
385 ExtensionCollection
* extensions
,
386 BackgroundApplicationListModel
* model
,
388 size_t* count
) { // Maybe remove an extension.
389 ExtensionCollection::iterator cursor
= extensions
->begin();
390 if (cursor
== extensions
->end()) {
391 // Nothing to remove. Just verify accounting.
392 ASSERT_EQ(0U, *count
);
393 ASSERT_EQ(0U, *expected
);
394 ASSERT_EQ(0U, service
->extensions()->size());
395 ASSERT_EQ(0U, model
->size());
397 // Randomly select which extension to remove
398 if (extensions
->size() > 1) {
399 int offset
= rand() % (extensions
->size() - 1);
400 for (int index
= 0; index
< offset
; ++index
)
403 scoped_refptr
<Extension
> extension
= cursor
->get();
404 std::string id
= extension
->id();
405 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
406 service
->profile())) {
409 extensions
->erase(cursor
);
411 ASSERT_EQ(*count
, extensions
->size());
412 service
->UninstallExtension(extension
->id(), false, NULL
);
413 ASSERT_EQ(*count
, service
->extensions()->size());
414 ASSERT_EQ(*expected
, model
->size());
418 void TogglePermission(ExtensionService
* service
,
419 ExtensionCollection
* extensions
,
420 BackgroundApplicationListModel
* model
,
423 ExtensionCollection::iterator cursor
= extensions
->begin();
424 if (cursor
== extensions
->end()) {
425 // Nothing to toggle. Just verify accounting.
426 ASSERT_EQ(0U, *count
);
427 ASSERT_EQ(0U, *expected
);
428 ASSERT_EQ(0U, service
->extensions()->size());
429 ASSERT_EQ(0U, model
->size());
431 // Randomly select which extension to toggle.
432 if (extensions
->size() > 1) {
433 int offset
= rand() % (extensions
->size() - 1);
434 for (int index
= 0; index
< offset
; ++index
)
437 scoped_refptr
<Extension
> extension
= cursor
->get();
438 std::string id
= extension
->id();
439 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
440 service
->profile())) {
442 ASSERT_EQ(*count
, extensions
->size());
443 RemoveBackgroundPermission(service
, extension
.get());
444 ASSERT_EQ(*count
, service
->extensions()->size());
445 ASSERT_EQ(*expected
, model
->size());
448 ASSERT_EQ(*count
, extensions
->size());
449 AddBackgroundPermission(service
, extension
.get());
450 ASSERT_EQ(*count
, service
->extensions()->size());
451 ASSERT_EQ(*expected
, model
->size());
457 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
458 // removing extensions, of which some are Background Apps and others are not.
459 TEST_F(BackgroundApplicationListModelTest
, RandomTest
) {
460 InitializeAndLoadEmptyExtensionService();
461 ExtensionService
* service
= extensions::ExtensionSystem::Get(profile_
.get())->
463 ASSERT_TRUE(service
);
464 ASSERT_TRUE(service
->is_ready());
465 ASSERT_TRUE(service
->extensions());
466 ASSERT_TRUE(service
->extensions()->is_empty());
467 scoped_ptr
<BackgroundApplicationListModel
> model(
468 new BackgroundApplicationListModel(profile_
.get()));
469 ASSERT_EQ(0U, model
->size());
471 static const int kIterations
= 20;
472 ExtensionCollection extensions
;
476 for (int index
= 0; index
< kIterations
; ++index
) {
477 switch (rand() % 3) {
479 AddExtension(service
, &extensions
, model
.get(), &expected
, &count
);
482 RemoveExtension(service
, &extensions
, model
.get(), &expected
, &count
);
485 TogglePermission(service
, &extensions
, model
.get(), &expected
, &count
);