// // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "update_engine/update_manager/real_device_policy_provider.h" #include <memory> #include <vector> #include <base/memory/ptr_util.h> #include <brillo/message_loops/fake_message_loop.h> #include <brillo/message_loops/message_loop.h> #include <brillo/message_loops/message_loop_utils.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <policy/mock_device_policy.h> #include <policy/mock_libpolicy.h> #if USE_DBUS #include <session_manager/dbus-proxies.h> #include <session_manager/dbus-proxy-mocks.h> #endif // USE_DBUS #include "update_engine/common/test_utils.h" #if USE_DBUS #include "update_engine/dbus_test_utils.h" #endif // USE_DBUS #include "update_engine/update_manager/umtest_utils.h" using base::TimeDelta; using brillo::MessageLoop; using chromeos_update_engine::ConnectionType; using policy::DevicePolicy; #if USE_DBUS using chromeos_update_engine::dbus_test_utils::MockSignalHandler; #endif // USE_DBUS using std::set; using std::string; using std::unique_ptr; using std::vector; using testing::_; using testing::DoAll; using testing::Mock; using testing::Return; using testing::ReturnRef; using testing::SetArgPointee; namespace chromeos_update_manager { class UmRealDevicePolicyProviderTest : public ::testing::Test { protected: void SetUp() override { loop_.SetAsCurrent(); #if USE_DBUS auto session_manager_proxy_mock = new org::chromium::SessionManagerInterfaceProxyMock(); provider_.reset(new RealDevicePolicyProvider( base::WrapUnique(session_manager_proxy_mock), &mock_policy_provider_)); #else provider_.reset(new RealDevicePolicyProvider(&mock_policy_provider_)); #endif // USE_DBUS // By default, we have a device policy loaded. Tests can call // SetUpNonExistentDevicePolicy() to override this. SetUpExistentDevicePolicy(); #if USE_DBUS // Setup the session manager_proxy such that it will accept the signal // handler and store it in the |property_change_complete_| once registered. MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER(property_change_complete_, *session_manager_proxy_mock, PropertyChangeComplete); #endif // USE_DBUS } void TearDown() override { provider_.reset(); // Check for leaked callbacks on the main loop. EXPECT_FALSE(loop_.PendingTasks()); } void SetUpNonExistentDevicePolicy() { ON_CALL(mock_policy_provider_, Reload()).WillByDefault(Return(false)); ON_CALL(mock_policy_provider_, device_policy_is_loaded()) .WillByDefault(Return(false)); EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0); } void SetUpExistentDevicePolicy() { // Setup the default behavior of the mocked PolicyProvider. ON_CALL(mock_policy_provider_, Reload()).WillByDefault(Return(true)); ON_CALL(mock_policy_provider_, device_policy_is_loaded()) .WillByDefault(Return(true)); ON_CALL(mock_policy_provider_, GetDevicePolicy()) .WillByDefault(ReturnRef(mock_device_policy_)); } brillo::FakeMessageLoop loop_{nullptr}; testing::NiceMock<policy::MockDevicePolicy> mock_device_policy_; testing::NiceMock<policy::MockPolicyProvider> mock_policy_provider_; unique_ptr<RealDevicePolicyProvider> provider_; #if USE_DBUS // The registered signal handler for the signal. MockSignalHandler<void(const string&)> property_change_complete_; #endif // USE_DBUS }; TEST_F(UmRealDevicePolicyProviderTest, RefreshScheduledTest) { // Check that the RefreshPolicy gets scheduled by checking the TaskId. EXPECT_TRUE(provider_->Init()); EXPECT_NE(MessageLoop::kTaskIdNull, provider_->scheduled_refresh_); loop_.RunOnce(false); } TEST_F(UmRealDevicePolicyProviderTest, FirstReload) { // Checks that the policy is reloaded and the DevicePolicy is consulted twice: // once on Init() and once again when the signal is connected. EXPECT_CALL(mock_policy_provider_, Reload()); EXPECT_TRUE(provider_->Init()); Mock::VerifyAndClearExpectations(&mock_policy_provider_); // We won't be notified that signal is connected without DBus. #if USE_DBUS EXPECT_CALL(mock_policy_provider_, Reload()); #endif // USE_DBUS loop_.RunOnce(false); } TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded) { // Checks that the policy is reloaded by RefreshDevicePolicy(). SetUpNonExistentDevicePolicy(); // We won't be notified that signal is connected without DBus. #if USE_DBUS EXPECT_CALL(mock_policy_provider_, Reload()).Times(3); #else EXPECT_CALL(mock_policy_provider_, Reload()).Times(2); #endif // USE_DBUS EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); // Force the policy refresh. provider_->RefreshDevicePolicy(); } #if USE_DBUS TEST_F(UmRealDevicePolicyProviderTest, SessionManagerSignalForcesReload) { // Checks that a signal from the SessionManager forces a reload. SetUpNonExistentDevicePolicy(); EXPECT_CALL(mock_policy_provider_, Reload()).Times(2); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); Mock::VerifyAndClearExpectations(&mock_policy_provider_); EXPECT_CALL(mock_policy_provider_, Reload()); ASSERT_TRUE(property_change_complete_.IsHandlerRegistered()); property_change_complete_.signal_callback().Run("success"); } #endif // USE_DBUS TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyEmptyVariables) { SetUpNonExistentDevicePolicy(); EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue(false, provider_->var_device_policy_is_loaded()); UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel()); UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel_delegated()); UmTestUtils::ExpectVariableNotSet(provider_->var_update_disabled()); UmTestUtils::ExpectVariableNotSet(provider_->var_target_version_prefix()); UmTestUtils::ExpectVariableNotSet( provider_->var_rollback_to_target_version()); UmTestUtils::ExpectVariableNotSet( provider_->var_rollback_allowed_milestones()); UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor()); UmTestUtils::ExpectVariableNotSet( provider_->var_allowed_connection_types_for_update()); UmTestUtils::ExpectVariableNotSet(provider_->var_owner()); UmTestUtils::ExpectVariableNotSet(provider_->var_http_downloads_enabled()); UmTestUtils::ExpectVariableNotSet(provider_->var_au_p2p_enabled()); UmTestUtils::ExpectVariableNotSet( provider_->var_allow_kiosk_app_control_chrome_version()); UmTestUtils::ExpectVariableNotSet( provider_->var_auto_launched_kiosk_app_id()); UmTestUtils::ExpectVariableNotSet(provider_->var_disallowed_time_intervals()); } TEST_F(UmRealDevicePolicyProviderTest, ValuesUpdated) { SetUpNonExistentDevicePolicy(); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); Mock::VerifyAndClearExpectations(&mock_policy_provider_); // Reload the policy with a good one and set some values as present. The // remaining values are false. SetUpExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetReleaseChannel(_)) .WillOnce(DoAll(SetArgPointee<0>(string("mychannel")), Return(true))); EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_)) .WillOnce(Return(false)); EXPECT_CALL(mock_device_policy_, GetAllowKioskAppControlChromeVersion(_)) .WillOnce(DoAll(SetArgPointee<0>(true), Return(true))); EXPECT_CALL(mock_device_policy_, GetAutoLaunchedKioskAppId(_)) .WillOnce(DoAll(SetArgPointee<0>(string("myapp")), Return(true))); provider_->RefreshDevicePolicy(); UmTestUtils::ExpectVariableHasValue(true, provider_->var_device_policy_is_loaded()); // Test that at least one variable is set, to ensure the refresh occurred. UmTestUtils::ExpectVariableHasValue(string("mychannel"), provider_->var_release_channel()); UmTestUtils::ExpectVariableNotSet( provider_->var_allowed_connection_types_for_update()); UmTestUtils::ExpectVariableHasValue( true, provider_->var_allow_kiosk_app_control_chrome_version()); UmTestUtils::ExpectVariableHasValue( string("myapp"), provider_->var_auto_launched_kiosk_app_id()); } TEST_F(UmRealDevicePolicyProviderTest, RollbackToTargetVersionConverted) { SetUpExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetRollbackToTargetVersion(_)) #if USE_DBUS .Times(2) #else .Times(1) #endif // USE_DBUS .WillRepeatedly(DoAll(SetArgPointee<0>(2), Return(true))); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue( RollbackToTargetVersion::kRollbackAndPowerwash, provider_->var_rollback_to_target_version()); } TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesOobe) { SetUpNonExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0); ON_CALL(mock_policy_provider_, IsConsumerDevice()) .WillByDefault(Return(false)); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableNotSet( provider_->var_rollback_allowed_milestones()); } TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesConsumer) { SetUpNonExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0); ON_CALL(mock_policy_provider_, IsConsumerDevice()) .WillByDefault(Return(true)); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue( 0, provider_->var_rollback_allowed_milestones()); } TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesEnterprisePolicySet) { SetUpExistentDevicePolicy(); ON_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)) .WillByDefault(DoAll(SetArgPointee<0>(2), Return(true))); ON_CALL(mock_policy_provider_, IsConsumerDevice()) .WillByDefault(Return(false)); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue( 2, provider_->var_rollback_allowed_milestones()); } TEST_F(UmRealDevicePolicyProviderTest, ScatterFactorConverted) { SetUpExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_)) #if USE_DBUS .Times(2) #else .Times(1) #endif // USE_DBUS .WillRepeatedly(DoAll(SetArgPointee<0>(1234), Return(true))); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue(TimeDelta::FromSeconds(1234), provider_->var_scatter_factor()); } TEST_F(UmRealDevicePolicyProviderTest, NegativeScatterFactorIgnored) { SetUpExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_)) #if USE_DBUS .Times(2) #else .Times(1) #endif // USE_DBUS .WillRepeatedly(DoAll(SetArgPointee<0>(-1), Return(true))); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor()); } TEST_F(UmRealDevicePolicyProviderTest, AllowedTypesConverted) { SetUpExistentDevicePolicy(); EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_)) #if USE_DBUS .Times(2) #else .Times(1) #endif // USE_DBUS .WillRepeatedly(DoAll( SetArgPointee<0>(set<string>{"bluetooth", "wifi", "not-a-type"}), Return(true))); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue( set<ConnectionType>{ConnectionType::kWifi, ConnectionType::kBluetooth}, provider_->var_allowed_connection_types_for_update()); } TEST_F(UmRealDevicePolicyProviderTest, DisallowedIntervalsConverted) { SetUpExistentDevicePolicy(); vector<DevicePolicy::WeeklyTimeInterval> intervals = { {5, TimeDelta::FromHours(5), 6, TimeDelta::FromHours(8)}, {1, TimeDelta::FromHours(1), 3, TimeDelta::FromHours(10)}}; EXPECT_CALL(mock_device_policy_, GetDisallowedTimeIntervals(_)) .WillRepeatedly(DoAll(SetArgPointee<0>(intervals), Return(true))); EXPECT_TRUE(provider_->Init()); loop_.RunOnce(false); UmTestUtils::ExpectVariableHasValue( WeeklyTimeIntervalVector{ WeeklyTimeInterval(WeeklyTime(5, TimeDelta::FromHours(5)), WeeklyTime(6, TimeDelta::FromHours(8))), WeeklyTimeInterval(WeeklyTime(1, TimeDelta::FromHours(1)), WeeklyTime(3, TimeDelta::FromHours(10)))}, provider_->var_disallowed_time_intervals()); } } // namespace chromeos_update_manager