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()).RemovePermissions(
133 extension
, extension
->permissions_data()->active_permissions().get());
136 void AddEphemeralApp(const Extension
* extension
, ExtensionService
* service
) {
137 extensions::ExtensionPrefs
* prefs
=
138 extensions::ExtensionPrefs::Get(service
->profile());
140 prefs
->OnExtensionInstalled(extension
,
141 extensions::Extension::ENABLED
,
142 syncer::StringOrdinal(),
143 extensions::kInstallFlagIsEphemeral
,
146 service
->AddExtension(extension
);
151 // Crashes on Mac tryslaves.
152 // http://crbug.com/165458
153 #if defined(OS_MACOSX) || defined(OS_LINUX)
154 #define MAYBE_ExplicitTest DISABLED_ExplicitTest
156 #define MAYBE_ExplicitTest ExplicitTest
158 // With minimal test logic, verifies behavior over an explicit set of
159 // extensions, of which some are Background Apps and others are not.
160 TEST_F(BackgroundApplicationListModelTest
, MAYBE_ExplicitTest
) {
161 InitializeAndLoadEmptyExtensionService();
162 ASSERT_TRUE(service()->is_ready());
163 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
164 scoped_ptr
<BackgroundApplicationListModel
> model(
165 new BackgroundApplicationListModel(profile_
.get()));
166 ASSERT_EQ(0U, model
->size());
168 scoped_refptr
<Extension
> ext1
= CreateExtension("alpha", false);
169 scoped_refptr
<Extension
> ext2
= CreateExtension("bravo", false);
170 scoped_refptr
<Extension
> ext3
= CreateExtension("charlie", false);
171 scoped_refptr
<Extension
> bgapp1
= CreateExtension("delta", true);
172 scoped_refptr
<Extension
> bgapp2
= CreateExtension("echo", true);
173 ASSERT_EQ(0U, registry()->enabled_extensions().size());
174 ASSERT_EQ(0U, model
->size());
176 // Add alternating Extensions and Background Apps
177 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
178 service()->AddExtension(ext1
.get());
179 ASSERT_EQ(1U, registry()->enabled_extensions().size());
180 ASSERT_EQ(0U, model
->size());
181 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
182 service()->AddExtension(bgapp1
.get());
183 ASSERT_EQ(2U, registry()->enabled_extensions().size());
184 ASSERT_EQ(1U, model
->size());
185 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
186 service()->AddExtension(ext2
.get());
187 ASSERT_EQ(3U, registry()->enabled_extensions().size());
188 ASSERT_EQ(1U, model
->size());
189 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
190 service()->AddExtension(bgapp2
.get());
191 ASSERT_EQ(4U, registry()->enabled_extensions().size());
192 ASSERT_EQ(2U, model
->size());
193 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
194 service()->AddExtension(ext3
.get());
195 ASSERT_EQ(5U, registry()->enabled_extensions().size());
196 ASSERT_EQ(2U, model
->size());
198 // Remove in FIFO order.
199 ASSERT_FALSE(IsBackgroundApp(*ext1
.get()));
200 service()->UninstallExtension(ext1
->id(),
201 extensions::UNINSTALL_REASON_FOR_TESTING
,
202 base::Bind(&base::DoNothing
), NULL
);
203 ASSERT_EQ(4U, registry()->enabled_extensions().size());
204 ASSERT_EQ(2U, model
->size());
205 ASSERT_TRUE(IsBackgroundApp(*bgapp1
.get()));
206 service()->UninstallExtension(bgapp1
->id(),
207 extensions::UNINSTALL_REASON_FOR_TESTING
,
208 base::Bind(&base::DoNothing
), NULL
);
209 ASSERT_EQ(3U, registry()->enabled_extensions().size());
210 ASSERT_EQ(1U, model
->size());
211 ASSERT_FALSE(IsBackgroundApp(*ext2
.get()));
212 service()->UninstallExtension(ext2
->id(),
213 extensions::UNINSTALL_REASON_FOR_TESTING
,
214 base::Bind(&base::DoNothing
), NULL
);
215 ASSERT_EQ(2U, registry()->enabled_extensions().size());
216 ASSERT_EQ(1U, model
->size());
217 ASSERT_TRUE(IsBackgroundApp(*bgapp2
.get()));
218 service()->UninstallExtension(bgapp2
->id(),
219 extensions::UNINSTALL_REASON_FOR_TESTING
,
220 base::Bind(&base::DoNothing
), NULL
);
221 ASSERT_EQ(1U, registry()->enabled_extensions().size());
222 ASSERT_EQ(0U, model
->size());
223 ASSERT_FALSE(IsBackgroundApp(*ext3
.get()));
224 service()->UninstallExtension(ext3
->id(),
225 extensions::UNINSTALL_REASON_FOR_TESTING
,
226 base::Bind(&base::DoNothing
), NULL
);
227 ASSERT_EQ(0U, registry()->enabled_extensions().size());
228 ASSERT_EQ(0U, model
->size());
231 // Verifies that an ephemeral app cannot trigger background mode.
232 TEST_F(BackgroundApplicationListModelTest
, EphemeralAppTest
) {
233 InitializeAndLoadEmptyExtensionService();
234 ASSERT_TRUE(service()->is_ready());
235 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
236 scoped_ptr
<BackgroundApplicationListModel
> model(
237 new BackgroundApplicationListModel(profile_
.get()));
238 ASSERT_EQ(0U, model
->size());
240 scoped_refptr
<Extension
> background
= CreateExtension("background", true);
242 // An ephemeral app with the background permission should not trigger
244 AddEphemeralApp(background
.get(), service());
245 ASSERT_FALSE(IsBackgroundApp(*background
.get()));
246 ASSERT_EQ(1U, registry()->enabled_extensions().size());
247 ASSERT_EQ(0U, model
->size());
249 // If the ephemeral app becomes promoted to an installed app, it can now
250 // trigger background mode.
251 service()->PromoteEphemeralApp(background
.get(), false /*from sync*/);
252 ASSERT_TRUE(IsBackgroundApp(*background
.get()));
253 ASSERT_EQ(1U, registry()->enabled_extensions().size());
254 ASSERT_EQ(1U, model
->size());
257 // With minimal test logic, verifies behavior with dynamic permissions.
258 TEST_F(BackgroundApplicationListModelTest
, AddRemovePermissionsTest
) {
259 InitializeAndLoadEmptyExtensionService();
260 ASSERT_TRUE(service()->is_ready());
261 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
262 scoped_ptr
<BackgroundApplicationListModel
> model(
263 new BackgroundApplicationListModel(profile_
.get()));
264 ASSERT_EQ(0U, model
->size());
266 scoped_refptr
<Extension
> ext
= CreateExtension("extension", false);
268 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
269 scoped_refptr
<Extension
> bgapp
= CreateExtension("application", true);
271 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
272 ASSERT_EQ(0U, registry()->enabled_extensions().size());
273 ASSERT_EQ(0U, model
->size());
275 // Add one (non-background) extension and one background application
276 ASSERT_FALSE(IsBackgroundApp(*ext
.get()));
277 service()->AddExtension(ext
.get());
278 ASSERT_EQ(1U, registry()->enabled_extensions().size());
279 ASSERT_EQ(0U, model
->size());
280 ASSERT_TRUE(IsBackgroundApp(*bgapp
.get()));
281 service()->AddExtension(bgapp
.get());
282 ASSERT_EQ(2U, registry()->enabled_extensions().size());
283 ASSERT_EQ(1U, model
->size());
285 // Change permissions back and forth
286 AddBackgroundPermission(service(), ext
.get());
288 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
289 ASSERT_EQ(2U, registry()->enabled_extensions().size());
290 ASSERT_EQ(2U, model
->size());
291 RemoveBackgroundPermission(service(), bgapp
.get());
293 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
294 ASSERT_EQ(2U, registry()->enabled_extensions().size());
295 ASSERT_EQ(1U, model
->size());
296 RemoveBackgroundPermission(service(), ext
.get());
298 ext
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
299 ASSERT_EQ(2U, registry()->enabled_extensions().size());
300 ASSERT_EQ(0U, model
->size());
301 AddBackgroundPermission(service(), bgapp
.get());
303 bgapp
->permissions_data()->HasAPIPermission(APIPermission::kBackground
));
304 ASSERT_EQ(2U, registry()->enabled_extensions().size());
305 ASSERT_EQ(1U, model
->size());
308 typedef std::set
<scoped_refptr
<Extension
> > ExtensionCollection
;
311 void AddExtension(ExtensionService
* service
,
312 ExtensionCollection
* extensions
,
313 BackgroundApplicationListModel
* model
,
316 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
317 bool create_background
= false;
319 create_background
= true;
322 scoped_refptr
<Extension
> extension
=
323 CreateExtension(GenerateUniqueExtensionName(), create_background
);
324 ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
327 extensions
->insert(extension
);
329 ASSERT_EQ(*count
, extensions
->size());
330 service
->AddExtension(extension
.get());
331 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
332 ASSERT_EQ(*expected
, model
->size());
335 void RemoveExtension(ExtensionService
* service
,
336 ExtensionCollection
* extensions
,
337 BackgroundApplicationListModel
* model
,
339 size_t* count
) { // Maybe remove an extension.
340 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
341 ExtensionCollection::iterator cursor
= extensions
->begin();
342 if (cursor
== extensions
->end()) {
343 // Nothing to remove. Just verify accounting.
344 ASSERT_EQ(0U, *count
);
345 ASSERT_EQ(0U, *expected
);
346 ASSERT_EQ(0U, registry
->enabled_extensions().size());
347 ASSERT_EQ(0U, model
->size());
349 // Randomly select which extension to remove
350 if (extensions
->size() > 1) {
351 int offset
= rand() % (extensions
->size() - 1);
352 for (int index
= 0; index
< offset
; ++index
)
355 scoped_refptr
<Extension
> extension
= cursor
->get();
356 std::string id
= extension
->id();
357 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
358 service
->profile())) {
361 extensions
->erase(cursor
);
363 ASSERT_EQ(*count
, extensions
->size());
364 service
->UninstallExtension(extension
->id(),
365 extensions::UNINSTALL_REASON_FOR_TESTING
,
366 base::Bind(&base::DoNothing
), NULL
);
367 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
368 ASSERT_EQ(*expected
, model
->size());
372 void TogglePermission(ExtensionService
* service
,
373 ExtensionCollection
* extensions
,
374 BackgroundApplicationListModel
* model
,
377 ExtensionRegistry
* registry
= ExtensionRegistry::Get(service
->profile());
378 ExtensionCollection::iterator cursor
= extensions
->begin();
379 if (cursor
== extensions
->end()) {
380 // Nothing to toggle. Just verify accounting.
381 ASSERT_EQ(0U, *count
);
382 ASSERT_EQ(0U, *expected
);
383 ASSERT_EQ(0U, registry
->enabled_extensions().size());
384 ASSERT_EQ(0U, model
->size());
386 // Randomly select which extension to toggle.
387 if (extensions
->size() > 1) {
388 int offset
= rand() % (extensions
->size() - 1);
389 for (int index
= 0; index
< offset
; ++index
)
392 scoped_refptr
<Extension
> extension
= cursor
->get();
393 std::string id
= extension
->id();
394 if (BackgroundApplicationListModel::IsBackgroundApp(*extension
.get(),
395 service
->profile())) {
397 ASSERT_EQ(*count
, extensions
->size());
398 RemoveBackgroundPermission(service
, extension
.get());
399 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
400 ASSERT_EQ(*expected
, model
->size());
403 ASSERT_EQ(*count
, extensions
->size());
404 AddBackgroundPermission(service
, extension
.get());
405 ASSERT_EQ(*count
, registry
->enabled_extensions().size());
406 ASSERT_EQ(*expected
, model
->size());
412 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
413 // removing extensions, of which some are Background Apps and others are not.
414 TEST_F(BackgroundApplicationListModelTest
, RandomTest
) {
415 InitializeAndLoadEmptyExtensionService();
416 ASSERT_TRUE(service()->is_ready());
417 ASSERT_TRUE(registry()->enabled_extensions().is_empty());
418 scoped_ptr
<BackgroundApplicationListModel
> model(
419 new BackgroundApplicationListModel(profile_
.get()));
420 ASSERT_EQ(0U, model
->size());
422 static const int kIterations
= 20;
423 ExtensionCollection extensions
;
427 for (int index
= 0; index
< kIterations
; ++index
) {
428 switch (rand() % 3) {
430 AddExtension(service(), &extensions
, model
.get(), &expected
, &count
);
433 RemoveExtension(service(), &extensions
, model
.get(), &expected
, &count
);
436 TogglePermission(service(), &extensions
, model
.get(), &expected
,