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_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_registry.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"
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)
37 using extensions::APIPermission
;
38 using extensions::Extension
;
39 using extensions::ExtensionRegistry
;
41 // For ExtensionService interface when it requires a path that is not used.
42 base::FilePath
bogus_file_pathname(const std::string
& name
) {
43 return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"))
47 class BackgroundApplicationListModelTest
48 : public extensions::ExtensionServiceTestBase
{
50 BackgroundApplicationListModelTest() {}
51 ~BackgroundApplicationListModelTest() override
{}
54 void InitializeAndLoadEmptyExtensionService() {
55 InitializeEmptyExtensionService();
56 service_
->Init(); /* Sends EXTENSIONS_READY */
59 bool IsBackgroundApp(const Extension
& app
) {
60 return BackgroundApplicationListModel::IsBackgroundApp(app
,
65 enum PushMessagingOption
{
67 PUSH_MESSAGING_PERMISSION
,
68 PUSH_MESSAGING_BUT_NOT_BACKGROUND
71 // Returns a barebones test Extension object with the specified |name|. The
72 // returned extension will include background permission if
73 // |background_permission| is true.
74 static scoped_refptr
<Extension
> CreateExtension(
75 const std::string
& name
,
76 bool background_permission
) {
77 base::DictionaryValue manifest
;
78 manifest
.SetString(extensions::manifest_keys::kVersion
, "1.0.0.0");
79 manifest
.SetString(extensions::manifest_keys::kName
, name
);
80 base::ListValue
* permissions
= new base::ListValue();
81 manifest
.Set(extensions::manifest_keys::kPermissions
, permissions
);
82 if (background_permission
) {
83 permissions
->Append(new base::StringValue("background"));
87 scoped_refptr
<Extension
> extension
;
89 extension
= Extension::Create(
90 bogus_file_pathname(name
),
91 extensions::Manifest::INVALID_LOCATION
,
96 // Cannot ASSERT_* here because that attempts an illegitimate return.
97 // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
98 EXPECT_TRUE(extension
.get() != NULL
) << error
;
103 std::string
GenerateUniqueExtensionName() {
104 static int uniqueness
= 0;
105 std::ostringstream output
;
106 output
<< "Unique Named Extension " << uniqueness
;
111 void AddBackgroundPermission(ExtensionService
* service
,
112 Extension
* extension
) {
113 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
,
114 service
->profile())) {
118 scoped_refptr
<Extension
> temporary
=
119 CreateExtension(GenerateUniqueExtensionName(), true);
120 scoped_refptr
<const extensions::PermissionSet
> permissions
=
121 temporary
->permissions_data()->active_permissions();
122 extensions::PermissionsUpdater(service
->profile()).AddPermissions(
123 extension
, permissions
.get());
126 void RemoveBackgroundPermission(ExtensionService
* service
,
127 Extension
* extension
) {
128 if (!BackgroundApplicationListModel::IsBackgroundApp(*extension
,
129 service
->profile())) {
132 extensions::PermissionsUpdater(service
->profile())
133 .RemovePermissionsUnsafe(
134 extension
, extension
->permissions_data()->active_permissions().get());
137 void AddEphemeralApp(const Extension
* extension
, ExtensionService
* service
) {
138 extensions::ExtensionPrefs
* prefs
=
139 extensions::ExtensionPrefs::Get(service
->profile());
141 prefs
->OnExtensionInstalled(extension
,
142 extensions::Extension::ENABLED
,
143 syncer::StringOrdinal(),
144 extensions::kInstallFlagIsEphemeral
,
147 service
->AddExtension(extension
);
152 // Crashes on Mac tryslaves.
153 // http://crbug.com/165458
154 #if defined(OS_MACOSX) || defined(OS_LINUX)
155 #define MAYBE_ExplicitTest DISABLED_ExplicitTest
157 #define MAYBE_ExplicitTest ExplicitTest
159 // With minimal test logic, verifies behavior over an explicit set of
160 // extensions, of which some are Background Apps and others are not.
161 TEST_F(BackgroundApplicationListModelTest
, MAYBE_ExplicitTest
) {
162 InitializeAndLoadEmptyExtensionService();
163 ASSERT_TRUE(service()->is_ready());
164 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
165 scoped_ptr
<BackgroundApplicationListModel
> model(
166 new BackgroundApplicationListModel(profile_
.get()));
167 ASSERT_EQ(0U, model
->size());
169 scoped_refptr
<Extension
> ext1
= CreateExtension("alpha", false);
170 scoped_refptr
<Extension
> ext2
= CreateExtension("bravo", false);
171 scoped_refptr
<Extension
> ext3
= CreateExtension("charlie", false);
172 scoped_refptr
<Extension
> bgapp1
= CreateExtension("delta", true);
173 scoped_refptr
<Extension
> bgapp2
= CreateExtension("echo", true);
174 ASSERT_EQ(0U, registry()->enabled_extensions().size());
175 ASSERT_EQ(0U, model
->size());
177 // Add alternating Extensions and Background Apps
178 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
179 service()->AddExtension(ext1
.get());
180 ASSERT_EQ(1U, registry()->enabled_extensions().size());
181 ASSERT_EQ(0U, model
->size());
182 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
183 service()->AddExtension(bgapp1
.get());
184 ASSERT_EQ(2U, registry()->enabled_extensions().size());
185 ASSERT_EQ(1U, model
->size());
186 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
187 service()->AddExtension(ext2
.get());
188 ASSERT_EQ(3U, registry()->enabled_extensions().size());
189 ASSERT_EQ(1U, model
->size());
190 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
191 service()->AddExtension(bgapp2
.get());
192 ASSERT_EQ(4U, registry()->enabled_extensions().size());
193 ASSERT_EQ(2U, model
->size());
194 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
195 service()->AddExtension(ext3
.get());
196 ASSERT_EQ(5U, registry()->enabled_extensions().size());
197 ASSERT_EQ(2U, model
->size());
199 // Remove in FIFO order.
200 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
201 service()->UninstallExtension(ext1
->id(),
202 extensions::UNINSTALL_REASON_FOR_TESTING
,
203 base::Bind(&base::DoNothing
), NULL
);
204 ASSERT_EQ(4U, registry()->enabled_extensions().size());
205 ASSERT_EQ(2U, model
->size());
206 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
207 service()->UninstallExtension(bgapp1
->id(),
208 extensions::UNINSTALL_REASON_FOR_TESTING
,
209 base::Bind(&base::DoNothing
), NULL
);
210 ASSERT_EQ(3U, registry()->enabled_extensions().size());
211 ASSERT_EQ(1U, model
->size());
212 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
213 service()->UninstallExtension(ext2
->id(),
214 extensions::UNINSTALL_REASON_FOR_TESTING
,
215 base::Bind(&base::DoNothing
), NULL
);
216 ASSERT_EQ(2U, registry()->enabled_extensions().size());
217 ASSERT_EQ(1U, model
->size());
218 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
219 service()->UninstallExtension(bgapp2
->id(),
220 extensions::UNINSTALL_REASON_FOR_TESTING
,
221 base::Bind(&base::DoNothing
), NULL
);
222 ASSERT_EQ(1U, registry()->enabled_extensions().size());
223 ASSERT_EQ(0U, model
->size());
224 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
225 service()->UninstallExtension(ext3
->id(),
226 extensions::UNINSTALL_REASON_FOR_TESTING
,
227 base::Bind(&base::DoNothing
), NULL
);
228 ASSERT_EQ(0U, registry()->enabled_extensions().size());
229 ASSERT_EQ(0U, model
->size());
232 // Verifies that an ephemeral app cannot trigger background mode.
233 TEST_F(BackgroundApplicationListModelTest
, EphemeralAppTest
) {
234 InitializeAndLoadEmptyExtensionService();
235 ASSERT_TRUE(service()->is_ready());
236 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
237 scoped_ptr
<BackgroundApplicationListModel
> model(
238 new BackgroundApplicationListModel(profile_
.get()));
239 ASSERT_EQ(0U, model
->size());
241 scoped_refptr
<Extension
> background
= CreateExtension("background", true);
243 // An ephemeral app with the background permission should not trigger
245 AddEphemeralApp(background
.get(), service());
246 ASSERT_FALSE(IsBackgroundApp(*background
.get()));
247 ASSERT_EQ(1U, registry()->enabled_extensions().size());
248 ASSERT_EQ(0U, model
->size());
250 // If the ephemeral app becomes promoted to an installed app, it can now
251 // trigger background mode.
252 service()->PromoteEphemeralApp(background
.get(), false /*from sync*/);
253 ASSERT_TRUE(IsBackgroundApp(*background
.get()));
254 ASSERT_EQ(1U, registry()->enabled_extensions().size());
255 ASSERT_EQ(1U, model
->size());
258 // With minimal test logic, verifies behavior with dynamic permissions.
259 TEST_F(BackgroundApplicationListModelTest
, AddRemovePermissionsTest
) {
260 InitializeAndLoadEmptyExtensionService();
261 ASSERT_TRUE(service()->is_ready());
262 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
263 scoped_ptr
<BackgroundApplicationListModel
> model(
264 new BackgroundApplicationListModel(profile_
.get()));
265 ASSERT_EQ(0U, model
->size());
267 scoped_refptr
<Extension
> ext
= CreateExtension("extension", false);
269 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
270 scoped_refptr
<Extension
> bgapp
= CreateExtension("application", true);
272 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
273 ASSERT_EQ(0U, registry()->enabled_extensions().size());
274 ASSERT_EQ(0U, model
->size());
276 // Add one (non-background) extension and one background application
277 ASSERT_FALSE(IsBackgroundApp(*ext
.get()));
278 service()->AddExtension(ext
.get());
279 ASSERT_EQ(1U, registry()->enabled_extensions().size());
280 ASSERT_EQ(0U, model
->size());
281 ASSERT_TRUE(IsBackgroundApp(*bgapp
.get()));
282 service()->AddExtension(bgapp
.get());
283 ASSERT_EQ(2U, registry()->enabled_extensions().size());
284 ASSERT_EQ(1U, model
->size());
286 // Change permissions back and forth
287 AddBackgroundPermission(service(), ext
.get());
289 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
290 ASSERT_EQ(2U, registry()->enabled_extensions().size());
291 ASSERT_EQ(2U, model
->size());
292 RemoveBackgroundPermission(service(), bgapp
.get());
294 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
295 ASSERT_EQ(2U, registry()->enabled_extensions().size());
296 ASSERT_EQ(1U, model
->size());
297 RemoveBackgroundPermission(service(), ext
.get());
299 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
300 ASSERT_EQ(2U, registry()->enabled_extensions().size());
301 ASSERT_EQ(0U, model
->size());
302 AddBackgroundPermission(service(), bgapp
.get());
304 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
305 ASSERT_EQ(2U, registry()->enabled_extensions().size());
306 ASSERT_EQ(1U, model
->size());
309 typedef std::set
<scoped_refptr
<Extension
> > ExtensionCollection
;
312 void AddExtension(ExtensionService
* service
,
313 ExtensionCollection
* extensions
,
314 BackgroundApplicationListModel
* model
,
317 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
318 bool create_background
= false;
320 create_background
= true;
323 scoped_refptr
<Extension
> extension
=
324 CreateExtension(GenerateUniqueExtensionName(), create_background
);
325 ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
328 extensions
->insert(extension
);
330 ASSERT_EQ(*count
, extensions
->size());
331 service
->AddExtension(extension
.get());
332 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
333 ASSERT_EQ(*expected
, model
->size());
336 void RemoveExtension(ExtensionService
* service
,
337 ExtensionCollection
* extensions
,
338 BackgroundApplicationListModel
* model
,
340 size_t* count
) { // Maybe remove an extension.
341 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
342 ExtensionCollection::iterator cursor
= extensions
->begin();
343 if (cursor
== extensions
->end()) {
344 // Nothing to remove. Just verify accounting.
345 ASSERT_EQ(0U, *count
);
346 ASSERT_EQ(0U, *expected
);
347 ASSERT_EQ(0U, registry
->enabled_extensions().size());
348 ASSERT_EQ(0U, model
->size());
350 // Randomly select which extension to remove
351 if (extensions
->size() > 1) {
352 int offset
= rand() % (extensions
->size() - 1);
353 for (int index
= 0; index
< offset
; ++index
)
356 scoped_refptr
<Extension
> extension
= cursor
->get();
357 std::string id
= extension
->id();
358 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
359 service
->profile())) {
362 extensions
->erase(cursor
);
364 ASSERT_EQ(*count
, extensions
->size());
365 service
->UninstallExtension(extension
->id(),
366 extensions::UNINSTALL_REASON_FOR_TESTING
,
367 base::Bind(&base::DoNothing
), NULL
);
368 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
369 ASSERT_EQ(*expected
, model
->size());
373 void TogglePermission(ExtensionService
* service
,
374 ExtensionCollection
* extensions
,
375 BackgroundApplicationListModel
* model
,
378 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
379 ExtensionCollection::iterator cursor
= extensions
->begin();
380 if (cursor
== extensions
->end()) {
381 // Nothing to toggle. Just verify accounting.
382 ASSERT_EQ(0U, *count
);
383 ASSERT_EQ(0U, *expected
);
384 ASSERT_EQ(0U, registry
->enabled_extensions().size());
385 ASSERT_EQ(0U, model
->size());
387 // Randomly select which extension to toggle.
388 if (extensions
->size() > 1) {
389 int offset
= rand() % (extensions
->size() - 1);
390 for (int index
= 0; index
< offset
; ++index
)
393 scoped_refptr
<Extension
> extension
= cursor
->get();
394 std::string id
= extension
->id();
395 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
396 service
->profile())) {
398 ASSERT_EQ(*count
, extensions
->size());
399 RemoveBackgroundPermission(service
, extension
.get());
400 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
401 ASSERT_EQ(*expected
, model
->size());
404 ASSERT_EQ(*count
, extensions
->size());
405 AddBackgroundPermission(service
, extension
.get());
406 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
407 ASSERT_EQ(*expected
, model
->size());
413 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
414 // removing extensions, of which some are Background Apps and others are not.
415 TEST_F(BackgroundApplicationListModelTest
, RandomTest
) {
416 InitializeAndLoadEmptyExtensionService();
417 ASSERT_TRUE(service()->is_ready());
418 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
419 scoped_ptr
<BackgroundApplicationListModel
> model(
420 new BackgroundApplicationListModel(profile_
.get()));
421 ASSERT_EQ(0U, model
->size());
423 static const int kIterations
= 20;
424 ExtensionCollection extensions
;
428 for (int index
= 0; index
< kIterations
; ++index
) {
429 switch (rand() % 3) {
431 AddExtension(service(), &extensions
, model
.get(), &expected
, &count
);
434 RemoveExtension(service(), &extensions
, model
.get(), &expected
, &count
);
437 TogglePermission(service(), &extensions
, model
.get(), &expected
,