blob: 821a34862dd953aef93e6b893c7cbe6b6d4b54a8 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/external_pref_loader.h"
#include <memory>
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/external_provider_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/sync/test/model/fake_sync_change_processor.h"
#include "components/sync/test/model/sync_error_factory_mock.h"
#include "components/sync_preferences/pref_model_associator.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/common/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
using extensions::mojom::ManifestLocation;
namespace extensions {
namespace {
class TestSyncService : public syncer::TestSyncService {
public:
TestSyncService() {}
~TestSyncService() override {}
// syncer::SyncService:
void AddObserver(syncer::SyncServiceObserver* observer) override {
ASSERT_FALSE(observer_);
observer_ = observer;
}
void RemoveObserver(syncer::SyncServiceObserver* observer) override {
EXPECT_EQ(observer_, observer);
}
void FireOnStateChanged() {
ASSERT_TRUE(observer_);
observer_->OnStateChanged(this);
}
private:
syncer::SyncServiceObserver* observer_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestSyncService);
};
std::unique_ptr<KeyedService> TestingSyncFactoryFunction(
content::BrowserContext* context) {
return std::make_unique<TestSyncService>();
}
} // namespace
// Test version of ExternalPrefLoader that doesn't do any IO.
class TestExternalPrefLoader : public ExternalPrefLoader {
public:
TestExternalPrefLoader(Profile* profile, base::OnceClosure load_callback)
: ExternalPrefLoader(
// Invalid value, doesn't matter since it's not used.
-1,
// Make sure ExternalPrefLoader waits for priority sync.
ExternalPrefLoader::DELAY_LOAD_UNTIL_PRIORITY_SYNC,
profile),
load_callback_(std::move(load_callback)) {}
void LoadOnFileThread() override {
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
std::move(load_callback_));
}
private:
~TestExternalPrefLoader() override {}
base::OnceClosure load_callback_;
DISALLOW_COPY_AND_ASSIGN(TestExternalPrefLoader);
};
class ExternalPrefLoaderTest : public testing::Test {
public:
ExternalPrefLoaderTest() {}
~ExternalPrefLoaderTest() override {}
void SetUp() override {
profile_ = std::make_unique<TestingProfile>();
sync_service_ = static_cast<TestSyncService*>(
ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), base::BindRepeating(&TestingSyncFactoryFunction)));
sync_service_->SetFirstSetupComplete(true);
}
void TearDown() override { profile_.reset(); }
TestingProfile* profile() { return profile_.get(); }
TestSyncService* sync_service() { return sync_service_; }
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> profile_;
TestSyncService* sync_service_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ExternalPrefLoaderTest);
};
// TODO(lazyboy): Add a test to cover
// PrioritySyncReadyWaiter::OnIsSyncingChanged().
// Tests that we fire pref reading correctly after priority sync state
// is resolved by ExternalPrefLoader.
TEST_F(ExternalPrefLoaderTest, PrefReadInitiatesCorrectly) {
// This test is only relevant pre-SplitSettingsSync.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(chromeos::features::kSplitSettingsSync);
base::RunLoop run_loop;
scoped_refptr<ExternalPrefLoader> loader(
new TestExternalPrefLoader(profile(), run_loop.QuitWhenIdleClosure()));
ExternalProviderImpl provider(
nullptr, loader, profile(), ManifestLocation::kInvalidLocation,
ManifestLocation::kInvalidLocation, Extension::NO_FLAGS);
provider.VisitRegisteredExtension();
// Initially CanSyncFeatureStart() returns true, returning false will let
// |loader| proceed.
sync_service()->SetDisableReasons(
syncer::SyncService::DISABLE_REASON_USER_CHOICE);
ASSERT_FALSE(sync_service()->CanSyncFeatureStart());
sync_service()->FireOnStateChanged();
run_loop.Run();
}
class ExternalPrefLoaderSplitSettingsSyncTest : public ExternalPrefLoaderTest {
public:
ExternalPrefLoaderSplitSettingsSyncTest() {
feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettingsSync);
}
~ExternalPrefLoaderSplitSettingsSyncTest() override = default;
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_F(ExternalPrefLoaderSplitSettingsSyncTest, OsSyncEnabled) {
base::RunLoop run_loop;
scoped_refptr<ExternalPrefLoader> loader =
base::MakeRefCounted<TestExternalPrefLoader>(
profile(), run_loop.QuitWhenIdleClosure());
ExternalProviderImpl provider(
/*service=*/nullptr, loader, profile(),
ManifestLocation::kInvalidLocation, ManifestLocation::kInvalidLocation,
Extension::NO_FLAGS);
provider.VisitRegisteredExtension();
PrefService* prefs = profile()->GetPrefs();
ASSERT_FALSE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
// Simulate OOBE screen completion with OS sync enabled.
sync_service()->GetUserSettings()->SetOsSyncFeatureEnabled(true);
prefs->SetBoolean(chromeos::prefs::kSyncOobeCompleted, true);
// Simulate OS prefs starting to sync.
sync_preferences::PrefServiceSyncable* pref_sync =
profile()->GetTestingPrefService();
// This is an ugly cast, but it's how other tests do it.
sync_preferences::PrefModelAssociator* pref_sync_service =
static_cast<sync_preferences::PrefModelAssociator*>(
pref_sync->GetSyncableService(syncer::OS_PRIORITY_PREFERENCES));
pref_sync_service->MergeDataAndStartSyncing(
syncer::OS_PRIORITY_PREFERENCES, syncer::SyncDataList(),
std::make_unique<syncer::FakeSyncChangeProcessor>(),
std::make_unique<syncer::SyncErrorFactoryMock>());
run_loop.Run();
// |loader| completed loading.
}
TEST_F(ExternalPrefLoaderSplitSettingsSyncTest, OsSyncDisable) {
base::RunLoop run_loop;
scoped_refptr<ExternalPrefLoader> loader =
base::MakeRefCounted<TestExternalPrefLoader>(
profile(), run_loop.QuitWhenIdleClosure());
ExternalProviderImpl provider(
/*service=*/nullptr, loader, profile(),
ManifestLocation::kInvalidLocation, ManifestLocation::kInvalidLocation,
Extension::NO_FLAGS);
provider.VisitRegisteredExtension();
PrefService* prefs = profile()->GetPrefs();
ASSERT_FALSE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
// Simulate OOBE screen completion with OS sync disabled.
sync_service()->GetUserSettings()->SetOsSyncFeatureEnabled(false);
prefs->SetBoolean(chromeos::prefs::kSyncOobeCompleted, true);
// Loader doesn't need to wait, since OS pref sync is disabled.
run_loop.Run();
// |loader| completed loading.
}
TEST_F(ExternalPrefLoaderSplitSettingsSyncTest, SyncDisabledByPolicy) {
sync_service()->SetDisableReasons(
syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
ASSERT_FALSE(sync_service()->CanSyncFeatureStart());
base::RunLoop run_loop;
scoped_refptr<ExternalPrefLoader> loader =
base::MakeRefCounted<TestExternalPrefLoader>(
profile(), run_loop.QuitWhenIdleClosure());
ExternalProviderImpl provider(
/*service=*/nullptr, loader, profile(),
ManifestLocation::kInvalidLocation, ManifestLocation::kInvalidLocation,
Extension::NO_FLAGS);
provider.VisitRegisteredExtension();
// Loader doesn't need to wait, because sync will never enable.
run_loop.Run();
// |loader| completed loading.
}
} // namespace extensions