// Copyright (c) 2012 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/chromeos/settings/device_settings_provider.h" #include <string> #include "base/bind.h" #include "base/callback.h" #include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/scoped_temp_dir.h" #include "base/values.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h" #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" #include "chrome/browser/chromeos/settings/mock_owner_key_util.h" #include "chrome/browser/policy/policy_builder.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_pref_service.h" #include "content/public/test/test_browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace em = enterprise_management; namespace chromeos { using ::testing::AnyNumber; using ::testing::Mock; using ::testing::_; class DeviceSettingsProviderTest: public testing::Test { public: MOCK_METHOD1(SettingChanged, void(const std::string&)); MOCK_METHOD0(GetTrustedCallback, void(void)); protected: DeviceSettingsProviderTest() : message_loop_(MessageLoop::TYPE_UI), ui_thread_(content::BrowserThread::UI, &message_loop_), file_thread_(content::BrowserThread::FILE, &message_loop_), local_state_(static_cast<TestingBrowserProcess*>(g_browser_process)), owner_key_util_(new MockOwnerKeyUtil()) {} virtual void SetUp() OVERRIDE { ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &original_user_data_dir_)); ASSERT_TRUE(user_data_dir_.CreateUniqueTempDir()); ASSERT_TRUE(PathService::Override(chrome::DIR_USER_DATA, user_data_dir_.path())); policy_.payload().mutable_metrics_enabled()->set_metrics_enabled(false); policy_.Build(); device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); device_settings_service_.Initialize(&device_settings_test_helper_, owner_key_util_); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); provider_.reset( new DeviceSettingsProvider( base::Bind(&DeviceSettingsProviderTest::SettingChanged, base::Unretained(this)), &device_settings_service_)); Mock::VerifyAndClearExpectations(this); } virtual void TearDown() OVERRIDE { device_settings_service_.Shutdown(); ASSERT_TRUE(PathService::Override(chrome::DIR_USER_DATA, original_user_data_dir_)); } MessageLoop message_loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; ScopedStubCrosEnabler stub_cros_enabler_; ScopedTestingLocalState local_state_; DeviceSettingsTestHelper device_settings_test_helper_; scoped_refptr<MockOwnerKeyUtil> owner_key_util_; DeviceSettingsService device_settings_service_; policy::DevicePolicyBuilder policy_; scoped_ptr<DeviceSettingsProvider> provider_; ScopedTempDir user_data_dir_; FilePath original_user_data_dir_; private: DISALLOW_COPY_AND_ASSIGN(DeviceSettingsProviderTest); }; TEST_F(DeviceSettingsProviderTest, InitializationTest) { owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); // Have the service load a settings blob. EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); device_settings_service_.Load(); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(this); // Verify that the policy blob has been correctly parsed and trusted. // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, provider_->PrepareTrustedValues(base::Closure())); const base::Value* value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(value); bool bool_value; EXPECT_TRUE(value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } TEST_F(DeviceSettingsProviderTest, InitializationTestUnowned) { // Have the service check the key. device_settings_service_.Load(); device_settings_test_helper_.Flush(); // The trusted flag should be set before the call to PrepareTrustedValues. EXPECT_EQ(CrosSettingsProvider::TRUSTED, provider_->PrepareTrustedValues(base::Closure())); const base::Value* value = provider_->Get(kReleaseChannel); ASSERT_TRUE(value); std::string string_value; EXPECT_TRUE(value->GetAsString(&string_value)); EXPECT_TRUE(string_value.empty()); // Sets should succeed though and be readable from the cache. EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kReleaseChannel)).Times(1); base::StringValue new_value("stable-channel"); provider_->Set(kReleaseChannel, new_value); Mock::VerifyAndClearExpectations(this); // This shouldn't trigger a write. device_settings_test_helper_.set_policy_blob(std::string()); device_settings_test_helper_.Flush(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify the change has been applied. const base::Value* saved_value = provider_->Get(kReleaseChannel); ASSERT_TRUE(saved_value); EXPECT_TRUE(saved_value->GetAsString(&string_value)); ASSERT_EQ("stable-channel", string_value); } TEST_F(DeviceSettingsProviderTest, SetPrefFailed) { // If we are not the owner no sets should work. owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); base::FundamentalValue value(true); EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); provider_->Set(kStatsReportingPref, value); Mock::VerifyAndClearExpectations(this); // This shouldn't trigger a write. device_settings_test_helper_.set_policy_blob(std::string()); device_settings_test_helper_.Flush(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify the change has not been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } TEST_F(DeviceSettingsProviderTest, SetPrefSucceed) { owner_key_util_->SetPrivateKey(policy_.signing_key()); device_settings_service_.SetUsername(policy_.policy_data().username()); device_settings_test_helper_.Flush(); base::FundamentalValue value(true); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1); provider_->Set(kStatsReportingPref, value); Mock::VerifyAndClearExpectations(this); // Process the store. device_settings_test_helper_.set_policy_blob(std::string()); device_settings_test_helper_.Flush(); // Verify that the device policy has been adjusted. ASSERT_TRUE(device_settings_service_.device_settings()); EXPECT_TRUE(device_settings_service_.device_settings()-> metrics_enabled().metrics_enabled()); // Verify the change has been applied. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_TRUE(bool_value); } TEST_F(DeviceSettingsProviderTest, SetPrefTwice) { owner_key_util_->SetPrivateKey(policy_.signing_key()); device_settings_service_.SetUsername(policy_.policy_data().username()); device_settings_test_helper_.Flush(); EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber()); base::StringValue value1("beta"); provider_->Set(kReleaseChannel, value1); base::StringValue value2("dev"); provider_->Set(kReleaseChannel, value2); // Let the changes propagate through the system. device_settings_test_helper_.set_policy_blob(std::string()); device_settings_test_helper_.Flush(); // Verify the second change has been applied. const base::Value* saved_value = provider_->Get(kReleaseChannel); EXPECT_TRUE(value2.Equals(saved_value)); Mock::VerifyAndClearExpectations(this); } TEST_F(DeviceSettingsProviderTest, PolicyRetrievalFailedBadSignature) { owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); policy_.policy().set_policy_data_signature("bad signature"); device_settings_test_helper_.set_policy_blob(policy_.GetBlob()); device_settings_service_.Load(); device_settings_test_helper_.Flush(); // Verify that the cached settings blob is not "trusted". EXPECT_EQ(DeviceSettingsService::STORE_VALIDATION_ERROR, device_settings_service_.status()); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyRetrievalNoPolicy) { owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); device_settings_test_helper_.set_policy_blob(std::string()); device_settings_service_.Load(); device_settings_test_helper_.Flush(); // Verify that the cached settings blob is not "trusted". EXPECT_EQ(DeviceSettingsService::STORE_NO_POLICY, device_settings_service_.status()); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyFailedPermanentlyNotification) { owner_key_util_->SetPublicKeyFromPrivateKey(policy_.signing_key()); device_settings_test_helper_.set_policy_blob(std::string()); EXPECT_CALL(*this, GetTrustedCallback()); EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); device_settings_service_.Load(); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(this); EXPECT_EQ(CrosSettingsProvider::PERMANENTLY_UNTRUSTED, provider_->PrepareTrustedValues(base::Closure())); } TEST_F(DeviceSettingsProviderTest, PolicyLoadNotification) { EXPECT_CALL(*this, GetTrustedCallback()); EXPECT_EQ(CrosSettingsProvider::TEMPORARILY_UNTRUSTED, provider_->PrepareTrustedValues( base::Bind(&DeviceSettingsProviderTest::GetTrustedCallback, base::Unretained(this)))); device_settings_service_.Load(); device_settings_test_helper_.Flush(); Mock::VerifyAndClearExpectations(this); } TEST_F(DeviceSettingsProviderTest, StatsReportingMigration) { // Create the legacy consent file. FilePath consent_file = user_data_dir_.path().AppendASCII("Consent To Send Stats"); ASSERT_EQ(1, file_util::WriteFile(consent_file, "0", 1)); // This should trigger migration because the metrics policy isn't in the blob. device_settings_test_helper_.set_policy_blob(std::string()); device_settings_test_helper_.Flush(); EXPECT_EQ(std::string(), device_settings_test_helper_.policy_blob()); // Verify that migration has kicked in. const base::Value* saved_value = provider_->Get(kStatsReportingPref); ASSERT_TRUE(saved_value); bool bool_value; EXPECT_TRUE(saved_value->GetAsBoolean(&bool_value)); EXPECT_FALSE(bool_value); } } // namespace chromeos