blob: 5ca5eefb90c2e2800a26c61527d3a381bfe41f9c [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2013 The Chromium Authors
[email protected]8a839a02013-03-07 05:23:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/external_provider_impl.h"
6
dchengc963c7142016-04-08 03:55:227#include <memory>
8
Henrique Ferreiro37770262021-02-06 01:20:539#include "ash/constants/ash_pref_names.h"
[email protected]8a839a02013-03-07 05:23:3310#include "base/command_line.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2611#include "base/memory/ptr_util.h"
Arthur Sonzogni39396932023-04-24 09:41:3312#include "base/memory/raw_ptr.h"
Gabriel Charette078e3662017-08-28 22:59:0413#include "base/run_loop.h"
[email protected]8a839a02013-03-07 05:23:3314#include "base/test/scoped_path_override.h"
Yeunjoo Choi91907642021-04-16 13:18:1915#include "chrome/browser/ash/customization/customization_document.h"
Henrique Ferreiro1ab7f12f2021-03-04 19:54:4016#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
[email protected]f484f8d52014-06-12 08:38:1817#include "chrome/browser/extensions/extension_service.h"
18#include "chrome/browser/extensions/extension_service_test_base.h"
sdefresneed27d86b2015-09-14 11:02:3819#include "chrome/browser/prefs/pref_service_syncable_util.h"
ginkageda30a3b2015-03-12 19:22:1720#include "chrome/browser/profiles/profile_manager.h"
Antonio Gomes3953a3f2018-11-26 19:31:3221#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
[email protected]8a839a02013-03-07 05:23:3322#include "chrome/common/chrome_paths.h"
23#include "chrome/common/chrome_switches.h"
[email protected]94365822014-04-23 14:17:5724#include "chrome/test/base/testing_browser_process.h"
[email protected]8a839a02013-03-07 05:23:3325#include "chrome/test/base/testing_profile.h"
Yeunjoo Choia10bd86e2022-12-15 02:34:5126#include "chromeos/ash/components/system/fake_statistics_provider.h"
27#include "chromeos/ash/components/system/statistics_provider.h"
Victor Hugo Vianna Silvaa48aa01c2022-02-09 20:38:2328#include "components/sync/base/command_line_switches.h"
Roman Sorokin25277a72022-09-21 13:34:0129#include "components/sync/base/model_type.h"
maxbogue2f960e52016-10-07 01:24:1530#include "components/sync/base/pref_names.h"
skym71603842016-10-10 18:17:3131#include "components/sync/model/sync_change_processor.h"
Victor Hugo Vianna Silvac331eeb92022-08-15 20:13:3732#include "components/sync/test/fake_sync_change_processor.h"
maxbogueea16ff412016-10-28 16:35:2933#include "components/sync_preferences/pref_service_syncable.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2634#include "components/user_manager/scoped_user_manager.h"
[email protected]6d057a0c2013-07-09 21:12:0735#include "content/public/test/test_utils.h"
David Bertoni9f897c92019-09-20 17:46:3536#include "extensions/browser/extension_registry.h"
Daniel d'Andrada36b41a72022-10-31 09:59:5637#include "extensions/browser/test_extension_registry_observer.h"
Roman Sorokinc2400cc2021-09-20 21:08:2138#include "testing/gtest/include/gtest/gtest.h"
[email protected]8a839a02013-03-07 05:23:3339
40namespace extensions {
41
42namespace {
43
44const char kExternalAppId[] = "kekdneafjmhmndejhmbcadfiiofngffo";
ginkageda30a3b2015-03-12 19:22:1745const char kStandaloneAppId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
khmelcb892d52018-01-06 03:01:4046const char kStandaloneChildAppId[] = "hcglmfcclpfgljeaiahehebeoaiicbko";
[email protected]8a839a02013-03-07 05:23:3347
Anqing Zhaof0e96fb42020-12-11 23:21:2148const char kTestUserAccount[] = "user@test";
49
[email protected]e1d2ac7a2013-11-14 19:18:2350class ExternalProviderImplChromeOSTest : public ExtensionServiceTestBase {
[email protected]8a839a02013-03-07 05:23:3351 public:
[email protected]f9357a442014-05-15 18:44:0752 ExternalProviderImplChromeOSTest()
Henrique Ferreiro4c2fc0a2021-03-26 10:42:4753 : fake_user_manager_(new ash::FakeChromeUserManager()),
Arthur Sonzogni39396932023-04-24 09:41:3354 scoped_user_manager_(base::WrapUnique(fake_user_manager_.get())) {}
[email protected]f9357a442014-05-15 18:44:0755
Peter Boström53c6c5952021-09-17 09:41:2656 ExternalProviderImplChromeOSTest(const ExternalProviderImplChromeOSTest&) =
57 delete;
58 ExternalProviderImplChromeOSTest& operator=(
59 const ExternalProviderImplChromeOSTest&) = delete;
60
dcheng6d888df2015-01-16 18:12:4861 ~ExternalProviderImplChromeOSTest() override {}
[email protected]8a839a02013-03-07 05:23:3362
ginkageda30a3b2015-03-12 19:22:1763 void InitServiceWithExternalProviders(bool standalone) {
khmelcb892d52018-01-06 03:01:4064 InitServiceWithExternalProvidersAndUserType(standalone,
65 false /* is_child */);
66 }
67
68 void InitServiceWithExternalProvidersAndUserType(bool standalone,
69 bool is_child) {
[email protected]8a839a02013-03-07 05:23:3370 InitializeEmptyExtensionService();
khmelcb892d52018-01-06 03:01:4071
Edman Anjos0f2ad562023-11-08 10:40:4972 if (is_child) {
Aga Wronska9139e6cb2022-02-11 19:44:2273 profile_->SetIsSupervisedProfile();
Edman Anjos0f2ad562023-11-08 10:40:4974 }
khmelcb892d52018-01-06 03:01:4075
[email protected]8a839a02013-03-07 05:23:3376 service_->Init();
77
ginkageda30a3b2015-03-12 19:22:1778 if (standalone) {
Peter Boström6b701822021-04-15 03:53:0879 external_externsions_overrides_ =
80 std::make_unique<base::ScopedPathOverride>(
81 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
82 data_dir().Append("external_standalone"));
ginkageda30a3b2015-03-12 19:22:1783 } else {
Peter Boström6b701822021-04-15 03:53:0884 external_externsions_overrides_ =
85 std::make_unique<base::ScopedPathOverride>(
86 chrome::DIR_EXTERNAL_EXTENSIONS, data_dir().Append("external"));
ginkageda30a3b2015-03-12 19:22:1787 }
88
Glen Robertsonafe91c7e2022-10-21 01:06:2489 // This switch is set when creating a TestingProfile, but needs to be
90 // removed for some ExternalProviders to be created.
91 base::CommandLine::ForCurrentProcess()->RemoveSwitch(
92 switches::kDisableDefaultApps);
93
[email protected]8a839a02013-03-07 05:23:3394 ProviderCollection providers;
Emilia Paz2342695f2023-11-21 18:40:0695 ExternalProviderImpl::CreateExternalProviders(service_, profile_.get(),
96 &providers);
[email protected]8a839a02013-03-07 05:23:3397
Edman Anjos0f2ad562023-11-08 10:40:4998 for (std::unique_ptr<ExternalProviderInterface>& provider : providers) {
lazyboyf33109d2016-08-31 00:37:0899 service_->AddProviderForTesting(std::move(provider));
Edman Anjos0f2ad562023-11-08 10:40:49100 }
[email protected]8a839a02013-03-07 05:23:33101 }
102
103 // ExtensionServiceTestBase overrides:
Edman Anjos0f2ad562023-11-08 10:40:49104 void SetUp() override { ExtensionServiceTestBase::SetUp(); }
[email protected]8a839a02013-03-07 05:23:33105
dcheng6d888df2015-01-16 18:12:48106 void TearDown() override {
Jay Civellie8323f732018-01-24 23:01:25107 // If some extensions are being installed (on a background thread) and we
108 // stop before the intsallation is complete, some installation related
109 // objects might be leaked (as the background thread won't block on exit and
110 // finish cleanly).
111 // So ensure we let pending extension installations finish.
112 WaitForPendingStandaloneExtensionsInstalled();
Christian Dullweber64d38d082018-02-02 14:06:31113 ExtensionServiceTestBase::TearDown();
[email protected]f0aaf2c2014-03-07 01:12:23114 }
115
khmelcb892d52018-01-06 03:01:40116 // Waits until all possible standalone extensions are installed.
117 void WaitForPendingStandaloneExtensionsInstalled() {
118 service_->CheckForExternalUpdates();
119 base::RunLoop().RunUntilIdle();
Emilia Paz2342695f2023-11-21 18:40:06120 PendingExtensionManager* const pending_extension_manager =
khmelcb892d52018-01-06 03:01:40121 service_->pending_extension_manager();
122 while (pending_extension_manager->IsIdPending(kStandaloneAppId) ||
123 pending_extension_manager->IsIdPending(kStandaloneChildAppId)) {
124 base::RunLoop().RunUntilIdle();
125 }
126 }
127
amraboelkher359f8732022-03-01 15:31:37128 void ValidateExternalProviderCountInAppMode(size_t expected_count) {
Anqing Zhaof0e96fb42020-12-11 23:21:21129 base::CommandLine* command = base::CommandLine::ForCurrentProcess();
130 command->AppendSwitchASCII(switches::kForceAppMode, std::string());
131 command->AppendSwitchASCII(switches::kAppId, std::string("app_id"));
132
133 InitializeEmptyExtensionService();
134
135 ProviderCollection providers;
Emilia Paz2342695f2023-11-21 18:40:06136 ExternalProviderImpl::CreateExternalProviders(service_, profile_.get(),
137 &providers);
Anqing Zhaof0e96fb42020-12-11 23:21:21138
139 EXPECT_EQ(providers.size(), expected_count);
140 }
141
Henrique Ferreiro4c2fc0a2021-03-26 10:42:47142 ash::FakeChromeUserManager* fake_user_manager() const {
Anqing Zhaof0e96fb42020-12-11 23:21:21143 return fake_user_manager_;
144 }
145
[email protected]8a839a02013-03-07 05:23:33146 private:
dchengc963c7142016-04-08 03:55:22147 std::unique_ptr<base::ScopedPathOverride> external_externsions_overrides_;
Yeunjoo Choi462896712022-12-20 01:15:40148 ash::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
Arthur Sonzogniebfd4c12023-08-18 08:03:35149 raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
150 fake_user_manager_;
Xiyuan Xiadfe3a9f2017-11-13 21:46:26151 user_manager::ScopedUserManager scoped_user_manager_;
[email protected]8a839a02013-03-07 05:23:33152};
153
154} // namespace
155
156// Normal mode, external app should be installed.
[email protected]e1d2ac7a2013-11-14 19:18:23157TEST_F(ExternalProviderImplChromeOSTest, Normal) {
ginkageda30a3b2015-03-12 19:22:17158 InitServiceWithExternalProviders(false);
[email protected]8a839a02013-03-07 05:23:33159
Elly Fong-Jonesbb330bc2023-07-20 23:44:18160 TestExtensionRegistryObserver observer(registry(), kExternalAppId);
[email protected]8a839a02013-03-07 05:23:33161
Daniel d'Andrada36b41a72022-10-31 09:59:56162 service_->CheckForExternalUpdates();
163
164 scoped_refptr<const Extension> loaded_extension =
165 observer.WaitForExtensionLoaded();
166
167 EXPECT_EQ(loaded_extension->id(), kExternalAppId);
[email protected]8a839a02013-03-07 05:23:33168}
169
170// App mode, no external app should be installed.
[email protected]e1d2ac7a2013-11-14 19:18:23171TEST_F(ExternalProviderImplChromeOSTest, AppMode) {
avi3ef9ec9e2014-12-22 22:50:17172 base::CommandLine* command = base::CommandLine::ForCurrentProcess();
[email protected]8a839a02013-03-07 05:23:33173 command->AppendSwitchASCII(switches::kForceAppMode, std::string());
174 command->AppendSwitchASCII(switches::kAppId, std::string("app_id"));
175
ginkageda30a3b2015-03-12 19:22:17176 InitServiceWithExternalProviders(false);
[email protected]8a839a02013-03-07 05:23:33177
178 service_->CheckForExternalUpdates();
[email protected]eedc1c752013-08-09 18:51:55179 base::RunLoop().RunUntilIdle();
[email protected]8a839a02013-03-07 05:23:33180
David Bertoni9f897c92019-09-20 17:46:35181 EXPECT_FALSE(registry()->GetInstalledExtension(kExternalAppId));
[email protected]8a839a02013-03-07 05:23:33182}
183
ginkageda30a3b2015-03-12 19:22:17184// Normal mode, standalone app should be installed, because sync is enabled but
185// not running.
Steven Holtee104d492018-06-19 20:24:31186// flaky: crbug.com/854206
187TEST_F(ExternalProviderImplChromeOSTest, DISABLED_Standalone) {
ginkageda30a3b2015-03-12 19:22:17188 InitServiceWithExternalProviders(true);
189
khmelcb892d52018-01-06 03:01:40190 WaitForPendingStandaloneExtensionsInstalled();
ginkageda30a3b2015-03-12 19:22:17191
David Bertoni9f897c92019-09-20 17:46:35192 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneAppId));
khmelcb892d52018-01-06 03:01:40193 // Also include apps available for child.
David Bertoni9f897c92019-09-20 17:46:35194 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneChildAppId));
khmelcb892d52018-01-06 03:01:40195}
196
197// Should include only subset of default apps
Steven Holtee104d492018-06-19 20:24:31198// flaky: crbug.com/854206
199TEST_F(ExternalProviderImplChromeOSTest, DISABLED_StandaloneChild) {
khmelcb892d52018-01-06 03:01:40200 InitServiceWithExternalProvidersAndUserType(true /* standalone */,
201 true /* is_child */);
202
203 WaitForPendingStandaloneExtensionsInstalled();
204
205 // kStandaloneAppId is not available for child.
David Bertoni9f897c92019-09-20 17:46:35206 EXPECT_FALSE(registry()->GetInstalledExtension(kStandaloneAppId));
207 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneChildAppId));
ginkageda30a3b2015-03-12 19:22:17208}
209
210// Normal mode, standalone app should be installed, because sync is disabled.
Daniel d'Andrada36b41a72022-10-31 09:59:56211TEST_F(ExternalProviderImplChromeOSTest, SyncDisabled) {
Victor Hugo Vianna Silva3cd7ae92022-02-09 20:49:51212 base::CommandLine::ForCurrentProcess()->AppendSwitch(syncer::kDisableSync);
ginkageda30a3b2015-03-12 19:22:17213
214 InitServiceWithExternalProviders(true);
215
Elly Fong-Jonesbb330bc2023-07-20 23:44:18216 TestExtensionRegistryObserver observer(registry(), kStandaloneAppId);
ginkageda30a3b2015-03-12 19:22:17217
Daniel d'Andrada36b41a72022-10-31 09:59:56218 service_->CheckForExternalUpdates();
219
220 scoped_refptr<const Extension> loaded_extension =
221 observer.WaitForExtensionLoaded();
222 EXPECT_EQ(loaded_extension->id(), kStandaloneAppId);
David Bertoni9f897c92019-09-20 17:46:35223 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneAppId));
ginkageda30a3b2015-03-12 19:22:17224}
225
226// User signed in, sync service started, install app when sync is disabled by
227// policy.
Daniel d'Andrada36b41a72022-10-31 09:59:56228TEST_F(ExternalProviderImplChromeOSTest, PolicyDisabled) {
ginkageda30a3b2015-03-12 19:22:17229 InitServiceWithExternalProviders(true);
230
231 // Log user in, start sync.
232 TestingBrowserProcess::GetGlobal()->SetProfileManager(
Alex Ilin036866e2021-04-22 18:40:49233 std::make_unique<ProfileManagerWithoutInit>(temp_dir().GetPath()));
Antonio Gomes3953a3f2018-11-26 19:31:32234
235 auto identity_test_env_profile_adaptor =
236 std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
237 identity_test_env_profile_adaptor->identity_test_env()
Tanmoy Mollikaa34c122021-06-04 13:12:29238 ->MakePrimaryAccountAvailable("[email protected]",
239 signin::ConsentLevel::kSync);
ginkageda30a3b2015-03-12 19:22:17240
ginkageda30a3b2015-03-12 19:22:17241 // Sync is dsabled by policy.
Marc Treib3d2c9c62023-05-12 14:48:59242 profile_->GetPrefs()->SetBoolean(syncer::prefs::internal::kSyncManaged, true);
ginkageda30a3b2015-03-12 19:22:17243
Elly Fong-Jonesbb330bc2023-07-20 23:44:18244 TestExtensionRegistryObserver observer(registry(), kStandaloneAppId);
ginkageda30a3b2015-03-12 19:22:17245
Daniel d'Andrada36b41a72022-10-31 09:59:56246 // App sync will wait for priority sync to complete.
247 service_->CheckForExternalUpdates();
248
249 scoped_refptr<const Extension> loaded_extension =
250 observer.WaitForExtensionLoaded();
251 EXPECT_EQ(loaded_extension->id(), kStandaloneAppId);
David Bertoni9f897c92019-09-20 17:46:35252 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneAppId));
ginkageda30a3b2015-03-12 19:22:17253
Alex Ilin036866e2021-04-22 18:40:49254 TestingBrowserProcess::GetGlobal()->SetProfileManager(nullptr);
ginkageda30a3b2015-03-12 19:22:17255}
256
257// User signed in, sync service started, install app when priority sync is
258// completed.
Daniel d'Andrada36b41a72022-10-31 09:59:56259TEST_F(ExternalProviderImplChromeOSTest, PriorityCompleted) {
ginkageda30a3b2015-03-12 19:22:17260 InitServiceWithExternalProviders(true);
261
262 // User is logged in.
Antonio Gomes3953a3f2018-11-26 19:31:32263 auto identity_test_env_profile_adaptor =
264 std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
265 identity_test_env_profile_adaptor->identity_test_env()->SetPrimaryAccount(
Tanmoy Mollikac233b042021-05-22 12:17:47266 "[email protected]", signin::ConsentLevel::kSync);
ginkageda30a3b2015-03-12 19:22:17267
James Cookb322e082020-05-27 16:29:11268 // OOBE screen completed with OS sync enabled.
269 PrefService* prefs = profile()->GetPrefs();
Yeunjoo Choi0c8273a2022-11-29 04:22:50270 prefs->SetBoolean(ash::prefs::kSyncOobeCompleted, true);
James Cookb322e082020-05-27 16:29:11271
Elly Fong-Jonesbb330bc2023-07-20 23:44:18272 TestExtensionRegistryObserver observer(registry(), kStandaloneAppId);
ginkageda30a3b2015-03-12 19:22:17273
274 // Priority sync completed.
James Cookb322e082020-05-27 16:29:11275 PrefServiceSyncableFromProfile(profile())
Roman Sorokin25277a72022-09-21 13:34:01276 ->GetSyncableService(syncer::OS_PRIORITY_PREFERENCES)
James Cookb322e082020-05-27 16:29:11277 ->MergeDataAndStartSyncing(
Roman Sorokin25277a72022-09-21 13:34:01278 syncer::OS_PRIORITY_PREFERENCES, syncer::SyncDataList(),
Marc Treib7bf627d2023-01-18 18:17:56279 std::make_unique<syncer::FakeSyncChangeProcessor>());
ginkageda30a3b2015-03-12 19:22:17280
Daniel d'Andrada36b41a72022-10-31 09:59:56281 // App sync will wait for priority sync to complete.
282 service_->CheckForExternalUpdates();
ginkageda30a3b2015-03-12 19:22:17283
Daniel d'Andrada36b41a72022-10-31 09:59:56284 scoped_refptr<const Extension> loaded_extension =
285 observer.WaitForExtensionLoaded();
286 EXPECT_EQ(loaded_extension->id(), kStandaloneAppId);
David Bertoni9f897c92019-09-20 17:46:35287 EXPECT_TRUE(registry()->GetInstalledExtension(kStandaloneAppId));
ginkageda30a3b2015-03-12 19:22:17288}
289
Anqing Zhaof0e96fb42020-12-11 23:21:21290// Validate the external providers enabled in the Chrome App Kiosk session. The
291// expected number should be 3.
292// - |policy_provider|.
293// - |kiosk_app_provider|.
294// - |secondary_kiosk_app_provider|.
295TEST_F(ExternalProviderImplChromeOSTest, ChromeAppKiosk) {
296 const AccountId kiosk_account_id(AccountId::FromUserEmail(kTestUserAccount));
297 fake_user_manager()->AddKioskAppUser(kiosk_account_id);
298 fake_user_manager()->LoginUser(kiosk_account_id);
299
amraboelkher359f8732022-03-01 15:31:37300 ValidateExternalProviderCountInAppMode(3u);
Anqing Zhaof0e96fb42020-12-11 23:21:21301}
302
303// Validate the external providers enabled in the ARC++ App Kiosk session. The
304// expected number should be only 1.
305// - |policy_provider|.
306TEST_F(ExternalProviderImplChromeOSTest, ArcAppKiosk) {
307 const AccountId kiosk_account_id(AccountId::FromUserEmail(kTestUserAccount));
308 fake_user_manager()->AddArcKioskAppUser(kiosk_account_id);
309 fake_user_manager()->LoginUser(kiosk_account_id);
310
amraboelkher359f8732022-03-01 15:31:37311 ValidateExternalProviderCountInAppMode(1u);
Anqing Zhaof0e96fb42020-12-11 23:21:21312}
313
314// Validate the external providers enabled in the Web App Kiosk session. The
315// expected number should be only 1.
316// - |policy_provider|.
317TEST_F(ExternalProviderImplChromeOSTest, WebAppKiosk) {
318 const AccountId kiosk_account_id(AccountId::FromUserEmail(kTestUserAccount));
319 fake_user_manager()->AddWebKioskAppUser(kiosk_account_id);
320 fake_user_manager()->LoginUser(kiosk_account_id);
321
amraboelkher359f8732022-03-01 15:31:37322 ValidateExternalProviderCountInAppMode(1u);
Anqing Zhaof0e96fb42020-12-11 23:21:21323}
324
[email protected]8a839a02013-03-07 05:23:33325} // namespace extensions