blob: 3bd4e75453f8c81da8fe921ca397d9c0c27d2155 [file] [log] [blame]
treib9afc6212015-10-30 18:49:581// Copyright 2015 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#include <string>
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/files/file_util.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/memory/weak_ptr.h"
12#include "base/metrics/field_trial.h"
13#include "base/test/mock_entropy_provider.h"
14#include "chrome/browser/extensions/component_loader.h"
15#include "chrome/browser/extensions/extension_service.h"
16#include "chrome/browser/extensions/extension_service_test_with_install.h"
17#include "chrome/browser/extensions/extension_sync_data.h"
18#include "chrome/browser/extensions/extension_sync_service.h"
19#include "chrome/browser/extensions/extension_util.h"
20#include "chrome/browser/extensions/updater/extension_updater.h"
treib9afc6212015-10-30 18:49:5821#include "chrome/browser/sync/profile_sync_service_factory.h"
22#include "chrome/common/chrome_constants.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/common/extensions/sync_helper.h"
25#include "chrome/test/base/testing_profile.h"
blundell7282b512015-11-09 07:21:1126#include "components/browser_sync/browser/profile_sync_service.h"
rdevlin.cronin738501d2015-11-05 21:51:3627#include "components/crx_file/id_util.h"
treib9afc6212015-10-30 18:49:5828#include "extensions/browser/app_sorting.h"
29#include "extensions/browser/extension_prefs.h"
30#include "extensions/browser/extension_registry.h"
31#include "extensions/browser/extension_system.h"
32#include "extensions/browser/management_policy.h"
33#include "extensions/browser/test_management_policy.h"
34#include "extensions/common/constants.h"
rdevlin.cronin738501d2015-11-05 21:51:3635#include "extensions/common/extension_builder.h"
treib9afc6212015-10-30 18:49:5836#include "extensions/common/manifest_url_handlers.h"
37#include "extensions/common/permissions/permission_set.h"
rdevlin.cronin738501d2015-11-05 21:51:3638#include "extensions/common/value_builder.h"
treib9afc6212015-10-30 18:49:5839#include "sync/api/fake_sync_change_processor.h"
40#include "sync/api/sync_data.h"
41#include "sync/api/sync_error_factory_mock.h"
42#include "testing/gtest/include/gtest/gtest.h"
43
44#if defined(ENABLE_SUPERVISED_USERS)
45#include "chrome/browser/supervised_user/permission_request_creator.h"
46#include "chrome/browser/supervised_user/supervised_user_constants.h"
47#include "chrome/browser/supervised_user/supervised_user_service.h"
48#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
49#endif
50
51using extensions::AppSorting;
52using extensions::Extension;
53using extensions::ExtensionPrefs;
54using extensions::ExtensionSyncData;
55using extensions::ExtensionSystem;
56using extensions::Manifest;
57using extensions::PermissionSet;
58
59const char good0[] = "behllobkkfkfnphdnhnkndlbkcpglgmj";
60const char good2[] = "bjafgdebaacbbbecmhlhpofkepfkgcpa";
61const char good_crx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
62const char page_action[] = "obcimlgaoabeegjmmpldobjndiealpln";
63const char theme2_crx[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
64
65class ExtensionServiceSyncTest
66 : public extensions::ExtensionServiceTestWithInstall {
67 public:
68 void MockSyncStartFlare(bool* was_called,
69 syncer::ModelType* model_type_passed_in,
70 syncer::ModelType model_type) {
71 *was_called = true;
72 *model_type_passed_in = model_type;
73 }
74
75 protected:
76 // Paths to some of the fake extensions.
77 base::FilePath good0_path() {
78 return data_dir()
79 .AppendASCII("good")
80 .AppendASCII("Extensions")
81 .AppendASCII(good0)
82 .AppendASCII("1.0.0.0");
83 }
84
85 ExtensionSyncService* extension_sync_service() {
86 return ExtensionSyncService::Get(profile());
87 }
88};
89
90TEST_F(ExtensionServiceSyncTest, DeferredSyncStartupPreInstalledComponent) {
91 InitializeEmptyExtensionService();
92
93 bool flare_was_called = false;
94 syncer::ModelType triggered_type(syncer::UNSPECIFIED);
95 base::WeakPtrFactory<ExtensionServiceSyncTest> factory(this);
96 extension_sync_service()->SetSyncStartFlareForTesting(
97 base::Bind(&ExtensionServiceSyncTest::MockSyncStartFlare,
98 factory.GetWeakPtr(),
99 &flare_was_called, // Safe due to WeakPtrFactory scope.
100 &triggered_type)); // Safe due to WeakPtrFactory scope.
101
102 // Install a component extension.
103 std::string manifest;
104 ASSERT_TRUE(base::ReadFileToString(
105 good0_path().Append(extensions::kManifestFilename), &manifest));
106 service()->component_loader()->Add(manifest, good0_path());
107 ASSERT_FALSE(service()->is_ready());
108 service()->Init();
109 ASSERT_TRUE(service()->is_ready());
110
111 // Extensions added before service is_ready() don't trigger sync startup.
112 EXPECT_FALSE(flare_was_called);
113 ASSERT_EQ(syncer::UNSPECIFIED, triggered_type);
114}
115
116TEST_F(ExtensionServiceSyncTest, DeferredSyncStartupPreInstalledNormal) {
117 InitializeGoodInstalledExtensionService();
118
119 bool flare_was_called = false;
120 syncer::ModelType triggered_type(syncer::UNSPECIFIED);
121 base::WeakPtrFactory<ExtensionServiceSyncTest> factory(this);
122 extension_sync_service()->SetSyncStartFlareForTesting(
123 base::Bind(&ExtensionServiceSyncTest::MockSyncStartFlare,
124 factory.GetWeakPtr(),
125 &flare_was_called, // Safe due to WeakPtrFactory scope.
126 &triggered_type)); // Safe due to WeakPtrFactory scope.
127
128 ASSERT_FALSE(service()->is_ready());
129 service()->Init();
130 ASSERT_EQ(3u, loaded_.size());
131 ASSERT_TRUE(service()->is_ready());
132
133 // Extensions added before service is_ready() don't trigger sync startup.
134 EXPECT_FALSE(flare_was_called);
135 ASSERT_EQ(syncer::UNSPECIFIED, triggered_type);
136}
137
138TEST_F(ExtensionServiceSyncTest, DeferredSyncStartupOnInstall) {
139 InitializeEmptyExtensionService();
140 service()->Init();
141 ASSERT_TRUE(service()->is_ready());
142
143 bool flare_was_called = false;
144 syncer::ModelType triggered_type(syncer::UNSPECIFIED);
145 base::WeakPtrFactory<ExtensionServiceSyncTest> factory(this);
146 extension_sync_service()->SetSyncStartFlareForTesting(
147 base::Bind(&ExtensionServiceSyncTest::MockSyncStartFlare,
148 factory.GetWeakPtr(),
149 &flare_was_called, // Safe due to WeakPtrFactory scope.
150 &triggered_type)); // Safe due to WeakPtrFactory scope.
151
152 base::FilePath path = data_dir().AppendASCII("good.crx");
153 InstallCRX(path, INSTALL_NEW);
154
155 EXPECT_TRUE(flare_was_called);
156 EXPECT_EQ(syncer::EXTENSIONS, triggered_type);
157
158 // Reset.
159 flare_was_called = false;
160 triggered_type = syncer::UNSPECIFIED;
161
162 // Once sync starts, flare should no longer be invoked.
163 extension_sync_service()->MergeDataAndStartSyncing(
164 syncer::EXTENSIONS,
165 syncer::SyncDataList(),
166 scoped_ptr<syncer::SyncChangeProcessor>(
167 new syncer::FakeSyncChangeProcessor),
168 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
169 path = data_dir().AppendASCII("page_action.crx");
170 InstallCRX(path, INSTALL_NEW);
171 EXPECT_FALSE(flare_was_called);
172 ASSERT_EQ(syncer::UNSPECIFIED, triggered_type);
173}
174
175TEST_F(ExtensionServiceSyncTest, DisableExtensionFromSync) {
176 // Start the extensions service with one external extension already installed.
177 base::FilePath source_install_dir =
178 data_dir().AppendASCII("good").AppendASCII("Extensions");
179 base::FilePath pref_path =
180 source_install_dir.DirName().Append(chrome::kPreferencesFilename);
181
182 InitializeInstalledExtensionService(pref_path, source_install_dir);
183
184 // The user has enabled sync.
185 ProfileSyncService* sync_service =
186 ProfileSyncServiceFactory::GetForProfile(profile());
187 sync_service->SetSyncSetupCompleted();
188
189 service()->Init();
190 ASSERT_TRUE(service()->is_ready());
191
192 ASSERT_EQ(3u, loaded_.size());
193
194 // We start enabled.
195 const Extension* extension = service()->GetExtensionById(good0, true);
196 ASSERT_TRUE(extension);
197 ASSERT_TRUE(service()->IsExtensionEnabled(good0));
198
199 // Sync starts up.
200 extension_sync_service()->MergeDataAndStartSyncing(
201 syncer::EXTENSIONS,
202 syncer::SyncDataList(),
203 make_scoped_ptr(new syncer::FakeSyncChangeProcessor),
204 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
205
206 // Then sync data arrives telling us to disable |good0|.
207 ExtensionSyncData disable_good_crx(*extension, false,
208 Extension::DISABLE_USER_ACTION, false,
209 false, ExtensionSyncData::BOOLEAN_UNSET);
210 syncer::SyncChange sync_change(FROM_HERE,
211 syncer::SyncChange::ACTION_UPDATE,
212 disable_good_crx.GetSyncData());
213 syncer::SyncChangeList list(1, sync_change);
214 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
215
216 ASSERT_FALSE(service()->IsExtensionEnabled(good0));
217}
218
219TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) {
220 // Start the extension service with three extensions already installed.
221 base::FilePath source_install_dir =
222 data_dir().AppendASCII("good").AppendASCII("Extensions");
223 base::FilePath pref_path =
224 source_install_dir.DirName().Append(chrome::kPreferencesFilename);
225
226 InitializeInstalledExtensionService(pref_path, source_install_dir);
227
228 // The user has enabled sync.
229 ProfileSyncService* sync_service =
230 ProfileSyncServiceFactory::GetForProfile(profile());
231 sync_service->SetSyncSetupCompleted();
232 // Make sure ExtensionSyncService is created, so it'll be notified of changes.
233 extension_sync_service();
234
235 service()->Init();
236 ASSERT_TRUE(service()->is_ready());
237 ASSERT_EQ(3u, loaded_.size());
238
239 ASSERT_TRUE(service()->IsExtensionEnabled(good0));
240 ASSERT_TRUE(service()->IsExtensionEnabled(good2));
241
242 // Disable and re-enable good0 before first sync data arrives.
243 service()->DisableExtension(good0, Extension::DISABLE_USER_ACTION);
244 ASSERT_FALSE(service()->IsExtensionEnabled(good0));
245 service()->EnableExtension(good0);
246 ASSERT_TRUE(service()->IsExtensionEnabled(good0));
247 // Disable good2 before first sync data arrives (good1 is considered
248 // non-syncable because it has plugin permission).
249 service()->DisableExtension(good2, Extension::DISABLE_USER_ACTION);
250 ASSERT_FALSE(service()->IsExtensionEnabled(good2));
251
252 const Extension* extension0 = service()->GetExtensionById(good0, true);
253 const Extension* extension2 = service()->GetExtensionById(good2, true);
254 ASSERT_TRUE(extensions::sync_helper::IsSyncable(extension0));
255 ASSERT_TRUE(extensions::sync_helper::IsSyncable(extension2));
256
257 // Now sync data comes in that says to disable good0 and enable good2.
258 ExtensionSyncData disable_good0(*extension0, false,
259 Extension::DISABLE_USER_ACTION, false, false,
260 ExtensionSyncData::BOOLEAN_UNSET);
261 ExtensionSyncData enable_good2(*extension2, true, Extension::DISABLE_NONE,
262 false, false,
263 ExtensionSyncData::BOOLEAN_UNSET);
264 syncer::SyncDataList sync_data;
265 sync_data.push_back(disable_good0.GetSyncData());
266 sync_data.push_back(enable_good2.GetSyncData());
267 extension_sync_service()->MergeDataAndStartSyncing(
268 syncer::EXTENSIONS,
269 sync_data,
270 make_scoped_ptr(new syncer::FakeSyncChangeProcessor),
271 make_scoped_ptr(new syncer::SyncErrorFactoryMock));
272
273 // Both sync changes should be ignored, since the local state was changed
274 // before sync started, and so the local state is considered more recent.
275 EXPECT_TRUE(service()->IsExtensionEnabled(good0));
276 EXPECT_FALSE(service()->IsExtensionEnabled(good2));
277}
278
279TEST_F(ExtensionServiceSyncTest, GetSyncData) {
280 InitializeEmptyExtensionService();
281 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
282 const Extension* extension = service()->GetInstalledExtension(good_crx);
283 ASSERT_TRUE(extension);
284
285 extension_sync_service()->MergeDataAndStartSyncing(
286 syncer::EXTENSIONS,
287 syncer::SyncDataList(),
288 scoped_ptr<syncer::SyncChangeProcessor>(
289 new syncer::FakeSyncChangeProcessor),
290 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
291
292 syncer::SyncDataList list =
293 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
294 ASSERT_EQ(list.size(), 1U);
295 scoped_ptr<ExtensionSyncData> data =
296 ExtensionSyncData::CreateFromSyncData(list[0]);
297 ASSERT_TRUE(data.get());
298 EXPECT_EQ(extension->id(), data->id());
299 EXPECT_FALSE(data->uninstalled());
300 EXPECT_EQ(service()->IsExtensionEnabled(good_crx), data->enabled());
301 EXPECT_EQ(extensions::util::IsIncognitoEnabled(good_crx, profile()),
302 data->incognito_enabled());
303 EXPECT_EQ(ExtensionSyncData::BOOLEAN_UNSET, data->all_urls_enabled());
304 EXPECT_TRUE(data->version().Equals(*extension->version()));
305 EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
306 data->update_url());
307 EXPECT_EQ(extension->name(), data->name());
308}
309
treib29e1b9b12015-11-11 08:50:56310TEST_F(ExtensionServiceSyncTest, GetSyncDataDisableReasons) {
311 InitializeEmptyExtensionService();
312 const Extension* extension =
313 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
314 ASSERT_TRUE(extension);
315
316 syncer::FakeSyncChangeProcessor processor;
317 extension_sync_service()->MergeDataAndStartSyncing(
318 syncer::EXTENSIONS,
319 syncer::SyncDataList(),
320 scoped_ptr<syncer::SyncChangeProcessor>(
321 new syncer::FakeSyncChangeProcessor),
322 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
323
324 {
325 syncer::SyncDataList list =
326 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
327 ASSERT_EQ(list.size(), 1U);
328 scoped_ptr<ExtensionSyncData> data =
329 ExtensionSyncData::CreateFromSyncData(list[0]);
330 ASSERT_TRUE(data.get());
331 EXPECT_TRUE(data->enabled());
332 EXPECT_TRUE(data->supports_disable_reasons());
333 EXPECT_EQ(Extension::DISABLE_NONE, data->disable_reasons());
334 }
335
336 // Syncable disable reason, should propagate to sync.
337 service()->DisableExtension(good_crx, Extension::DISABLE_USER_ACTION);
338 {
339 syncer::SyncDataList list =
340 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
341 ASSERT_EQ(list.size(), 1U);
342 scoped_ptr<ExtensionSyncData> data =
343 ExtensionSyncData::CreateFromSyncData(list[0]);
344 ASSERT_TRUE(data.get());
345 EXPECT_FALSE(data->enabled());
346 EXPECT_TRUE(data->supports_disable_reasons());
347 EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons());
348 }
349 service()->EnableExtension(good_crx);
350
351 // Non-syncable disable reason. The sync data should still say "enabled".
352 service()->DisableExtension(good_crx, Extension::DISABLE_RELOAD);
353 {
354 syncer::SyncDataList list =
355 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
356 ASSERT_EQ(list.size(), 1U);
357 scoped_ptr<ExtensionSyncData> data =
358 ExtensionSyncData::CreateFromSyncData(list[0]);
359 ASSERT_TRUE(data.get());
360 EXPECT_TRUE(data->enabled());
361 EXPECT_TRUE(data->supports_disable_reasons());
362 EXPECT_EQ(Extension::DISABLE_NONE, data->disable_reasons());
363 }
364 service()->EnableExtension(good_crx);
365
366 // Both a syncable and a non-syncable disable reason, only the former should
367 // propagate to sync.
368 service()->DisableExtension(
369 good_crx, Extension::DISABLE_USER_ACTION | Extension::DISABLE_RELOAD);
370 {
371 syncer::SyncDataList list =
372 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
373 ASSERT_EQ(list.size(), 1U);
374 scoped_ptr<ExtensionSyncData> data =
375 ExtensionSyncData::CreateFromSyncData(list[0]);
376 ASSERT_TRUE(data.get());
377 EXPECT_FALSE(data->enabled());
378 EXPECT_TRUE(data->supports_disable_reasons());
379 EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons());
380 }
381 service()->EnableExtension(good_crx);
382}
383
treib9afc6212015-10-30 18:49:58384TEST_F(ExtensionServiceSyncTest, GetSyncDataTerminated) {
385 InitializeEmptyExtensionService();
386 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
387 TerminateExtension(good_crx);
388 const Extension* extension = service()->GetInstalledExtension(good_crx);
389 ASSERT_TRUE(extension);
390
391 syncer::FakeSyncChangeProcessor processor;
392 extension_sync_service()->MergeDataAndStartSyncing(
393 syncer::EXTENSIONS,
394 syncer::SyncDataList(),
395 scoped_ptr<syncer::SyncChangeProcessor>(
396 new syncer::FakeSyncChangeProcessor),
397 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
398
399 syncer::SyncDataList list =
400 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
401 ASSERT_EQ(list.size(), 1U);
402 scoped_ptr<ExtensionSyncData> data =
403 ExtensionSyncData::CreateFromSyncData(list[0]);
404 ASSERT_TRUE(data.get());
405 EXPECT_EQ(extension->id(), data->id());
406 EXPECT_FALSE(data->uninstalled());
407 EXPECT_EQ(service()->IsExtensionEnabled(good_crx), data->enabled());
408 EXPECT_EQ(extensions::util::IsIncognitoEnabled(good_crx, profile()),
409 data->incognito_enabled());
410 EXPECT_EQ(ExtensionSyncData::BOOLEAN_UNSET, data->all_urls_enabled());
411 EXPECT_TRUE(data->version().Equals(*extension->version()));
412 EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
413 data->update_url());
414 EXPECT_EQ(extension->name(), data->name());
415}
416
417TEST_F(ExtensionServiceSyncTest, GetSyncDataFilter) {
418 InitializeEmptyExtensionService();
419 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
420 const Extension* extension = service()->GetInstalledExtension(good_crx);
421 ASSERT_TRUE(extension);
422
423 syncer::FakeSyncChangeProcessor processor;
424 extension_sync_service()->MergeDataAndStartSyncing(
425 syncer::APPS,
426 syncer::SyncDataList(),
427 scoped_ptr<syncer::SyncChangeProcessor>(
428 new syncer::FakeSyncChangeProcessor),
429 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
430
431 syncer::SyncDataList list =
432 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
433 ASSERT_EQ(list.size(), 0U);
434}
435
436TEST_F(ExtensionServiceSyncTest, GetSyncExtensionDataUserSettings) {
437 InitializeEmptyExtensionService();
438 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
439 const Extension* extension = service()->GetInstalledExtension(good_crx);
440 ASSERT_TRUE(extension);
441
442 syncer::FakeSyncChangeProcessor processor;
443 extension_sync_service()->MergeDataAndStartSyncing(
444 syncer::EXTENSIONS,
445 syncer::SyncDataList(),
446 scoped_ptr<syncer::SyncChangeProcessor>(
447 new syncer::FakeSyncChangeProcessor),
448 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
449
450 {
451 syncer::SyncDataList list =
452 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
453 ASSERT_EQ(list.size(), 1U);
454 scoped_ptr<ExtensionSyncData> data =
455 ExtensionSyncData::CreateFromSyncData(list[0]);
456 ASSERT_TRUE(data.get());
457 EXPECT_TRUE(data->enabled());
458 EXPECT_FALSE(data->incognito_enabled());
459 EXPECT_EQ(ExtensionSyncData::BOOLEAN_UNSET, data->all_urls_enabled());
460 }
461
462 service()->DisableExtension(good_crx, Extension::DISABLE_USER_ACTION);
463 {
464 syncer::SyncDataList list =
465 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
466 ASSERT_EQ(list.size(), 1U);
467 scoped_ptr<ExtensionSyncData> data =
468 ExtensionSyncData::CreateFromSyncData(list[0]);
469 ASSERT_TRUE(data.get());
470 EXPECT_FALSE(data->enabled());
471 EXPECT_FALSE(data->incognito_enabled());
472 EXPECT_EQ(ExtensionSyncData::BOOLEAN_UNSET, data->all_urls_enabled());
473 }
474
475 extensions::util::SetIsIncognitoEnabled(good_crx, profile(), true);
476 extensions::util::SetAllowedScriptingOnAllUrls(
477 good_crx, profile(), false);
478 {
479 syncer::SyncDataList list =
480 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
481 ASSERT_EQ(list.size(), 1U);
482 scoped_ptr<ExtensionSyncData> data =
483 ExtensionSyncData::CreateFromSyncData(list[0]);
484 ASSERT_TRUE(data.get());
485 EXPECT_FALSE(data->enabled());
486 EXPECT_TRUE(data->incognito_enabled());
487 EXPECT_EQ(ExtensionSyncData::BOOLEAN_FALSE, data->all_urls_enabled());
488 }
489
490 service()->EnableExtension(good_crx);
491 extensions::util::SetAllowedScriptingOnAllUrls(
492 good_crx, profile(), true);
493 {
494 syncer::SyncDataList list =
495 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
496 ASSERT_EQ(list.size(), 1U);
497 scoped_ptr<ExtensionSyncData> data =
498 ExtensionSyncData::CreateFromSyncData(list[0]);
499 ASSERT_TRUE(data.get());
500 EXPECT_TRUE(data->enabled());
501 EXPECT_TRUE(data->incognito_enabled());
502 EXPECT_EQ(ExtensionSyncData::BOOLEAN_TRUE, data->all_urls_enabled());
503 }
504}
505
506TEST_F(ExtensionServiceSyncTest, SyncForUninstalledExternalExtension) {
507 InitializeEmptyExtensionService();
508 InstallCRXWithLocation(
509 data_dir().AppendASCII("good.crx"), Manifest::EXTERNAL_PREF, INSTALL_NEW);
510 const Extension* extension = service()->GetInstalledExtension(good_crx);
511 ASSERT_TRUE(extension);
512
513 syncer::FakeSyncChangeProcessor processor;
514 extension_sync_service()->MergeDataAndStartSyncing(
515 syncer::EXTENSIONS,
516 syncer::SyncDataList(),
517 scoped_ptr<syncer::SyncChangeProcessor>(
518 new syncer::FakeSyncChangeProcessor),
519 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
520
521 UninstallExtension(good_crx, false);
522 EXPECT_TRUE(
523 ExtensionPrefs::Get(profile())->IsExternalExtensionUninstalled(good_crx));
524
525 sync_pb::EntitySpecifics specifics;
526 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app();
527 sync_pb::ExtensionSpecifics* extension_specifics =
528 app_specifics->mutable_extension();
529 extension_specifics->set_id(good_crx);
530 extension_specifics->set_version("1.0");
531 extension_specifics->set_enabled(true);
532
533 syncer::SyncData sync_data =
534 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
535 syncer::SyncChange sync_change(FROM_HERE,
536 syncer::SyncChange::ACTION_UPDATE,
537 sync_data);
538 syncer::SyncChangeList list(1);
539 list[0] = sync_change;
540
541 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
542 EXPECT_TRUE(
543 ExtensionPrefs::Get(profile())->IsExternalExtensionUninstalled(good_crx));
544}
545
546TEST_F(ExtensionServiceSyncTest, GetSyncAppDataUserSettings) {
547 InitializeEmptyExtensionService();
548 const Extension* app =
549 PackAndInstallCRX(data_dir().AppendASCII("app"), INSTALL_NEW);
550 ASSERT_TRUE(app);
551 ASSERT_TRUE(app->is_app());
552
553 syncer::FakeSyncChangeProcessor processor;
554 extension_sync_service()->MergeDataAndStartSyncing(
555 syncer::APPS,
556 syncer::SyncDataList(),
557 scoped_ptr<syncer::SyncChangeProcessor>(
558 new syncer::FakeSyncChangeProcessor),
559 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
560
561 syncer::StringOrdinal initial_ordinal =
562 syncer::StringOrdinal::CreateInitialOrdinal();
563 {
564 syncer::SyncDataList list =
565 extension_sync_service()->GetAllSyncData(syncer::APPS);
566 ASSERT_EQ(list.size(), 1U);
567
568 scoped_ptr<ExtensionSyncData> app_sync_data =
569 ExtensionSyncData::CreateFromSyncData(list[0]);
570 EXPECT_TRUE(initial_ordinal.Equals(app_sync_data->app_launch_ordinal()));
571 EXPECT_TRUE(initial_ordinal.Equals(app_sync_data->page_ordinal()));
572 }
573
deepak.m14ba69e62015-11-17 05:42:12574 AppSorting* sorting = ExtensionSystem::Get(profile())->app_sorting();
treib9afc6212015-10-30 18:49:58575 sorting->SetAppLaunchOrdinal(app->id(), initial_ordinal.CreateAfter());
576 {
577 syncer::SyncDataList list =
578 extension_sync_service()->GetAllSyncData(syncer::APPS);
579 ASSERT_EQ(list.size(), 1U);
580
581 scoped_ptr<ExtensionSyncData> app_sync_data =
582 ExtensionSyncData::CreateFromSyncData(list[0]);
583 ASSERT_TRUE(app_sync_data.get());
584 EXPECT_TRUE(initial_ordinal.LessThan(app_sync_data->app_launch_ordinal()));
585 EXPECT_TRUE(initial_ordinal.Equals(app_sync_data->page_ordinal()));
586 }
587
588 sorting->SetPageOrdinal(app->id(), initial_ordinal.CreateAfter());
589 {
590 syncer::SyncDataList list =
591 extension_sync_service()->GetAllSyncData(syncer::APPS);
592 ASSERT_EQ(list.size(), 1U);
593
594 scoped_ptr<ExtensionSyncData> app_sync_data =
595 ExtensionSyncData::CreateFromSyncData(list[0]);
596 ASSERT_TRUE(app_sync_data.get());
597 EXPECT_TRUE(initial_ordinal.LessThan(app_sync_data->app_launch_ordinal()));
598 EXPECT_TRUE(initial_ordinal.LessThan(app_sync_data->page_ordinal()));
599 }
600}
601
602// TODO (rdevlin.cronin): The OnExtensionMoved() method has been removed from
603// ExtensionService, so this test probably needs a new home. Unfortunately, it
604// relies pretty heavily on things like InitializeExtension[Sync]Service() and
605// PackAndInstallCRX(). When we clean up a bit more, this should move out.
606TEST_F(ExtensionServiceSyncTest, GetSyncAppDataUserSettingsOnExtensionMoved) {
607 InitializeEmptyExtensionService();
608 const size_t kAppCount = 3;
609 const Extension* apps[kAppCount];
610 apps[0] = PackAndInstallCRX(data_dir().AppendASCII("app1"), INSTALL_NEW);
611 apps[1] = PackAndInstallCRX(data_dir().AppendASCII("app2"), INSTALL_NEW);
612 apps[2] = PackAndInstallCRX(data_dir().AppendASCII("app4"), INSTALL_NEW);
613 for (size_t i = 0; i < kAppCount; ++i) {
614 ASSERT_TRUE(apps[i]);
615 ASSERT_TRUE(apps[i]->is_app());
616 }
617
618 syncer::FakeSyncChangeProcessor processor;
619 extension_sync_service()->MergeDataAndStartSyncing(
620 syncer::APPS,
621 syncer::SyncDataList(),
622 scoped_ptr<syncer::SyncChangeProcessor>(
623 new syncer::FakeSyncChangeProcessor),
624 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
625
deepak.m14ba69e62015-11-17 05:42:12626 ExtensionSystem::Get(service()->GetBrowserContext())
treib9afc6212015-10-30 18:49:58627 ->app_sorting()
628 ->OnExtensionMoved(apps[0]->id(), apps[1]->id(), apps[2]->id());
629 {
630 syncer::SyncDataList list =
631 extension_sync_service()->GetAllSyncData(syncer::APPS);
632 ASSERT_EQ(list.size(), 3U);
633
634 scoped_ptr<ExtensionSyncData> data[kAppCount];
635 for (size_t i = 0; i < kAppCount; ++i) {
636 data[i] = ExtensionSyncData::CreateFromSyncData(list[i]);
637 ASSERT_TRUE(data[i].get());
638 }
639
640 // The sync data is not always in the same order our apps were installed in,
641 // so we do that sorting here so we can make sure the values are changed as
642 // expected.
643 syncer::StringOrdinal app_launch_ordinals[kAppCount];
644 for (size_t i = 0; i < kAppCount; ++i) {
645 for (size_t j = 0; j < kAppCount; ++j) {
646 if (apps[i]->id() == data[j]->id())
647 app_launch_ordinals[i] = data[j]->app_launch_ordinal();
648 }
649 }
650
651 EXPECT_TRUE(app_launch_ordinals[1].LessThan(app_launch_ordinals[0]));
652 EXPECT_TRUE(app_launch_ordinals[0].LessThan(app_launch_ordinals[2]));
653 }
654}
655
656TEST_F(ExtensionServiceSyncTest, GetSyncDataList) {
657 InitializeEmptyExtensionService();
658 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
659 InstallCRX(data_dir().AppendASCII("page_action.crx"), INSTALL_NEW);
660 InstallCRX(data_dir().AppendASCII("theme.crx"), INSTALL_NEW);
661 InstallCRX(data_dir().AppendASCII("theme2.crx"), INSTALL_NEW);
662
663 syncer::FakeSyncChangeProcessor processor;
664 extension_sync_service()->MergeDataAndStartSyncing(
665 syncer::APPS,
666 syncer::SyncDataList(),
667 scoped_ptr<syncer::SyncChangeProcessor>(
668 new syncer::FakeSyncChangeProcessor),
669 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
670 extension_sync_service()->MergeDataAndStartSyncing(
671 syncer::EXTENSIONS,
672 syncer::SyncDataList(),
673 scoped_ptr<syncer::SyncChangeProcessor>(
674 new syncer::FakeSyncChangeProcessor),
675 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
676
677 service()->DisableExtension(page_action, Extension::DISABLE_USER_ACTION);
678 TerminateExtension(theme2_crx);
679
680 EXPECT_EQ(0u, extension_sync_service()->GetAllSyncData(syncer::APPS).size());
681 EXPECT_EQ(
682 2u, extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS).size());
683}
684
685TEST_F(ExtensionServiceSyncTest, ProcessSyncDataUninstall) {
686 InitializeEmptyExtensionService();
687 syncer::FakeSyncChangeProcessor processor;
688 extension_sync_service()->MergeDataAndStartSyncing(
689 syncer::EXTENSIONS,
690 syncer::SyncDataList(),
691 scoped_ptr<syncer::SyncChangeProcessor>(
692 new syncer::FakeSyncChangeProcessor),
693 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
694
695 sync_pb::EntitySpecifics specifics;
696 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
697 ext_specifics->set_id(good_crx);
698 ext_specifics->set_version("1.0");
699 syncer::SyncData sync_data =
700 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
701 syncer::SyncChange sync_change(FROM_HERE,
702 syncer::SyncChange::ACTION_DELETE,
703 sync_data);
704 syncer::SyncChangeList list(1);
705 list[0] = sync_change;
706
707 // Should do nothing.
708 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
709 EXPECT_FALSE(service()->GetExtensionById(good_crx, true));
710
711 // Install the extension.
712 base::FilePath extension_path = data_dir().AppendASCII("good.crx");
713 InstallCRX(extension_path, INSTALL_NEW);
714 EXPECT_TRUE(service()->GetExtensionById(good_crx, true));
715
716 // Should uninstall the extension.
717 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
718 EXPECT_FALSE(service()->GetExtensionById(good_crx, true));
719
720 // Should again do nothing.
721 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
722 EXPECT_FALSE(service()->GetExtensionById(good_crx, true));
723}
724
725TEST_F(ExtensionServiceSyncTest, ProcessSyncDataWrongType) {
726 InitializeEmptyExtensionService();
727
728 // Install the extension.
729 base::FilePath extension_path = data_dir().AppendASCII("good.crx");
730 InstallCRX(extension_path, INSTALL_NEW);
731 EXPECT_TRUE(service()->GetExtensionById(good_crx, true));
732
733 sync_pb::EntitySpecifics specifics;
734 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app();
735 sync_pb::ExtensionSpecifics* extension_specifics =
736 app_specifics->mutable_extension();
737 extension_specifics->set_id(good_crx);
738 extension_specifics->set_version(
739 service()->GetInstalledExtension(good_crx)->version()->GetString());
740
741 {
742 extension_specifics->set_enabled(true);
743 syncer::SyncData sync_data =
744 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
745 syncer::SyncChange sync_change(FROM_HERE,
746 syncer::SyncChange::ACTION_DELETE,
747 sync_data);
748 syncer::SyncChangeList list(1);
749 list[0] = sync_change;
750
751 // Should do nothing
752 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
753 EXPECT_TRUE(service()->GetExtensionById(good_crx, true));
754 }
755
756 {
757 extension_specifics->set_enabled(false);
758 syncer::SyncData sync_data =
759 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
760 syncer::SyncChange sync_change(FROM_HERE,
761 syncer::SyncChange::ACTION_UPDATE,
762 sync_data);
763 syncer::SyncChangeList list(1);
764 list[0] = sync_change;
765
766 // Should again do nothing.
767 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
768 EXPECT_TRUE(service()->GetExtensionById(good_crx, false));
769 }
770}
771
772TEST_F(ExtensionServiceSyncTest, ProcessSyncDataSettings) {
773 InitializeEmptyExtensionService();
774 syncer::FakeSyncChangeProcessor processor;
775 extension_sync_service()->MergeDataAndStartSyncing(
776 syncer::EXTENSIONS,
777 syncer::SyncDataList(),
778 scoped_ptr<syncer::SyncChangeProcessor>(
779 new syncer::FakeSyncChangeProcessor),
780 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
781
782 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
783 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
784 EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
785 EXPECT_FALSE(extensions::util::HasSetAllowedScriptingOnAllUrls(
786 good_crx, profile()));
787 const bool kDefaultAllowedScripting =
788 extensions::util::DefaultAllowedScriptingOnAllUrls();
789 EXPECT_EQ(kDefaultAllowedScripting,
790 extensions::util::AllowedScriptingOnAllUrls(good_crx, profile()));
791
792 sync_pb::EntitySpecifics specifics;
793 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
794 ext_specifics->set_id(good_crx);
795 ext_specifics->set_version(
796 service()->GetInstalledExtension(good_crx)->version()->GetString());
797 ext_specifics->set_enabled(false);
798
799 {
800 syncer::SyncData sync_data =
801 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
802 syncer::SyncChange sync_change(FROM_HERE,
803 syncer::SyncChange::ACTION_UPDATE,
804 sync_data);
805 syncer::SyncChangeList list(1);
806 list[0] = sync_change;
807 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
808 EXPECT_FALSE(service()->IsExtensionEnabled(good_crx));
809 EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
810 EXPECT_FALSE(extensions::util::HasSetAllowedScriptingOnAllUrls(
811 good_crx, profile()));
812 EXPECT_EQ(kDefaultAllowedScripting,
813 extensions::util::AllowedScriptingOnAllUrls(good_crx, profile()));
814 }
815
816 {
817 ext_specifics->set_enabled(true);
818 ext_specifics->set_incognito_enabled(true);
819 syncer::SyncData sync_data =
820 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
821 syncer::SyncChange sync_change(FROM_HERE,
822 syncer::SyncChange::ACTION_UPDATE,
823 sync_data);
824 syncer::SyncChangeList list(1);
825 list[0] = sync_change;
826 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
827 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
828 EXPECT_TRUE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
829 }
830
831 {
832 ext_specifics->set_enabled(false);
833 ext_specifics->set_incognito_enabled(true);
834 syncer::SyncData sync_data =
835 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
836 syncer::SyncChange sync_change(FROM_HERE,
837 syncer::SyncChange::ACTION_UPDATE,
838 sync_data);
839 syncer::SyncChangeList list(1);
840 list[0] = sync_change;
841 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
842 EXPECT_FALSE(service()->IsExtensionEnabled(good_crx));
843 EXPECT_TRUE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
844 }
845
846 {
847 ext_specifics->set_enabled(true);
848 ext_specifics->set_all_urls_enabled(!kDefaultAllowedScripting);
849 syncer::SyncData sync_data =
850 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
851 syncer::SyncChange sync_change(FROM_HERE,
852 syncer::SyncChange::ACTION_UPDATE,
853 sync_data);
854 syncer::SyncChangeList list(1);
855 list[0] = sync_change;
856 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
857 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
858 EXPECT_TRUE(extensions::util::HasSetAllowedScriptingOnAllUrls(
859 good_crx, profile()));
860 EXPECT_EQ(!kDefaultAllowedScripting,
861 extensions::util::AllowedScriptingOnAllUrls(good_crx, profile()));
862 }
863
864 {
865 ext_specifics->set_all_urls_enabled(kDefaultAllowedScripting);
866 syncer::SyncData sync_data =
867 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
868 syncer::SyncChange sync_change(FROM_HERE,
869 syncer::SyncChange::ACTION_UPDATE,
870 sync_data);
871 syncer::SyncChangeList list(1);
872 list[0] = sync_change;
873 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
874 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
875 EXPECT_TRUE(extensions::util::HasSetAllowedScriptingOnAllUrls(
876 good_crx, profile()));
877 EXPECT_EQ(kDefaultAllowedScripting,
878 extensions::util::AllowedScriptingOnAllUrls(good_crx, profile()));
879 }
880
881 EXPECT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
882}
883
884TEST_F(ExtensionServiceSyncTest, ProcessSyncDataNewExtension) {
885 InitializeEmptyExtensionService();
886 syncer::FakeSyncChangeProcessor processor;
887 extension_sync_service()->MergeDataAndStartSyncing(
888 syncer::EXTENSIONS,
889 syncer::SyncDataList(),
890 scoped_ptr<syncer::SyncChangeProcessor>(
891 new syncer::FakeSyncChangeProcessor),
892 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
893
894 const base::FilePath path = data_dir().AppendASCII("good.crx");
895 const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
896
897 struct TestCase {
898 const char* name; // For failure output only.
899 bool sync_enabled; // The "enabled" flag coming in from Sync.
900 // The disable reason(s) coming in from Sync, or -1 for "not set".
901 int sync_disable_reasons;
902 // The disable reason(s) that should be set on the installed extension.
903 // This will usually be the same as |sync_disable_reasons|, but see the
904 // "Legacy" case.
905 int expect_disable_reasons;
906 // Whether the extension's permissions should be auto-granted during
907 // installation.
908 bool expect_permissions_granted;
909 } test_cases[] = {
910 // Standard case: Extension comes in enabled; permissions should be granted
911 // during installation.
912 { "Standard", true, 0, 0, true },
913 // If the extension comes in disabled, its permissions should still be
914 // granted (the user already approved them on another machine).
915 { "Disabled", false, Extension::DISABLE_USER_ACTION,
916 Extension::DISABLE_USER_ACTION, true },
917 // Legacy case (<M45): No disable reasons come in from Sync (see
918 // crbug.com/484214). After installation, the reason should be set to
treib3b91e9f2015-11-04 11:29:41919 // DISABLE_USER_ACTION (default assumption).
920 { "Legacy", false, -1, Extension::DISABLE_USER_ACTION, true },
treib9afc6212015-10-30 18:49:58921 // If the extension came in disabled due to a permissions increase, then the
922 // user has *not* approved the permissions, and they shouldn't be granted.
923 // crbug.com/484214
924 { "PermissionsIncrease", false, Extension::DISABLE_PERMISSIONS_INCREASE,
925 Extension::DISABLE_PERMISSIONS_INCREASE, false },
926 };
927
928 for (const TestCase& test_case : test_cases) {
929 SCOPED_TRACE(test_case.name);
930
931 sync_pb::EntitySpecifics specifics;
932 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
933 ext_specifics->set_id(good_crx);
934 ext_specifics->set_version(base::Version("1").GetString());
935 ext_specifics->set_enabled(test_case.sync_enabled);
936 if (test_case.sync_disable_reasons != -1)
937 ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
938
939 syncer::SyncData sync_data =
940 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
941 syncer::SyncChange sync_change(FROM_HERE,
942 syncer::SyncChange::ACTION_UPDATE,
943 sync_data);
944 syncer::SyncChangeList list(1, sync_change);
945 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
946
947 ASSERT_TRUE(service()->pending_extension_manager()->IsIdPending(good_crx));
948 UpdateExtension(good_crx, path, test_case.sync_enabled ? ENABLED
949 : DISABLED);
950 EXPECT_EQ(test_case.expect_disable_reasons,
951 prefs->GetDisableReasons(good_crx));
952 scoped_ptr<const PermissionSet> permissions =
953 prefs->GetGrantedPermissions(good_crx);
954 EXPECT_EQ(test_case.expect_permissions_granted, !permissions->IsEmpty());
955 ASSERT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
956
957 // Remove the extension again, so we can install it again for the next case.
958 UninstallExtension(good_crx, false,
959 test_case.sync_enabled ? Extension::ENABLED
960 : Extension::DISABLED);
961 }
962}
963
964TEST_F(ExtensionServiceSyncTest, ProcessSyncDataTerminatedExtension) {
965 InitializeExtensionServiceWithUpdater();
966 syncer::FakeSyncChangeProcessor processor;
967 extension_sync_service()->MergeDataAndStartSyncing(
968 syncer::EXTENSIONS,
969 syncer::SyncDataList(),
970 scoped_ptr<syncer::SyncChangeProcessor>(
971 new syncer::FakeSyncChangeProcessor),
972 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
973
974 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
975 TerminateExtension(good_crx);
976 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
977 EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
978
979 sync_pb::EntitySpecifics specifics;
980 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
981 ext_specifics->set_id(good_crx);
982 ext_specifics->set_version(
983 service()->GetInstalledExtension(good_crx)->version()->GetString());
984 ext_specifics->set_enabled(false);
985 ext_specifics->set_incognito_enabled(true);
986 syncer::SyncData sync_data =
987 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
988 syncer::SyncChange sync_change(FROM_HERE,
989 syncer::SyncChange::ACTION_UPDATE,
990 sync_data);
991 syncer::SyncChangeList list(1);
992 list[0] = sync_change;
993
994 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
995 EXPECT_FALSE(service()->IsExtensionEnabled(good_crx));
996 EXPECT_TRUE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
997
998 EXPECT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
999}
1000
1001TEST_F(ExtensionServiceSyncTest, ProcessSyncDataVersionCheck) {
1002 InitializeExtensionServiceWithUpdater();
1003 syncer::FakeSyncChangeProcessor processor;
1004 extension_sync_service()->MergeDataAndStartSyncing(
1005 syncer::EXTENSIONS,
1006 syncer::SyncDataList(),
1007 scoped_ptr<syncer::SyncChangeProcessor>(
1008 new syncer::FakeSyncChangeProcessor),
1009 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1010
1011 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
1012 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
1013 EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
1014
1015 sync_pb::EntitySpecifics specifics;
1016 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1017 ext_specifics->set_id(good_crx);
1018 ext_specifics->set_enabled(true);
1019
1020 const base::Version installed_version =
1021 *service()->GetInstalledExtension(good_crx)->version();
1022
1023 {
1024 ext_specifics->set_version(installed_version.GetString());
1025 syncer::SyncData sync_data =
1026 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1027 syncer::SyncChange sync_change(FROM_HERE,
1028 syncer::SyncChange::ACTION_UPDATE,
1029 sync_data);
1030 syncer::SyncChangeList list(1, sync_change);
1031
1032 // Should do nothing if extension version == sync version.
1033 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1034 EXPECT_FALSE(service()->updater()->WillCheckSoon());
1035 // Make sure the version we'll send back to sync didn't change.
1036 syncer::SyncDataList data =
1037 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
1038 ASSERT_EQ(1u, data.size());
1039 scoped_ptr<ExtensionSyncData> extension_data =
1040 ExtensionSyncData::CreateFromSyncData(data[0]);
1041 ASSERT_TRUE(extension_data);
1042 EXPECT_TRUE(installed_version.Equals(extension_data->version()));
1043 }
1044
1045 // Should do nothing if extension version > sync version.
1046 {
1047 ext_specifics->set_version("0.0.0.0");
1048 syncer::SyncData sync_data =
1049 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1050 syncer::SyncChange sync_change(FROM_HERE,
1051 syncer::SyncChange::ACTION_UPDATE,
1052 sync_data);
1053 syncer::SyncChangeList list(1, sync_change);
1054
1055 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1056 EXPECT_FALSE(service()->updater()->WillCheckSoon());
1057 // Make sure the version we'll send back to sync didn't change.
1058 syncer::SyncDataList data =
1059 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
1060 ASSERT_EQ(1u, data.size());
1061 scoped_ptr<ExtensionSyncData> extension_data =
1062 ExtensionSyncData::CreateFromSyncData(data[0]);
1063 ASSERT_TRUE(extension_data);
1064 EXPECT_TRUE(installed_version.Equals(extension_data->version()));
1065 }
1066
1067 // Should kick off an update if extension version < sync version.
1068 {
1069 const base::Version new_version("9.9.9.9");
1070 ext_specifics->set_version(new_version.GetString());
1071 syncer::SyncData sync_data =
1072 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1073 syncer::SyncChange sync_change(FROM_HERE,
1074 syncer::SyncChange::ACTION_UPDATE,
1075 sync_data);
1076 syncer::SyncChangeList list(1, sync_change);
1077
1078 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1079 EXPECT_TRUE(service()->updater()->WillCheckSoon());
1080 // Make sure that we'll send the NEW version back to sync, even though we
1081 // haven't actually updated yet. This is to prevent the data in sync from
1082 // flip-flopping back and forth until all clients are up to date.
1083 syncer::SyncDataList data =
1084 extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
1085 ASSERT_EQ(1u, data.size());
1086 scoped_ptr<ExtensionSyncData> extension_data =
1087 ExtensionSyncData::CreateFromSyncData(data[0]);
1088 ASSERT_TRUE(extension_data);
1089 EXPECT_TRUE(new_version.Equals(extension_data->version()));
1090 }
1091
1092 EXPECT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
1093}
1094
1095TEST_F(ExtensionServiceSyncTest, ProcessSyncDataNotInstalled) {
1096 InitializeExtensionServiceWithUpdater();
1097 syncer::FakeSyncChangeProcessor processor;
1098 extension_sync_service()->MergeDataAndStartSyncing(
1099 syncer::EXTENSIONS,
1100 syncer::SyncDataList(),
1101 scoped_ptr<syncer::SyncChangeProcessor>(
1102 new syncer::FakeSyncChangeProcessor),
1103 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1104
1105 sync_pb::EntitySpecifics specifics;
1106 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1107 ext_specifics->set_id(good_crx);
1108 ext_specifics->set_enabled(false);
1109 ext_specifics->set_incognito_enabled(true);
1110 ext_specifics->set_update_url("http://www.google.com/");
1111 ext_specifics->set_version("1.2.3.4");
1112 syncer::SyncData sync_data =
1113 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1114 syncer::SyncChange sync_change(FROM_HERE,
1115 syncer::SyncChange::ACTION_UPDATE,
1116 sync_data);
1117 syncer::SyncChangeList list(1);
1118 list[0] = sync_change;
1119
1120 EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
1121 EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
1122 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1123 EXPECT_TRUE(service()->updater()->WillCheckSoon());
1124 EXPECT_FALSE(service()->IsExtensionEnabled(good_crx));
1125 EXPECT_TRUE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
1126
1127 const extensions::PendingExtensionInfo* info;
1128 EXPECT_TRUE(
1129 (info = service()->pending_extension_manager()->GetById(good_crx)));
1130 EXPECT_EQ(ext_specifics->update_url(), info->update_url().spec());
1131 EXPECT_TRUE(info->is_from_sync());
1132 EXPECT_EQ(Manifest::INTERNAL, info->install_source());
1133 // TODO(akalin): Figure out a way to test |info.ShouldAllowInstall()|.
1134}
1135
1136TEST_F(ExtensionServiceSyncTest, ProcessSyncDataEnableDisable) {
1137 InitializeEmptyExtensionService();
1138 extension_sync_service()->MergeDataAndStartSyncing(
1139 syncer::EXTENSIONS,
1140 syncer::SyncDataList(),
1141 scoped_ptr<syncer::SyncChangeProcessor>(
1142 new syncer::FakeSyncChangeProcessor),
1143 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1144
1145 const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
1146
1147 struct TestCase {
1148 const char* name; // For failure output only.
1149 // Set of disable reasons before any Sync data comes in. If this is != 0,
1150 // the extension is disabled.
1151 int previous_disable_reasons;
1152 bool sync_enable; // The enabled flag coming in from Sync.
1153 // The disable reason(s) coming in from Sync, or -1 for "not set".
1154 int sync_disable_reasons;
1155 // The expected set of disable reasons after processing the Sync update. The
1156 // extension should be disabled iff this is != 0.
1157 int expect_disable_reasons;
1158 } test_cases[] = {
1159 { "NopEnable", 0, true, 0, 0 },
1160 { "NopDisable", Extension::DISABLE_USER_ACTION, false,
1161 Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
treib29e1b9b12015-11-11 08:50:561162 { "Enable", Extension::DISABLE_USER_ACTION, true, 0, 0 },
treib9afc6212015-10-30 18:49:581163 { "Disable", 0, false, Extension::DISABLE_USER_ACTION,
1164 Extension::DISABLE_USER_ACTION },
treib9afc6212015-10-30 18:49:581165 { "AddDisableReason", Extension::DISABLE_REMOTE_INSTALL, false,
1166 Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION,
1167 Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION },
treib9afc6212015-10-30 18:49:581168 { "RemoveDisableReason",
1169 Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION, false,
1170 Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
treib29e1b9b12015-11-11 08:50:561171 { "PreserveLocalDisableReason", Extension::DISABLE_RELOAD, true, 0,
1172 Extension::DISABLE_RELOAD },
1173 { "PreserveOnlyLocalDisableReason",
1174 Extension::DISABLE_USER_ACTION | Extension::DISABLE_RELOAD, true, 0,
1175 Extension::DISABLE_RELOAD },
1176
1177 // Interaction with Chrome clients <=M44, which don't sync disable_reasons
1178 // at all (any existing reasons are preserved).
1179 { "M44Enable", Extension::DISABLE_USER_ACTION, true, -1, 0 },
1180 // An M44 client enables an extension that had been disabled on a new
1181 // client. The disable reasons are still be there, but should be ignored.
1182 { "M44ReEnable", Extension::DISABLE_USER_ACTION, true,
1183 Extension::DISABLE_USER_ACTION, 0 },
1184 { "M44Disable", 0, false, -1, Extension::DISABLE_USER_ACTION },
1185 { "M44ReDisable", 0, false, 0, Extension::DISABLE_USER_ACTION },
1186 { "M44AlreadyDisabledByUser", Extension::DISABLE_USER_ACTION, false, -1,
1187 Extension::DISABLE_USER_ACTION},
1188 { "M44AlreadyDisabledWithOtherReason", Extension::DISABLE_REMOTE_INSTALL,
1189 false, -1,
1190 Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION },
treib9afc6212015-10-30 18:49:581191 };
1192
1193 for (const TestCase& test_case : test_cases) {
1194 SCOPED_TRACE(test_case.name);
1195
1196 std::string id;
1197 std::string version;
1198 // Don't keep |extension| around longer than necessary.
1199 {
1200 const Extension* extension =
1201 InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
1202 // The extension should now be installed and enabled.
1203 ASSERT_TRUE(extension);
1204 id = extension->id();
1205 version = extension->VersionString();
1206 }
1207 ASSERT_TRUE(registry()->enabled_extensions().Contains(id));
1208
1209 // Disable it if the test case says so.
1210 if (test_case.previous_disable_reasons) {
1211 service()->DisableExtension(id, test_case.previous_disable_reasons);
1212 ASSERT_TRUE(registry()->disabled_extensions().Contains(id));
1213 }
1214
1215 // Now a sync update comes in.
1216 sync_pb::EntitySpecifics specifics;
1217 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1218 ext_specifics->set_id(id);
1219 ext_specifics->set_enabled(test_case.sync_enable);
1220 ext_specifics->set_version(version);
1221 if (test_case.sync_disable_reasons != -1)
1222 ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
1223
1224 syncer::SyncData sync_data =
1225 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1226 syncer::SyncChange sync_change(FROM_HERE,
1227 syncer::SyncChange::ACTION_UPDATE,
1228 sync_data);
1229 syncer::SyncChangeList list(1, sync_change);
1230 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1231
1232 // Check expectations.
1233 const bool expect_enabled = !test_case.expect_disable_reasons;
1234 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id));
1235 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id));
1236
1237 // Remove the extension again, so we can install it again for the next case.
1238 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED
1239 : Extension::DISABLED);
1240 }
1241}
1242
1243TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) {
1244 InitializeEmptyExtensionService();
1245 extension_sync_service()->MergeDataAndStartSyncing(
1246 syncer::EXTENSIONS,
1247 syncer::SyncDataList(),
1248 scoped_ptr<syncer::SyncChangeProcessor>(
1249 new syncer::FakeSyncChangeProcessor),
1250 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1251
1252 base::FilePath base_path = data_dir().AppendASCII("permissions_increase");
1253 base::FilePath pem_path = base_path.AppendASCII("permissions.pem");
1254
1255 base::FilePath path = base_path.AppendASCII("v1");
1256 const Extension* extension = PackAndInstallCRX(path, pem_path, INSTALL_NEW);
1257 // The extension must now be installed and enabled.
1258 ASSERT_TRUE(extension);
1259 ASSERT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
1260
1261 // Save the id, as the extension object will be destroyed during updating.
1262 std::string id = extension->id();
1263
1264 // Update to a new version with increased permissions.
1265 path = base_path.AppendASCII("v2");
1266 PackCRXAndUpdateExtension(id, path, pem_path, DISABLED);
1267
1268 // Now a sync update comes in, telling us to re-enable a *newer* version.
1269 sync_pb::EntitySpecifics specifics;
1270 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1271 ext_specifics->set_id(id);
1272 ext_specifics->set_version("3");
1273 ext_specifics->set_enabled(true);
1274 ext_specifics->set_disable_reasons(Extension::DISABLE_NONE);
1275
1276 syncer::SyncData sync_data =
1277 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1278 syncer::SyncChange sync_change(FROM_HERE,
1279 syncer::SyncChange::ACTION_UPDATE,
1280 sync_data);
1281 syncer::SyncChangeList list(1, sync_change);
1282 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1283
1284 // Since the version didn't match, the extension should still be disabled.
1285 EXPECT_TRUE(registry()->disabled_extensions().Contains(id));
1286
1287 // After we update to the matching version, the extension should get enabled.
1288 path = base_path.AppendASCII("v3");
1289 PackCRXAndUpdateExtension(id, path, pem_path, ENABLED);
1290}
1291
1292TEST_F(ExtensionServiceSyncTest, ProcessSyncDataPermissionApproval) {
1293 // This is the update URL specified in the test extension. Setting it here is
1294 // necessary to make it considered syncable.
1295 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1296 switches::kAppsGalleryUpdateURL,
1297 "http://localhost/autoupdate/updates.xml");
1298
1299 InitializeEmptyExtensionService();
1300 extension_sync_service()->MergeDataAndStartSyncing(
1301 syncer::EXTENSIONS,
1302 syncer::SyncDataList(),
1303 scoped_ptr<syncer::SyncChangeProcessor>(
1304 new syncer::FakeSyncChangeProcessor),
1305 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1306
1307 const base::FilePath base_path =
1308 data_dir().AppendASCII("permissions_increase");
1309 const base::FilePath pem_path = base_path.AppendASCII("permissions.pem");
1310 const base::FilePath path_v1 = base_path.AppendASCII("v1");
1311 const base::FilePath path_v2 = base_path.AppendASCII("v2");
1312
1313 base::ScopedTempDir crx_dir;
1314 ASSERT_TRUE(crx_dir.CreateUniqueTempDir());
1315 const base::FilePath crx_path_v1 = crx_dir.path().AppendASCII("temp1.crx");
1316 PackCRX(path_v1, pem_path, crx_path_v1);
1317 const base::FilePath crx_path_v2 = crx_dir.path().AppendASCII("temp2.crx");
1318 PackCRX(path_v2, pem_path, crx_path_v2);
1319
1320 const std::string v1("1");
1321 const std::string v2("2");
1322
1323 const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
1324
1325 struct TestCase {
1326 const char* name; // For failure output only.
1327 const std::string& sync_version; // The version coming in from Sync.
1328 // The disable reason(s) coming in from Sync, or -1 for "not set".
1329 int sync_disable_reasons;
1330 // The expected set of disable reasons after processing the Sync update. The
1331 // extension should be enabled iff this is 0.
1332 int expect_disable_reasons;
1333 // Whether the extension's permissions should be auto-granted.
1334 bool expect_permissions_granted;
1335 } test_cases[] = {
1336 // Sync tells us to re-enable an older version. No permissions should be
1337 // granted, since we can't be sure if the user actually approved the right
1338 // set of permissions.
1339 { "OldVersion", v1, 0, Extension::DISABLE_PERMISSIONS_INCREASE, false },
1340 // Legacy case: Sync tells us to re-enable the extension, but doesn't
1341 // specify disable reasons. No permissions should be granted.
1342 { "Legacy", v2, -1, Extension::DISABLE_PERMISSIONS_INCREASE, false },
1343 // Sync tells us to re-enable the extension and explicitly removes the
1344 // disable reasons. Now the extension should have its permissions granted.
1345 { "GrantPermissions", v2, 0, Extension::DISABLE_NONE, true },
1346 };
1347
1348 for (const TestCase& test_case : test_cases) {
1349 SCOPED_TRACE(test_case.name);
1350
1351 std::string id;
1352 // Don't keep |extension| around longer than necessary (it'll be destroyed
1353 // during updating).
1354 {
1355 const Extension* extension = InstallCRX(crx_path_v1, INSTALL_NEW);
1356 // The extension should now be installed and enabled.
1357 ASSERT_TRUE(extension);
1358 ASSERT_EQ(v1, extension->VersionString());
1359 id = extension->id();
1360 }
1361 ASSERT_TRUE(registry()->enabled_extensions().Contains(id));
1362
1363 scoped_ptr<const PermissionSet> granted_permissions_v1 =
1364 prefs->GetGrantedPermissions(id);
1365
1366 // Update to a new version with increased permissions.
1367 UpdateExtension(id, crx_path_v2, DISABLED);
1368
1369 // Now the extension should be disabled due to a permissions increase.
1370 {
1371 const Extension* extension =
1372 registry()->disabled_extensions().GetByID(id);
1373 ASSERT_TRUE(extension);
1374 ASSERT_EQ(v2, extension->VersionString());
1375 }
1376 ASSERT_TRUE(prefs->HasDisableReason(
1377 id, Extension::DISABLE_PERMISSIONS_INCREASE));
1378
1379 // No new permissions should have been granted.
1380 scoped_ptr<const PermissionSet> granted_permissions_v2 =
1381 prefs->GetGrantedPermissions(id);
1382 ASSERT_EQ(*granted_permissions_v1, *granted_permissions_v2);
1383
1384 // Now a sync update comes in.
1385 sync_pb::EntitySpecifics specifics;
1386 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1387 ext_specifics->set_id(id);
1388 ext_specifics->set_enabled(true);
1389 ext_specifics->set_version(test_case.sync_version);
1390 if (test_case.sync_disable_reasons != -1)
1391 ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
1392
1393 syncer::SyncData sync_data =
1394 syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
1395 syncer::SyncChange sync_change(FROM_HERE,
1396 syncer::SyncChange::ACTION_UPDATE,
1397 sync_data);
1398 syncer::SyncChangeList list(1, sync_change);
1399 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1400
1401 // Check expectations.
1402 const bool expect_enabled = !test_case.expect_disable_reasons;
1403 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id));
1404 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id));
1405 scoped_ptr<const PermissionSet> granted_permissions =
1406 prefs->GetGrantedPermissions(id);
1407 if (test_case.expect_permissions_granted) {
1408 scoped_ptr<const PermissionSet> active_permissions =
1409 prefs->GetActivePermissions(id);
1410 EXPECT_EQ(*granted_permissions, *active_permissions);
1411 } else {
1412 EXPECT_EQ(*granted_permissions, *granted_permissions_v1);
1413 }
1414
1415 // Remove the extension again, so we can install it again for the next case.
1416 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED
1417 : Extension::DISABLED);
1418 }
1419}
1420
1421#if defined(ENABLE_SUPERVISED_USERS)
1422
1423class ExtensionServiceTestSupervised : public ExtensionServiceSyncTest,
1424 public SupervisedUserService::Delegate {
1425 public:
1426 void SetUp() override {
1427 ExtensionServiceSyncTest::SetUp();
1428
1429 // This is the update URL specified in the permissions test extension.
1430 // Setting it here is necessary to make the extension considered syncable.
1431 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1432 switches::kAppsGalleryUpdateURL,
1433 "http://localhost/autoupdate/updates.xml");
1434 }
1435
1436 void TearDown() override {
1437 supervised_user_service()->SetDelegate(nullptr);
1438
1439 ExtensionServiceSyncTest::TearDown();
1440 }
1441
1442 protected:
1443 void InitServices(bool profile_is_supervised) {
1444 ExtensionServiceInitParams params = CreateDefaultInitParams();
1445 params.profile_is_supervised = profile_is_supervised;
1446 InitializeExtensionService(params);
1447
1448 supervised_user_service()->SetDelegate(this);
1449 supervised_user_service()->Init();
1450 }
1451
1452 std::string InstallPermissionsTestExtension() {
1453 const std::string version("1");
1454
1455 const Extension* extension =
1456 PackAndInstallCRX(dir_path(version), pem_path(), INSTALL_NEW,
1457 Extension::WAS_INSTALLED_BY_CUSTODIAN);
1458 // The extension must now be installed and enabled.
1459 EXPECT_TRUE(extension);
1460 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
1461 EXPECT_EQ(version, extension->VersionString());
1462
1463 return extension->id();
1464 }
1465
1466 void UpdatePermissionsTestExtension(const std::string& id,
1467 const std::string& version,
1468 UpdateState expected_state) {
1469 PackCRXAndUpdateExtension(id, dir_path(version), pem_path(),
1470 expected_state);
1471 const Extension* extension = registry()->GetInstalledExtension(id);
1472 ASSERT_TRUE(extension);
1473 // The version should have been updated.
1474 EXPECT_EQ(version, extension->VersionString());
1475 }
1476
1477 SupervisedUserService* supervised_user_service() {
1478 return SupervisedUserServiceFactory::GetForProfile(profile());
1479 }
1480
1481 static std::string UpdateRequestId(const std::string& extension_id,
1482 const std::string& version) {
1483 return SupervisedUserService::GetExtensionUpdateRequestId(
1484 extension_id, base::Version(version));
1485 }
1486
1487 private:
1488 // This prevents the legacy supervised user init code from running.
1489 bool SetActive(bool active) override { return true; }
1490
1491 base::FilePath base_path() const {
1492 return data_dir().AppendASCII("permissions_increase");
1493 }
1494 base::FilePath dir_path(const std::string& version) const {
1495 return base_path().AppendASCII("v" + version);
1496 }
1497 base::FilePath pem_path() const {
1498 return base_path().AppendASCII("permissions.pem");
1499 }
1500};
1501
1502class MockPermissionRequestCreator : public PermissionRequestCreator {
1503 public:
1504 MockPermissionRequestCreator() {}
1505 ~MockPermissionRequestCreator() override {}
1506
1507 bool IsEnabled() const override { return true; }
1508
1509 void CreateURLAccessRequest(const GURL& url_requested,
1510 const SuccessCallback& callback) override {
1511 FAIL();
1512 }
1513
1514 MOCK_METHOD2(CreateExtensionUpdateRequest,
1515 void(const std::string& id,
1516 const SupervisedUserService::SuccessCallback& callback));
1517
1518 private:
1519 DISALLOW_COPY_AND_ASSIGN(MockPermissionRequestCreator);
1520};
1521
1522TEST_F(ExtensionServiceTestSupervised, InstallOnlyAllowedByCustodian) {
1523 InitServices(true /* profile_is_supervised */);
1524
1525 base::FilePath path1 = data_dir().AppendASCII("good.crx");
1526 base::FilePath path2 = data_dir().AppendASCII("good2048.crx");
1527 const Extension* extensions[] = {
1528 InstallCRX(path1, INSTALL_FAILED),
1529 InstallCRX(path2, INSTALL_NEW, Extension::WAS_INSTALLED_BY_CUSTODIAN)
1530 };
1531
1532 // Only the extension with the "installed by custodian" flag should have been
1533 // installed and enabled.
1534 EXPECT_FALSE(extensions[0]);
1535 ASSERT_TRUE(extensions[1]);
1536 EXPECT_TRUE(registry()->enabled_extensions().Contains(extensions[1]->id()));
1537}
1538
1539TEST_F(ExtensionServiceTestSupervised, PreinstalledExtension) {
1540 InitServices(false /* profile_is_supervised */);
1541
1542 // Install an extension.
1543 base::FilePath path = data_dir().AppendASCII("good.crx");
1544 const Extension* extension = InstallCRX(path, INSTALL_NEW);
1545 std::string id = extension->id();
1546
1547 // Now make the profile supervised.
1548 profile()->AsTestingProfile()->SetSupervisedUserId(
1549 supervised_users::kChildAccountSUID);
1550
1551 // The extension should not be enabled anymore.
1552 EXPECT_FALSE(registry()->enabled_extensions().Contains(id));
1553}
1554
1555TEST_F(ExtensionServiceTestSupervised, UpdateWithoutPermissionIncrease) {
1556 InitServices(true /* profile_is_supervised */);
1557
1558 base::FilePath base_path = data_dir().AppendASCII("autoupdate");
1559 base::FilePath pem_path = base_path.AppendASCII("key.pem");
1560
1561 const Extension* extension =
1562 PackAndInstallCRX(base_path.AppendASCII("v1"), pem_path, INSTALL_NEW,
1563 Extension::WAS_INSTALLED_BY_CUSTODIAN);
1564 // The extension must now be installed and enabled.
1565 ASSERT_TRUE(extension);
1566 ASSERT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
1567
1568 // Save the id, as the extension object will be destroyed during updating.
1569 std::string id = extension->id();
1570
1571 std::string old_version = extension->VersionString();
1572
1573 // Update to a new version.
1574 PackCRXAndUpdateExtension(id, base_path.AppendASCII("v2"), pem_path, ENABLED);
1575
1576 // The extension should still be there and enabled.
1577 extension = registry()->enabled_extensions().GetByID(id);
1578 ASSERT_TRUE(extension);
1579 // The version should have changed.
1580 EXPECT_NE(extension->VersionString(), old_version);
1581}
1582
1583TEST_F(ExtensionServiceTestSupervised, UpdateWithPermissionIncreaseNoApproval) {
1584 // Explicitly disable the "need custodian approval" field trial.
1585 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
1586 base::FieldTrialList::CreateFieldTrial(
1587 "SupervisedUserExtensionPermissionIncrease", "");
1588
1589 InitServices(true /* profile_is_supervised */);
1590
1591 MockPermissionRequestCreator* creator = new MockPermissionRequestCreator;
1592 supervised_user_service()->AddPermissionRequestCreator(
1593 make_scoped_ptr(creator));
1594
1595 std::string id = InstallPermissionsTestExtension();
1596
1597 // Update to a new version with increased permissions.
1598 // Since we don't require the custodian's approval, no permission request
1599 // should be created.
1600 const std::string version2("2");
1601 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1602 UpdateRequestId(id, version2), testing::_))
1603 .Times(0);
1604 UpdatePermissionsTestExtension(id, version2, DISABLED);
1605}
1606
1607TEST_F(ExtensionServiceTestSupervised,
1608 UpdateWithPermissionIncreaseApprovalOldVersion) {
1609 // Explicitly enable the "need custodian approval" field trial.
1610 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
1611 base::FieldTrialList::CreateFieldTrial(
1612 "SupervisedUserExtensionPermissionIncrease", "NeedCustodianApproval");
1613
1614 InitServices(true /* profile_is_supervised */);
1615
1616 MockPermissionRequestCreator* creator = new MockPermissionRequestCreator;
1617 supervised_user_service()->AddPermissionRequestCreator(
1618 make_scoped_ptr(creator));
1619
1620 const std::string version1("1");
1621 const std::string version2("2");
1622
1623 std::string id = InstallPermissionsTestExtension();
1624
1625 // Update to a new version with increased permissions.
1626 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1627 UpdateRequestId(id, version2), testing::_));
1628 UpdatePermissionsTestExtension(id, version2, DISABLED);
1629
1630 // Simulate a custodian approval for re-enabling the extension coming in
1631 // through Sync, but set the old version. This can happen when there already
1632 // was a pending request for an earlier version of the extension.
1633 sync_pb::EntitySpecifics specifics;
1634 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1635 ext_specifics->set_id(id);
1636 ext_specifics->set_enabled(true);
1637 ext_specifics->set_disable_reasons(Extension::DISABLE_NONE);
1638 ext_specifics->set_installed_by_custodian(true);
1639 ext_specifics->set_version(version1);
1640
1641 // Attempting to re-enable an old version should result in a permission
1642 // request for the current version.
1643 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1644 UpdateRequestId(id, version2), testing::_));
1645
1646 syncer::SyncData sync_data =
1647 syncer::SyncData::CreateLocalData(id, "Name", specifics);
1648 syncer::SyncChange sync_change(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
1649 sync_data);
1650 syncer::SyncChangeList change_list(1, sync_change);
1651 extension_sync_service()->ProcessSyncChanges(FROM_HERE, change_list);
1652 // The re-enable should be ignored, since the version doesn't match.
1653 EXPECT_FALSE(registry()->enabled_extensions().Contains(id));
1654 EXPECT_FALSE(extension_sync_service()->HasPendingReenable(
1655 id, base::Version(version1)));
1656 EXPECT_FALSE(extension_sync_service()->HasPendingReenable(
1657 id, base::Version(version2)));
1658}
1659
1660TEST_F(ExtensionServiceTestSupervised,
1661 UpdateWithPermissionIncreaseApprovalMatchingVersion) {
1662 // Explicitly enable the "need custodian approval" field trial.
1663 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
1664 base::FieldTrialList::CreateFieldTrial(
1665 "SupervisedUserExtensionPermissionIncrease", "NeedCustodianApproval");
1666
1667 InitServices(true /* profile_is_supervised */);
1668
1669 MockPermissionRequestCreator* creator = new MockPermissionRequestCreator;
1670 supervised_user_service()->AddPermissionRequestCreator(
1671 make_scoped_ptr(creator));
1672
1673 std::string id = InstallPermissionsTestExtension();
1674
1675 // Update to a new version with increased permissions.
1676 const std::string version2("2");
1677 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1678 UpdateRequestId(id, version2), testing::_));
1679 UpdatePermissionsTestExtension(id, version2, DISABLED);
1680
1681 // Simulate a custodian approval for re-enabling the extension coming in
1682 // through Sync.
1683 sync_pb::EntitySpecifics specifics;
1684 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1685 ext_specifics->set_id(id);
1686 ext_specifics->set_enabled(true);
1687 ext_specifics->set_disable_reasons(Extension::DISABLE_NONE);
1688 ext_specifics->set_installed_by_custodian(true);
1689 ext_specifics->set_version(version2);
1690
1691 syncer::SyncData sync_data =
1692 syncer::SyncData::CreateLocalData(id, "Name", specifics);
1693 syncer::SyncChange sync_change(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
1694 sync_data);
1695 syncer::SyncChangeList change_list(1, sync_change);
1696 extension_sync_service()->ProcessSyncChanges(FROM_HERE, change_list);
1697 // The extension should have gotten re-enabled.
1698 EXPECT_TRUE(registry()->enabled_extensions().Contains(id));
1699}
1700
1701TEST_F(ExtensionServiceTestSupervised,
1702 UpdateWithPermissionIncreaseApprovalNewVersion) {
1703 // Explicitly enable the "need custodian approval" field trial.
1704 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
1705 base::FieldTrialList::CreateFieldTrial(
1706 "SupervisedUserExtensionPermissionIncrease", "NeedCustodianApproval");
1707
1708 InitServices(true /* profile_is_supervised */);
1709
1710 MockPermissionRequestCreator* creator = new MockPermissionRequestCreator;
1711 supervised_user_service()->AddPermissionRequestCreator(
1712 make_scoped_ptr(creator));
1713
1714 std::string id = InstallPermissionsTestExtension();
1715
1716 // Update to a new version with increased permissions.
1717 const std::string version2("2");
1718 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1719 UpdateRequestId(id, version2), testing::_));
1720 UpdatePermissionsTestExtension(id, version2, DISABLED);
1721
1722 // Simulate a custodian approval for re-enabling the extension coming in
1723 // through Sync. Set a newer version than we have installed.
1724 const std::string version3("3");
1725 sync_pb::EntitySpecifics specifics;
1726 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1727 ext_specifics->set_id(id);
1728 ext_specifics->set_enabled(true);
1729 ext_specifics->set_disable_reasons(Extension::DISABLE_NONE);
1730 ext_specifics->set_installed_by_custodian(true);
1731 ext_specifics->set_version(version3);
1732
1733 // This should *not* result in a new permission request.
1734 EXPECT_CALL(*creator, CreateExtensionUpdateRequest(
1735 UpdateRequestId(id, version3), testing::_))
1736 .Times(0);
1737
1738 syncer::SyncData sync_data =
1739 syncer::SyncData::CreateLocalData(id, "Name", specifics);
1740 syncer::SyncChange sync_change(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
1741 sync_data);
1742 syncer::SyncChangeList change_list(1, sync_change);
1743 extension_sync_service()->ProcessSyncChanges(FROM_HERE, change_list);
1744 // The re-enable should be delayed until the extension is updated to the
1745 // matching version.
1746 EXPECT_FALSE(registry()->enabled_extensions().Contains(id));
1747 EXPECT_TRUE(extension_sync_service()->HasPendingReenable(
1748 id, base::Version(version3)));
1749
1750 // Update to the matching version. Now the extension should get enabled.
1751 UpdatePermissionsTestExtension(id, version3, ENABLED);
1752}
1753
1754TEST_F(ExtensionServiceSyncTest, SyncUninstallByCustodianSkipsPolicy) {
1755 InitializeEmptyExtensionService();
1756 extension_sync_service()->MergeDataAndStartSyncing(
1757 syncer::EXTENSIONS,
1758 syncer::SyncDataList(),
1759 scoped_ptr<syncer::SyncChangeProcessor>(
1760 new syncer::FakeSyncChangeProcessor),
1761 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
1762
1763 // Install two extensions.
1764 base::FilePath path1 = data_dir().AppendASCII("good.crx");
1765 base::FilePath path2 = data_dir().AppendASCII("good2048.crx");
1766 const Extension* extensions[] = {
1767 InstallCRX(path1, INSTALL_NEW),
1768 InstallCRX(path2, INSTALL_NEW, Extension::WAS_INSTALLED_BY_CUSTODIAN)
1769 };
1770
1771 // Add a policy provider that will disallow any changes.
1772 extensions::TestManagementPolicyProvider provider(
1773 extensions::TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS);
1774 ExtensionSystem::Get(
1775 browser_context())->management_policy()->RegisterProvider(&provider);
1776
1777 // Create a sync deletion for each extension.
1778 syncer::SyncChangeList change_list;
1779 for (size_t i = 0; i < arraysize(extensions); i++) {
1780 const std::string& id = extensions[i]->id();
1781 sync_pb::EntitySpecifics specifics;
1782 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1783 ext_specifics->set_id(id);
1784 ext_specifics->set_version("1.0");
1785 ext_specifics->set_installed_by_custodian(
1786 extensions[i]->was_installed_by_custodian());
1787 syncer::SyncData sync_data =
1788 syncer::SyncData::CreateLocalData(id, "Name", specifics);
1789 change_list.push_back(syncer::SyncChange(FROM_HERE,
1790 syncer::SyncChange::ACTION_DELETE,
1791 sync_data));
1792 }
1793
1794 // Save the extension ids, as uninstalling destroys the Extension instance.
1795 std::string extension_ids[] = {
1796 extensions[0]->id(),
1797 extensions[1]->id()
1798 };
1799
1800 // Now apply the uninstallations.
1801 extension_sync_service()->ProcessSyncChanges(FROM_HERE, change_list);
1802
1803 // Uninstalling the extension without installed_by_custodian should have been
1804 // blocked by policy, so it should still be there.
1805 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_ids[0]));
1806
1807 // But installed_by_custodian should result in bypassing the policy check.
1808 EXPECT_FALSE(
1809 registry()->GenerateInstalledExtensionsSet()->Contains(extension_ids[1]));
1810}
1811
rdevlin.cronin738501d2015-11-05 21:51:361812TEST_F(ExtensionServiceSyncTest, SyncExtensionHasAllhostsWithheld) {
1813 InitializeEmptyExtensionService();
1814
1815 // Create an extension that needs all-hosts.
1816 const std::string kName("extension");
1817 scoped_refptr<const Extension> extension =
1818 extensions::ExtensionBuilder()
1819 .SetLocation(Manifest::INTERNAL)
1820 .SetManifest(
1821 extensions::DictionaryBuilder()
1822 .Set("name", kName)
1823 .Set("description", "foo")
1824 .Set("manifest_version", 2)
1825 .Set("version", "1.0")
1826 .Set("permissions", extensions::ListBuilder().Append("*://*/*")))
1827 .SetID(crx_file::id_util::GenerateId(kName))
1828 .Build();
1829
1830 // Install and enable it.
1831 service()->AddExtension(extension.get());
1832 service()->GrantPermissionsAndEnableExtension(extension.get());
1833 const std::string id = extension->id();
1834 EXPECT_TRUE(registry()->enabled_extensions().GetByID(id));
1835
1836 // Simulate a sync node coming in where the extension had all-hosts withheld.
1837 // This means that it should have all-hosts withheld on this machine, too.
1838 syncer::SyncChangeList change_list;
1839 sync_pb::EntitySpecifics specifics;
1840 sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
1841 ext_specifics->set_id(id);
1842 ext_specifics->set_name(kName);
1843 ext_specifics->set_version("1.0");
1844 ext_specifics->set_all_urls_enabled(false);
1845 ext_specifics->set_enabled(true);
1846 syncer::SyncData sync_data =
1847 syncer::SyncData::CreateLocalData(id, "Name", specifics);
1848 change_list.push_back(syncer::SyncChange(FROM_HERE,
1849 syncer::SyncChange::ACTION_UPDATE,
1850 sync_data));
1851
1852 extension_sync_service()->ProcessSyncChanges(FROM_HERE, change_list);
1853
1854 EXPECT_TRUE(registry()->enabled_extensions().GetByID(id));
1855 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile()));
1856 EXPECT_TRUE(extensions::util::HasSetAllowedScriptingOnAllUrls(id, profile()));
1857 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile()));
1858}
1859
treib9afc6212015-10-30 18:49:581860#endif // defined(ENABLE_SUPERVISED_USERS)