| // Copyright (c) 2012 The Chromium OS 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 "login_manager/session_manager_impl.h" |
| |
| #include <fcntl.h> |
| #include <keyutils.h> |
| #include <stdint.h> |
| #include <sys/socket.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <algorithm> |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <base/command_line.h> |
| #include <base/compiler_specific.h> |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_file.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/memory/ptr_util.h> |
| #include <base/memory/ref_counted.h> |
| #include <base/memory/weak_ptr.h> |
| #include <base/task/single_thread_task_executor.h> |
| #include <base/optional.h> |
| #include <base/run_loop.h> |
| #include <base/strings/string_util.h> |
| #include <base/test/simple_test_tick_clock.h> |
| #include <brillo/cryptohome.h> |
| #include <brillo/dbus/dbus_param_writer.h> |
| #include <brillo/errors/error.h> |
| #include <brillo/message_loops/fake_message_loop.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <crypto/scoped_nss_types.h> |
| #include <dbus/bus.h> |
| #include <dbus/message.h> |
| #include <dbus/mock_exported_object.h> |
| #include <dbus/mock_object_proxy.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <libpasswordprovider/password.h> |
| #include <libpasswordprovider/password_provider.h> |
| |
| #include "bindings/chrome_device_policy.pb.h" |
| #include "bindings/device_management_backend.pb.h" |
| #include "libpasswordprovider/fake_password_provider.h" |
| #include "login_manager/blob_util.h" |
| #include "login_manager/dbus_test_util.h" |
| #include "login_manager/dbus_util.h" |
| #include "login_manager/device_local_account_manager.h" |
| #include "login_manager/fake_container_manager.h" |
| #include "login_manager/fake_crossystem.h" |
| #include "login_manager/fake_secret_util.h" |
| #include "login_manager/file_checker.h" |
| #include "login_manager/matchers.h" |
| #include "login_manager/mock_arc_sideload_status.h" |
| #include "login_manager/mock_device_policy_service.h" |
| #include "login_manager/mock_file_checker.h" |
| #include "login_manager/mock_init_daemon_controller.h" |
| #include "login_manager/mock_install_attributes_reader.h" |
| #include "login_manager/mock_key_generator.h" |
| #include "login_manager/mock_metrics.h" |
| #include "login_manager/mock_nss_util.h" |
| #include "login_manager/mock_policy_key.h" |
| #include "login_manager/mock_policy_service.h" |
| #include "login_manager/mock_process_manager_service.h" |
| #include "login_manager/mock_server_backed_state_key_generator.h" |
| #include "login_manager/mock_system_utils.h" |
| #include "login_manager/mock_user_policy_service_factory.h" |
| #include "login_manager/mock_vpd_process.h" |
| #include "login_manager/proto_bindings/arc.pb.h" |
| #include "login_manager/proto_bindings/login_screen_storage.pb.h" |
| #include "login_manager/proto_bindings/policy_descriptor.pb.h" |
| #include "login_manager/secret_util.h" |
| #include "login_manager/system_utils_impl.h" |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::AtMost; |
| using ::testing::ByMove; |
| using ::testing::DoAll; |
| using ::testing::ElementsAre; |
| using ::testing::ElementsAreArray; |
| using ::testing::Field; |
| using ::testing::HasSubstr; |
| using ::testing::Invoke; |
| using ::testing::InvokeWithoutArgs; |
| using ::testing::IsEmpty; |
| using ::testing::Matcher; |
| using ::testing::Mock; |
| using ::testing::NotNull; |
| using ::testing::Return; |
| using ::testing::ReturnNull; |
| using ::testing::ReturnRef; |
| using ::testing::SaveArg; |
| using ::testing::SetArgPointee; |
| using ::testing::StartsWith; |
| using ::testing::StrEq; |
| using ::testing::WithArg; |
| |
| using brillo::cryptohome::home::GetRootPath; |
| using brillo::cryptohome::home::kGuestUserName; |
| using brillo::cryptohome::home::SanitizeUserName; |
| using brillo::cryptohome::home::SetSystemSalt; |
| |
| ACTION_TEMPLATE(MovePointee, |
| HAS_1_TEMPLATE_PARAMS(int, k), |
| AND_1_VALUE_PARAMS(pointer)) { |
| *pointer = std::move(*(::std::get<k>(args))); |
| } |
| |
| using std::map; |
| using std::string; |
| using std::vector; |
| |
| namespace em = enterprise_management; |
| |
| namespace login_manager { |
| |
| namespace { |
| |
| // Test Bus instance to inject MockExportedObject. |
| class FakeBus : public dbus::Bus { |
| public: |
| FakeBus() |
| : dbus::Bus(GetBusOptions()), |
| exported_object_(new dbus::MockExportedObject( |
| nullptr, dbus::ObjectPath("/fake/path"))) {} |
| |
| dbus::MockExportedObject* exported_object() { return exported_object_.get(); } |
| |
| // dbus::Bus overrides. |
| dbus::ExportedObject* GetExportedObject( |
| const dbus::ObjectPath& object_path) override { |
| return exported_object_.get(); |
| } |
| |
| bool RequestOwnershipAndBlock(const std::string& service_name, |
| ServiceOwnershipOptions options) override { |
| return true; // Fake to success. |
| } |
| |
| protected: |
| // dbus::Bus is refcounted object. |
| ~FakeBus() override = default; |
| |
| private: |
| scoped_refptr<dbus::MockExportedObject> exported_object_; |
| |
| static dbus::Bus::Options GetBusOptions() { |
| dbus::Bus::Options options; |
| options.bus_type = dbus::Bus::SYSTEM; |
| return options; |
| } |
| }; |
| |
| // Storing T value. Iff T is const char*, instead std::string value. |
| template <typename T> |
| struct PayloadStorage { |
| // gtest/gmock 1.8.1 and later add an extra const that needs to be stripped. |
| typename std::remove_const<T>::type value; |
| }; |
| |
| // For gtest/gmock < 1.8.1 |
| template <> |
| struct PayloadStorage<const char*> { |
| std::string value; |
| }; |
| |
| // For gtest/gmock >= 1.8.1 |
| template <> |
| struct PayloadStorage<const char* const> { |
| std::string value; |
| }; |
| |
| #if USE_CHEETS |
| // For gtest/gmock < 1.8.1 |
| template <> |
| struct PayloadStorage<ArcContainerStopReason> { |
| uint32_t value; |
| }; |
| |
| // For gtest/gmock >= 1.8.1 |
| template <> |
| struct PayloadStorage<const ArcContainerStopReason> { |
| uint32_t value; |
| }; |
| |
| // Overloading for easier payload test in MATCHERs. |
| bool operator==(ArcContainerStopReason payload, uint32_t value) { |
| return static_cast<uint32_t>(payload) == value; |
| } |
| #endif |
| |
| // Matcher for SessionManagerInterface's signal. |
| MATCHER_P(SignalEq, method_name, "") { |
| return arg->GetMember() == method_name; |
| } |
| |
| MATCHER_P2(SignalEq, method_name, payload1, "") { |
| PayloadStorage<decltype(payload1)> actual1; |
| dbus::MessageReader reader(arg); |
| return (arg->GetMember() == method_name && |
| brillo::dbus_utils::PopValueFromReader(&reader, &actual1.value) && |
| payload1 == actual1.value); |
| } |
| |
| MATCHER_P3(SignalEq, method_name, payload1, payload2, "") { |
| PayloadStorage<decltype(payload1)> actual1; |
| PayloadStorage<decltype(payload2)> actual2; |
| dbus::MessageReader reader(arg); |
| return (arg->GetMember() == method_name && |
| brillo::dbus_utils::PopValueFromReader(&reader, &actual1.value) && |
| payload1 == actual1.value && |
| brillo::dbus_utils::PopValueFromReader(&reader, &actual2.value) && |
| payload2 == actual2.value); |
| } |
| |
| // Checks whether a PolicyNamespace is not a POLICY_DOMAIN_CHROME namespace and |
| // has a component id. |
| MATCHER(IsComponentNamespace, "") { |
| return arg.first != POLICY_DOMAIN_CHROME && !arg.second.empty(); |
| } |
| |
| // Checks whether the PK11SlotDescriptor object includes a given PK11SlotInfo |
| // object. |
| MATCHER_P(IncludesSlot, slot, "") { |
| return arg->slot.get() == slot; |
| } |
| |
| constexpr pid_t kAndroidPid = 10; |
| |
| constexpr char kSaneEmail[] = "user@somewhere.com"; |
| constexpr char kDeviceLocalAccountsDir[] = "device_local_accounts"; |
| constexpr char kLoginScreenStoragePath[] = "login_screen_storage"; |
| |
| #if USE_CHEETS |
| constexpr char kDefaultLocale[] = "en_US"; |
| |
| UpgradeArcContainerRequest CreateUpgradeArcContainerRequest() { |
| UpgradeArcContainerRequest request; |
| request.set_account_id(kSaneEmail); |
| request.set_locale(kDefaultLocale); |
| return request; |
| } |
| #endif |
| |
| constexpr char kEmptyAccountId[] = ""; |
| |
| std::vector<uint8_t> MakePolicyDescriptor(PolicyAccountType account_type, |
| const std::string& account_id) { |
| PolicyDescriptor descriptor; |
| descriptor.set_account_type(account_type); |
| descriptor.set_account_id(account_id); |
| descriptor.set_domain(POLICY_DOMAIN_CHROME); |
| return StringToBlob(descriptor.SerializeAsString()); |
| } |
| |
| std::vector<uint8_t> MakeLoginScreenStorageMetadata( |
| bool clear_on_session_exit) { |
| LoginScreenStorageMetadata metadata; |
| metadata.set_clear_on_session_exit(clear_on_session_exit); |
| return StringToBlob(metadata.SerializeAsString()); |
| } |
| |
| #if USE_CHEETS |
| std::string ExpectedSkipPackagesCacheSetupFlagValue(bool enabled) { |
| return base::StringPrintf("SKIP_PACKAGES_CACHE_SETUP=%d", enabled); |
| } |
| |
| std::string ExpectedCopyPackagesCacheFlagValue(bool enabled) { |
| return base::StringPrintf("COPY_PACKAGES_CACHE=%d", enabled); |
| } |
| |
| std::string ExpectedSkipGmsCoreCacheSetupFlagValue(bool enabled) { |
| return base::StringPrintf("SKIP_GMS_CORE_CACHE_SETUP=%d", enabled); |
| } |
| |
| #endif // USE_CHEETS |
| |
| } // namespace |
| |
| class SessionManagerImplTest : public ::testing::Test, |
| public SessionManagerImpl::Delegate { |
| public: |
| SessionManagerImplTest() |
| : bus_(new FakeBus()), |
| state_key_generator_(&utils_, &metrics_), |
| android_container_(kAndroidPid), |
| powerd_proxy_(new dbus::MockObjectProxy( |
| nullptr, "", dbus::ObjectPath("/fake/powerd"))), |
| system_clock_proxy_(new dbus::MockObjectProxy( |
| nullptr, "", dbus::ObjectPath("/fake/clock"))), |
| debugd_proxy_(new dbus::MockObjectProxy( |
| nullptr, "", dbus::ObjectPath("/fake/debugd"))) {} |
| |
| ~SessionManagerImplTest() override = default; |
| |
| void SetUp() override { |
| ON_CALL(utils_, GetDevModeState()) |
| .WillByDefault(Return(DevModeState::DEV_MODE_OFF)); |
| ON_CALL(utils_, GetVmState()).WillByDefault(Return(VmState::OUTSIDE_VM)); |
| |
| // Forward file operation calls to |real_utils_| so that the tests can |
| // actually create/modify/delete files in |tmpdir_|. |
| ON_CALL(utils_, EnsureAndReturnSafeFileSize(_, _)) |
| .WillByDefault(Invoke(&real_utils_, |
| &SystemUtilsImpl::EnsureAndReturnSafeFileSize)); |
| ON_CALL(utils_, Exists(_)) |
| .WillByDefault(Invoke(&real_utils_, &SystemUtilsImpl::Exists)); |
| ON_CALL(utils_, DirectoryExists(_)) |
| .WillByDefault(Invoke(&real_utils_, &SystemUtilsImpl::DirectoryExists)); |
| ON_CALL(utils_, CreateDir(_)) |
| .WillByDefault(Invoke(&real_utils_, &SystemUtilsImpl::CreateDir)); |
| ON_CALL(utils_, GetUniqueFilenameInWriteOnlyTempDir(_)) |
| .WillByDefault( |
| Invoke(&real_utils_, |
| &SystemUtilsImpl::GetUniqueFilenameInWriteOnlyTempDir)); |
| ON_CALL(utils_, RemoveFile(_)) |
| .WillByDefault(Invoke(&real_utils_, &SystemUtilsImpl::RemoveFile)); |
| ON_CALL(utils_, AtomicFileWrite(_, _)) |
| .WillByDefault(Invoke(&real_utils_, &SystemUtilsImpl::AtomicFileWrite)); |
| |
| // 10 GB Free Disk Space for ARC launch. |
| ON_CALL(utils_, AmountOfFreeDiskSpace(_)).WillByDefault(Return(10LL << 30)); |
| |
| ASSERT_TRUE(tmpdir_.CreateUniqueTempDir()); |
| real_utils_.set_base_dir_for_testing(tmpdir_.GetPath()); |
| SetSystemSalt(&fake_salt_); |
| |
| // AtomicFileWrite calls in TEST_F assume that these directories exist. |
| ASSERT_TRUE(utils_.CreateDir(base::FilePath("/run/session_manager"))); |
| ASSERT_TRUE(utils_.CreateDir(base::FilePath("/mnt/stateful_partition"))); |
| |
| ASSERT_TRUE(log_dir_.CreateUniqueTempDir()); |
| log_symlink_ = log_dir_.GetPath().Append("ui.LATEST"); |
| |
| init_controller_ = new MockInitDaemonController(); |
| arc_sideload_status_ = new MockArcSideloadStatus(); |
| impl_ = std::make_unique<SessionManagerImpl>( |
| this /* delegate */, base::WrapUnique(init_controller_), bus_.get(), |
| &key_gen_, &state_key_generator_, &manager_, &metrics_, &nss_, |
| base::nullopt, &utils_, &crossystem_, &vpd_process_, &owner_key_, |
| &android_container_, &install_attributes_reader_, powerd_proxy_.get(), |
| system_clock_proxy_.get(), debugd_proxy_.get(), arc_sideload_status_); |
| impl_->SetSystemClockLastSyncInfoRetryDelayForTesting(base::TimeDelta()); |
| impl_->SetUiLogSymlinkPathForTesting(log_symlink_); |
| |
| device_policy_store_ = new MockPolicyStore(); |
| ON_CALL(*device_policy_store_, Get()) |
| .WillByDefault(ReturnRef(device_policy_)); |
| |
| device_policy_service_ = new MockDevicePolicyService(&owner_key_); |
| device_policy_service_->SetStoreForTesting( |
| MakeChromePolicyNamespace(), |
| std::unique_ptr<MockPolicyStore>(device_policy_store_)); |
| |
| user_policy_service_factory_ = |
| new testing::NiceMock<MockUserPolicyServiceFactory>(); |
| ON_CALL(*user_policy_service_factory_, Create(_)) |
| .WillByDefault( |
| Invoke(this, &SessionManagerImplTest::CreateUserPolicyService)); |
| ON_CALL(*user_policy_service_factory_, CreateForHiddenUserHome(_)) |
| .WillByDefault(Invoke( |
| this, |
| &SessionManagerImplTest::ReturnUserPolicyServiceForHiddenUserHome)); |
| |
| device_local_accounts_dir_ = |
| tmpdir_.GetPath().Append(kDeviceLocalAccountsDir); |
| auto device_local_account_manager = |
| std::make_unique<DeviceLocalAccountManager>(device_local_accounts_dir_, |
| &owner_key_); |
| |
| impl_->SetPolicyServicesForTesting( |
| base::WrapUnique(device_policy_service_), |
| base::WrapUnique(user_policy_service_factory_), |
| std::move(device_local_account_manager)); |
| |
| // Start at an arbitrary non-zero time. |
| tick_clock_ = new base::SimpleTestTickClock(); |
| tick_clock_->SetNowTicks(base::TimeTicks() + base::TimeDelta::FromHours(1)); |
| impl_->SetTickClockForTesting(base::WrapUnique(tick_clock_)); |
| |
| login_screen_storage_path_ = |
| tmpdir_.GetPath().Append(kLoginScreenStoragePath); |
| auto shared_memory_util = |
| std::make_unique<secret_util::FakeSharedMemoryUtil>(); |
| shared_memory_util_ = shared_memory_util.get(); |
| impl_->SetLoginScreenStorageForTesting(std::make_unique<LoginScreenStorage>( |
| login_screen_storage_path_, std::move(shared_memory_util))); |
| |
| EXPECT_CALL(*debugd_proxy_, CallMethodAndBlock(_, _)) |
| .WillRepeatedly( |
| Invoke(this, &SessionManagerImplTest::CreateMockProxyResponse)); |
| |
| EXPECT_CALL(*powerd_proxy_, |
| DoConnectToSignal(power_manager::kPowerManagerInterface, |
| power_manager::kSuspendImminentSignal, _, _)) |
| .WillOnce(SaveArg<2>(&suspend_imminent_callback_)); |
| EXPECT_CALL(*powerd_proxy_, |
| DoConnectToSignal(power_manager::kPowerManagerInterface, |
| power_manager::kSuspendDoneSignal, _, _)) |
| .WillOnce(SaveArg<2>(&suspend_done_callback_)); |
| |
| EXPECT_CALL(*system_clock_proxy_, DoWaitForServiceToBeAvailable(_)) |
| .WillOnce(MovePointee<0>(&available_callback_)); |
| |
| EXPECT_CALL(*arc_sideload_status_, Initialize()); |
| impl_->Initialize(); |
| |
| ASSERT_TRUE(Mock::VerifyAndClearExpectations(powerd_proxy_.get())); |
| ASSERT_FALSE(suspend_imminent_callback_.is_null()); |
| ASSERT_FALSE(suspend_done_callback_.is_null()); |
| |
| ASSERT_TRUE(Mock::VerifyAndClearExpectations(system_clock_proxy_.get())); |
| ASSERT_FALSE(available_callback_.is_null()); |
| |
| EXPECT_CALL(*exported_object(), ExportMethodAndBlock(_, _, _)) |
| .WillRepeatedly(Return(true)); |
| impl_->StartDBusService(); |
| ASSERT_TRUE(Mock::VerifyAndClearExpectations(exported_object())); |
| |
| password_provider_ = new password_provider::FakePasswordProvider; |
| impl_->SetPasswordProviderForTesting( |
| std::unique_ptr<password_provider::FakePasswordProvider>( |
| password_provider_)); |
| } |
| |
| void TearDown() override { |
| device_policy_service_ = nullptr; |
| init_controller_ = nullptr; |
| EXPECT_CALL(*exported_object(), Unregister()).Times(1); |
| impl_.reset(); |
| Mock::VerifyAndClearExpectations(exported_object()); |
| |
| SetSystemSalt(nullptr); |
| EXPECT_EQ(actual_locks_, expected_locks_); |
| EXPECT_EQ(actual_restarts_, expected_restarts_); |
| } |
| |
| // SessionManagerImpl::Delegate: |
| void LockScreen() override { actual_locks_++; } |
| void RestartDevice(const std::string& description) override { |
| actual_restarts_++; |
| } |
| |
| protected: |
| #if USE_CHEETS |
| class StartArcInstanceExpectationsBuilder { |
| public: |
| StartArcInstanceExpectationsBuilder() = default; |
| |
| StartArcInstanceExpectationsBuilder& SetDevMode(bool v) { |
| dev_mode_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetNativeBridgeExperiment(bool v) { |
| native_bridge_experiment_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetArcFilePickerExperiment(bool v) { |
| arc_file_picker_experiment_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetArcCustomTabExperiment(bool v) { |
| arc_custom_tab_experiment_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetDisableSystemDefaultApp(bool v) { |
| disable_system_default_app_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetPlayStoreAutoUpdate( |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate v) { |
| play_store_auto_update_ = v; |
| return *this; |
| } |
| |
| StartArcInstanceExpectationsBuilder& SetArcLcdDensity(int v) { |
| arc_lcd_density_ = v; |
| return *this; |
| } |
| |
| std::vector<std::string> Build() const { |
| std::vector<std::string> result({ |
| "CHROMEOS_DEV_MODE=" + std::to_string(dev_mode_), |
| "CHROMEOS_INSIDE_VM=0", |
| "NATIVE_BRIDGE_EXPERIMENT=" + |
| std::to_string(native_bridge_experiment_), |
| "ARC_FILE_PICKER_EXPERIMENT=" + |
| std::to_string(arc_file_picker_experiment_), |
| "ARC_CUSTOM_TABS_EXPERIMENT=" + |
| std::to_string(arc_custom_tab_experiment_), |
| "DISABLE_SYSTEM_DEFAULT_APP=" + |
| std::to_string(disable_system_default_app_), |
| }); |
| |
| switch (play_store_auto_update_) { |
| case StartArcMiniContainerRequest::AUTO_UPDATE_DEFAULT: |
| break; |
| case StartArcMiniContainerRequest::AUTO_UPDATE_ON: |
| result.emplace_back("PLAY_STORE_AUTO_UPDATE=1"); |
| break; |
| case StartArcMiniContainerRequest::AUTO_UPDATE_OFF: |
| result.emplace_back("PLAY_STORE_AUTO_UPDATE=0"); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| if (arc_lcd_density_ >= 0) { |
| result.emplace_back( |
| base::StringPrintf("ARC_LCD_DENSITY=%d", arc_lcd_density_)); |
| } |
| return result; |
| } |
| |
| private: |
| bool dev_mode_ = false; |
| bool native_bridge_experiment_ = false; |
| bool arc_file_picker_experiment_ = false; |
| bool arc_custom_tab_experiment_ = false; |
| |
| bool disable_system_default_app_ = false; |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate play_store_auto_update_ = |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate_AUTO_UPDATE_DEFAULT; |
| int arc_lcd_density_ = -1; |
| |
| DISALLOW_COPY_AND_ASSIGN(StartArcInstanceExpectationsBuilder); |
| }; |
| |
| class UpgradeContainerExpectationsBuilder { |
| public: |
| UpgradeContainerExpectationsBuilder() = default; |
| |
| UpgradeContainerExpectationsBuilder& SetDevMode(bool v) { |
| dev_mode_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetDisableBootCompletedCallback( |
| bool v) { |
| disable_boot_completed_callback_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetIsDemoSession(bool v) { |
| is_demo_session_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetDemoSessionAppsPath( |
| const std::string& v) { |
| demo_session_apps_path_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetSkipPackagesCache(bool v) { |
| skip_packages_cache_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetCopyPackagesCache(bool v) { |
| copy_packages_cache_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetSkipGmsCoreCache(bool v) { |
| skip_gms_core_cache_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetLocale(const std::string& v) { |
| locale_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetPreferredLanguages( |
| const std::string& v) { |
| preferred_languages_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetEnableAdbSideload(int v) { |
| enable_adb_sideload_ = v; |
| return *this; |
| } |
| |
| UpgradeContainerExpectationsBuilder& SetSupervisionTransition(int v) { |
| supervision_transition_ = v; |
| return *this; |
| } |
| |
| std::vector<std::string> Build() const { |
| return { |
| "CHROMEOS_DEV_MODE=" + std::to_string(dev_mode_), |
| "CHROMEOS_INSIDE_VM=0", std::string("CHROMEOS_USER=") + kSaneEmail, |
| "DISABLE_BOOT_COMPLETED_BROADCAST=" + |
| std::to_string(disable_boot_completed_callback_), |
| // The upgrade signal has a PID. |
| "CONTAINER_PID=" + std::to_string(kAndroidPid), |
| "DEMO_SESSION_APPS_PATH=" + demo_session_apps_path_, |
| "IS_DEMO_SESSION=" + std::to_string(is_demo_session_), |
| "SUPERVISION_TRANSITION=" + std::to_string(supervision_transition_), |
| "ENABLE_ADB_SIDELOAD=" + std::to_string(enable_adb_sideload_), |
| ExpectedSkipPackagesCacheSetupFlagValue(skip_packages_cache_), |
| ExpectedCopyPackagesCacheFlagValue(copy_packages_cache_), |
| ExpectedSkipGmsCoreCacheSetupFlagValue(skip_gms_core_cache_), |
| "LOCALE=" + locale_, "PREFERRED_LANGUAGES=" + preferred_languages_}; |
| } |
| |
| private: |
| bool dev_mode_ = false; |
| bool disable_boot_completed_callback_ = false; |
| bool is_demo_session_ = false; |
| std::string demo_session_apps_path_; |
| bool skip_packages_cache_ = false; |
| bool copy_packages_cache_ = false; |
| bool skip_gms_core_cache_ = false; |
| std::string locale_ = kDefaultLocale; |
| std::string preferred_languages_; |
| int supervision_transition_ = 0; |
| bool enable_adb_sideload_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(UpgradeContainerExpectationsBuilder); |
| }; |
| #endif |
| |
| dbus::MockExportedObject* exported_object() { |
| return bus_->exported_object(); |
| } |
| |
| void SetDeviceMode(const std::string& mode) { |
| install_attributes_reader_.SetAttributes({{"enterprise.mode", mode}}); |
| } |
| |
| void ExpectStartSession(const string& account_id_string) { |
| ExpectSessionBoilerplate(account_id_string, false /* guest */, |
| false /* for_owner */); |
| } |
| |
| void ExpectGuestSession() { |
| ExpectSessionBoilerplate(kGuestUserName, true /* guest */, |
| false /* for_owner */); |
| } |
| |
| void ExpectStartOwnerSession(const string& account_id_string) { |
| ExpectSessionBoilerplate(account_id_string, false /* guest */, |
| true /* for_owner */); |
| } |
| |
| void ExpectStartSessionUnowned(const string& account_id_string) { |
| ExpectStartSessionUnownedBoilerplate(account_id_string, |
| false, // mitigating |
| true); // key_gen |
| } |
| |
| void ExpectStartSessionOwningInProcess(const string& account_id_string) { |
| ExpectStartSessionUnownedBoilerplate(account_id_string, |
| false, // mitigating |
| false); // key_gen |
| } |
| |
| void ExpectStartSessionOwnerLost(const string& account_id_string) { |
| ExpectStartSessionUnownedBoilerplate(account_id_string, |
| true, // mitigating |
| false); // key_gen |
| } |
| |
| void ExpectStartSessionActiveDirectory(const string& account_id_string) { |
| ExpectStartSessionUnownedBoilerplate(account_id_string, |
| false, // mitigating |
| false); // key_gen |
| } |
| |
| void ExpectLockScreen() { expected_locks_ = 1; } |
| |
| void ExpectDeviceRestart() { expected_restarts_ = 1; } |
| |
| void ExpectStorePolicy(MockDevicePolicyService* service, |
| const std::vector<uint8_t>& policy_blob, |
| int flags, |
| SignatureCheck signature_check) { |
| EXPECT_CALL(*service, Store(MakeChromePolicyNamespace(), policy_blob, flags, |
| signature_check, _)) |
| .WillOnce(Return(true)); |
| } |
| |
| void ExpectDeletePolicy(MockDevicePolicyService* service) { |
| EXPECT_CALL(*service, |
| Delete(IsComponentNamespace(), SignatureCheck::kDisabled)) |
| .WillOnce(Return(true)); |
| } |
| |
| void ExpectNoStorePolicy(MockDevicePolicyService* service) { |
| EXPECT_CALL(*service, Store(_, _, _, _, _)).Times(0); |
| } |
| |
| void ExpectAndRunStartSession(const string& email) { |
| ExpectStartSession(email); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, email, kNothing)); |
| EXPECT_FALSE(error.get()); |
| VerifyAndClearExpectations(); |
| } |
| |
| void ExpectAndRunGuestSession() { |
| ExpectGuestSession(); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kGuestUserName, kNothing)); |
| EXPECT_FALSE(error.get()); |
| VerifyAndClearExpectations(); |
| } |
| |
| std::unique_ptr<PolicyService> CreateUserPolicyService( |
| const string& username) { |
| std::unique_ptr<MockPolicyService> policy_service = |
| std::make_unique<MockPolicyService>(); |
| user_policy_services_[username] = policy_service.get(); |
| return policy_service; |
| } |
| |
| std::unique_ptr<PolicyService> ReturnUserPolicyServiceForHiddenUserHome( |
| const string& username) { |
| EXPECT_EQ(username, hidden_user_home_expected_username_); |
| return std::move(hidden_user_home_policy_service_); |
| } |
| |
| void SetDevicePolicy(const em::ChromeDeviceSettingsProto& settings) { |
| em::PolicyData policy_data; |
| CHECK(settings.SerializeToString(policy_data.mutable_policy_value())); |
| CHECK(policy_data.SerializeToString(device_policy_.mutable_policy_data())); |
| } |
| |
| #if USE_CHEETS |
| void SetUpArcMiniContainer() { |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| VerifyAndClearExpectations(); |
| } |
| #endif |
| |
| // Stores a device policy with a device local account, which should add this |
| // account to SessionManagerImpl's device local account manager. |
| void SetupDeviceLocalAccount(const std::string& account_id) { |
| // Setup device policy with a device local account. |
| em::ChromeDeviceSettingsProto settings; |
| em::DeviceLocalAccountInfoProto* account = |
| settings.mutable_device_local_accounts()->add_account(); |
| account->set_type( |
| em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); |
| account->set_account_id(account_id); |
| |
| // Make sure that SessionManagerImpl calls DeviceLocalAccountManager with |
| // the given |settings| to initialize the account. |
| SetDevicePolicy(settings); |
| EXPECT_CALL(*device_policy_store_, Get()).Times(1); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq( |
| login_manager::kPropertyChangeCompleteSignal, "success"))) |
| .Times(1); |
| device_policy_service_->OnPolicySuccessfullyPersisted(); |
| VerifyAndClearExpectations(); |
| } |
| |
| // Creates a policy blob that can be serialized with a real PolicyService. |
| std::vector<uint8_t> CreatePolicyFetchResponseBlob() { |
| em::PolicyFetchResponse policy; |
| em::PolicyData policy_data; |
| policy_data.set_policy_value("fake policy"); |
| CHECK(policy_data.SerializeToString(policy.mutable_policy_data())); |
| return StringToBlob(policy.SerializeAsString()); |
| } |
| |
| base::FilePath GetDeviceLocalAccountPolicyPath( |
| const std::string& account_id) { |
| return device_local_accounts_dir_.Append(SanitizeUserName(account_id)) |
| .Append(DeviceLocalAccountManager::kPolicyDir) |
| .Append(PolicyService::kChromePolicyFileName); |
| } |
| |
| void VerifyAndClearExpectations() { |
| Mock::VerifyAndClearExpectations(device_policy_store_); |
| Mock::VerifyAndClearExpectations(device_policy_service_); |
| for (auto& entry : user_policy_services_) |
| Mock::VerifyAndClearExpectations(entry.second); |
| Mock::VerifyAndClearExpectations(init_controller_); |
| Mock::VerifyAndClearExpectations(&manager_); |
| Mock::VerifyAndClearExpectations(&metrics_); |
| Mock::VerifyAndClearExpectations(&nss_); |
| Mock::VerifyAndClearExpectations(&utils_); |
| Mock::VerifyAndClearExpectations(exported_object()); |
| } |
| |
| void GotLastSyncInfo(bool network_synchronized) { |
| ASSERT_FALSE(available_callback_.is_null()); |
| |
| dbus::ObjectProxy::ResponseCallback time_sync_callback; |
| EXPECT_CALL(*system_clock_proxy_, |
| DoCallMethod(_, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, _)) |
| .WillOnce(MovePointee<2>(&time_sync_callback)); |
| std::move(available_callback_).Run(true); |
| ASSERT_TRUE(Mock::VerifyAndClearExpectations(system_clock_proxy_.get())); |
| |
| std::unique_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendBool(network_synchronized); |
| std::move(time_sync_callback).Run(response.get()); |
| } |
| |
| base::FilePath GetTestLoginScreenStoragePath(const std::string& key) { |
| return base::FilePath(login_screen_storage_path_) |
| .Append(secret_util::StringToSafeFilename(key)); |
| } |
| |
| // These are bare pointers, not unique_ptrs, because we need to give them |
| // to a SessionManagerImpl instance, but also be able to set expectations |
| // on them after we hand them off. |
| // Owned by SessionManagerImpl. |
| MockInitDaemonController* init_controller_ = nullptr; |
| MockPolicyStore* device_policy_store_ = nullptr; |
| MockDevicePolicyService* device_policy_service_ = nullptr; |
| MockUserPolicyServiceFactory* user_policy_service_factory_ = nullptr; |
| MockArcSideloadStatus* arc_sideload_status_ = nullptr; |
| base::SimpleTestTickClock* tick_clock_ = nullptr; |
| map<string, MockPolicyService*> user_policy_services_; |
| // The username which is expected to be passed to |
| // MockUserPolicyServiceFactory::CreateForHiddenUserHome. |
| std::string hidden_user_home_expected_username_; |
| // The policy service which shall be returned from |
| // MockUserPolicyServiceFactory::CreateForHiddenUserHome. |
| std::unique_ptr<MockPolicyService> hidden_user_home_policy_service_; |
| em::PolicyFetchResponse device_policy_; |
| |
| scoped_refptr<FakeBus> bus_; |
| MockKeyGenerator key_gen_; |
| MockServerBackedStateKeyGenerator state_key_generator_; |
| MockProcessManagerService manager_; |
| MockMetrics metrics_; |
| MockNssUtil nss_; |
| SystemUtilsImpl real_utils_; |
| testing::NiceMock<MockSystemUtils> utils_; |
| FakeCrossystem crossystem_; |
| MockVpdProcess vpd_process_; |
| MockPolicyKey owner_key_; |
| FakeContainerManager android_container_; |
| MockInstallAttributesReader install_attributes_reader_; |
| |
| scoped_refptr<dbus::MockObjectProxy> powerd_proxy_; |
| dbus::ObjectProxy::SignalCallback suspend_imminent_callback_; |
| dbus::ObjectProxy::SignalCallback suspend_done_callback_; |
| |
| scoped_refptr<dbus::MockObjectProxy> system_clock_proxy_; |
| dbus::ObjectProxy::WaitForServiceToBeAvailableCallback available_callback_; |
| |
| scoped_refptr<dbus::MockObjectProxy> debugd_proxy_; |
| |
| password_provider::FakePasswordProvider* password_provider_ = nullptr; |
| |
| base::ScopedTempDir log_dir_; // simulates /var/log/ui |
| base::FilePath log_symlink_; // simulates ui.LATEST; not created by default |
| |
| std::unique_ptr<SessionManagerImpl> impl_; |
| base::ScopedTempDir tmpdir_; |
| base::FilePath device_local_accounts_dir_; |
| secret_util::SharedMemoryUtil* shared_memory_util_; |
| base::FilePath login_screen_storage_path_; |
| |
| static const pid_t kDummyPid; |
| static const char kNothing[]; |
| static const char kContainerInstanceId[]; |
| static const int kAllKeyFlags; |
| |
| private: |
| // Returns a response for the given method call. Used to implement |
| // CallMethodAndBlock() for |mock_proxy_|. |
| std::unique_ptr<dbus::Response> CreateMockProxyResponse( |
| dbus::MethodCall* method_call, int timeout_ms) { |
| return dbus::Response::CreateEmpty(); |
| } |
| |
| void ExpectSessionBoilerplate(const string& account_id_string, |
| bool guest, |
| bool for_owner) { |
| EXPECT_CALL(manager_, SetBrowserSessionForUser( |
| StrEq(account_id_string), |
| StrEq(SanitizeUserName(account_id_string)))) |
| .Times(1); |
| // Expect initialization of the device policy service, return success. |
| EXPECT_CALL(*device_policy_service_, |
| CheckAndHandleOwnerLogin(StrEq(account_id_string), _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(for_owner), Return(true))); |
| // Confirm that the key is present. |
| EXPECT_CALL(*device_policy_service_, KeyMissing()).WillOnce(Return(false)); |
| |
| EXPECT_CALL(metrics_, SendLoginUserType(false, guest, for_owner)).Times(1); |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartUserSessionImpulse, |
| ElementsAre(StartsWith("CHROMEOS_USER=")), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(nullptr))); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kSessionStateChangedSignal, |
| SessionManagerImpl::kStarted))) |
| .Times(1); |
| } |
| |
| void ExpectStartSessionUnownedBoilerplate(const string& account_id_string, |
| bool mitigating, |
| bool key_gen) { |
| CHECK(!(mitigating && key_gen)); |
| |
| EXPECT_CALL(manager_, SetBrowserSessionForUser( |
| StrEq(account_id_string), |
| StrEq(SanitizeUserName(account_id_string)))) |
| .Times(1); |
| |
| // Expect initialization of the device policy service, return success. |
| EXPECT_CALL(*device_policy_service_, |
| CheckAndHandleOwnerLogin(StrEq(account_id_string), _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(false), Return(true))); |
| |
| // Indicate that there is no owner key in order to trigger a new one to be |
| // generated. |
| EXPECT_CALL(*device_policy_service_, KeyMissing()).WillOnce(Return(true)); |
| EXPECT_CALL(*device_policy_service_, Mitigating()) |
| .WillRepeatedly(Return(mitigating)); |
| if (key_gen) |
| EXPECT_CALL(key_gen_, Start(StrEq(account_id_string), _)).Times(1); |
| else |
| EXPECT_CALL(key_gen_, Start(_, _)).Times(0); |
| |
| EXPECT_CALL(metrics_, SendLoginUserType(false, false, false)).Times(1); |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartUserSessionImpulse, |
| ElementsAre(StartsWith("CHROMEOS_USER=")), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(nullptr))); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kSessionStateChangedSignal, |
| SessionManagerImpl::kStarted))) |
| .Times(1); |
| } |
| |
| string fake_salt_ = "fake salt"; |
| |
| base::SingleThreadTaskExecutor task_executor; |
| |
| // Used by fake closures that simulate calling chrome and powerd to lock |
| // the screen and restart the device. |
| uint32_t actual_locks_ = 0; |
| uint32_t expected_locks_ = 0; |
| uint32_t actual_restarts_ = 0; |
| uint32_t expected_restarts_ = 0; |
| |
| DISALLOW_COPY_AND_ASSIGN(SessionManagerImplTest); |
| }; |
| |
| class SessionManagerPackagesCacheTest |
| : public SessionManagerImplTest, |
| public testing::WithParamInterface< |
| std::tuple<UpgradeArcContainerRequest_PackageCacheMode, bool>> { |
| public: |
| SessionManagerPackagesCacheTest() = default; |
| ~SessionManagerPackagesCacheTest() override = default; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SessionManagerPackagesCacheTest); |
| }; |
| |
| class SessionManagerPlayStoreAutoUpdateTest |
| : public SessionManagerImplTest, |
| public testing::WithParamInterface< |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate> { |
| public: |
| SessionManagerPlayStoreAutoUpdateTest() = default; |
| ~SessionManagerPlayStoreAutoUpdateTest() override = default; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SessionManagerPlayStoreAutoUpdateTest); |
| }; |
| |
| const pid_t SessionManagerImplTest::kDummyPid = 4; |
| const char SessionManagerImplTest::kNothing[] = ""; |
| const int SessionManagerImplTest::kAllKeyFlags = |
| PolicyService::KEY_ROTATE | PolicyService::KEY_INSTALL_NEW | |
| PolicyService::KEY_CLOBBER; |
| |
| TEST_F(SessionManagerImplTest, EmitLoginPromptVisible) { |
| const char event_name[] = "login-prompt-visible"; |
| EXPECT_CALL(metrics_, RecordStats(StrEq(event_name))).Times(1); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kLoginPromptVisibleSignal))) |
| .Times(1); |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse("login-prompt-visible", ElementsAre(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .Times(1); |
| impl_->EmitLoginPromptVisible(); |
| } |
| |
| TEST_F(SessionManagerImplTest, EmitAshInitialized) { |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse("ash-initialized", ElementsAre(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .Times(1); |
| impl_->EmitAshInitialized(); |
| } |
| |
| TEST_F(SessionManagerImplTest, EnableChromeTesting) { |
| std::vector<std::string> args = {"--repeat-arg", "--one-time-arg"}; |
| const std::vector<std::string> kEnvVars = {"FOO=", "BAR=/tmp"}; |
| |
| base::FilePath temp_dir; |
| ASSERT_TRUE(base::CreateNewTempDirectory("" /* ignored */, &temp_dir)); |
| |
| const size_t random_suffix_len = strlen("XXXXXX"); |
| ASSERT_LT(random_suffix_len, temp_dir.value().size()) << temp_dir.value(); |
| |
| // Check that SetBrowserTestArgs() is called with a randomly chosen |
| // --testing-channel path name. |
| const string expected_testing_path_prefix = |
| temp_dir.value().substr(0, temp_dir.value().size() - random_suffix_len); |
| EXPECT_CALL(manager_, |
| SetBrowserTestArgs(ElementsAre( |
| args[0], args[1], HasSubstr(expected_testing_path_prefix)))) |
| .Times(1); |
| EXPECT_CALL(manager_, SetBrowserAdditionalEnvironmentalVariables( |
| ElementsAre(kEnvVars[0], kEnvVars[1]))) |
| .Times(1); |
| EXPECT_CALL(manager_, RestartBrowser()).Times(1); |
| |
| { |
| brillo::ErrorPtr error; |
| std::string testing_path; |
| ASSERT_TRUE(impl_->EnableChromeTesting(&error, false, args, kEnvVars, |
| &testing_path)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_NE(std::string::npos, |
| testing_path.find(expected_testing_path_prefix)) |
| << testing_path; |
| } |
| |
| { |
| // Calling again, without forcing relaunch, should not do anything. |
| brillo::ErrorPtr error; |
| std::string testing_path; |
| ASSERT_TRUE(impl_->EnableChromeTesting(&error, false, args, kEnvVars, |
| &testing_path)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_NE(std::string::npos, |
| testing_path.find(expected_testing_path_prefix)) |
| << testing_path; |
| } |
| |
| // Force relaunch. Should go through the whole path again. |
| args[0] = "--dummy"; |
| args[1] = "--repeat-arg"; |
| EXPECT_CALL(manager_, |
| SetBrowserTestArgs(ElementsAre( |
| args[0], args[1], HasSubstr(expected_testing_path_prefix)))) |
| .Times(1); |
| EXPECT_CALL(manager_, SetBrowserAdditionalEnvironmentalVariables( |
| ElementsAre(kEnvVars[0], kEnvVars[1]))) |
| .Times(1); |
| EXPECT_CALL(manager_, RestartBrowser()).Times(1); |
| |
| { |
| brillo::ErrorPtr error; |
| std::string testing_path; |
| ASSERT_TRUE(impl_->EnableChromeTesting(&error, true, args, kEnvVars, |
| &testing_path)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_NE(std::string::npos, |
| testing_path.find(expected_testing_path_prefix)) |
| << testing_path; |
| } |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession) { |
| ExpectStartSession(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_New) { |
| ExpectStartSessionUnowned(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_InvalidUser) { |
| constexpr char kBadEmail[] = "user"; |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StartSession(&error, kBadEmail, kNothing)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kInvalidAccount, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_Twice) { |
| ExpectStartSession(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| |
| EXPECT_FALSE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kSessionExists, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_TwoUsers) { |
| ExpectStartSession(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| VerifyAndClearExpectations(); |
| |
| constexpr char kEmail2[] = "user2@somewhere"; |
| ExpectStartSession(kEmail2); |
| EXPECT_TRUE(impl_->StartSession(&error, kEmail2, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_OwnerAndOther) { |
| ExpectStartSessionUnowned(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| VerifyAndClearExpectations(); |
| |
| constexpr char kEmail2[] = "user2@somewhere"; |
| ExpectStartSession(kEmail2); |
| EXPECT_TRUE(impl_->StartSession(&error, kEmail2, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_OwnerRace) { |
| ExpectStartSessionUnowned(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| VerifyAndClearExpectations(); |
| |
| constexpr char kEmail2[] = "user2@somewhere"; |
| ExpectStartSessionOwningInProcess(kEmail2); |
| EXPECT_TRUE(impl_->StartSession(&error, kEmail2, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_BadNssDB) { |
| nss_.MakeBadDB(); |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNoUserNssDb, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_DevicePolicyFailure) { |
| // Upon the owner login check, return an error. |
| |
| EXPECT_CALL(*device_policy_service_, |
| CheckAndHandleOwnerLogin(StrEq(kSaneEmail), _, _, _)) |
| .WillOnce(WithArg<3>(Invoke([](brillo::ErrorPtr* error) { |
| *error = CreateError(dbus_error::kPubkeySetIllegal, "test"); |
| return false; |
| }))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| ASSERT_TRUE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_Owner) { |
| ExpectStartOwnerSession(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartSession_KeyMitigation) { |
| ExpectStartSessionOwnerLost(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| // Ensure that starting Active Directory session does not create owner key. |
| TEST_F(SessionManagerImplTest, StartSession_ActiveDirectorManaged) { |
| SetDeviceMode("enterprise_ad"); |
| ExpectStartSessionActiveDirectory(kSaneEmail); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, SaveLoginPassword) { |
| const string kPassword("thepassword"); |
| base::ScopedFD password_fd = secret_util::WriteSizeAndDataToPipe( |
| std::vector<uint8_t>(kPassword.begin(), kPassword.end())); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->SaveLoginPassword(&error, password_fd)); |
| EXPECT_FALSE(error.get()); |
| |
| EXPECT_TRUE(password_provider_->password_saved()); |
| } |
| |
| TEST_F(SessionManagerImplTest, DiscardPasswordOnStopSession) { |
| impl_->StopSessionWithReason( |
| static_cast<uint32_t>(SessionStopReason::RESTORE_ACTIVE_SESSIONS)); |
| EXPECT_TRUE(password_provider_->password_discarded()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StopSession) { |
| EXPECT_CALL(manager_, ScheduleShutdown()).Times(1); |
| impl_->StopSessionWithReason( |
| static_cast<uint32_t>(SessionStopReason::RESTORE_ACTIVE_SESSIONS)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LoginScreenStorage_StoreEphemeral) { |
| const string kTestKey("testkey"); |
| const string kTestValue("testvalue"); |
| const vector<uint8_t> kTestValueVector = |
| std::vector<uint8_t>(kTestValue.begin(), kTestValue.end()); |
| auto value_fd = |
| shared_memory_util_->WriteDataToSharedMemory(kTestValueVector); |
| |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| brillo::ErrorPtr error; |
| impl_->LoginScreenStorageStore( |
| &error, kTestKey, |
| MakeLoginScreenStorageMetadata(/*clear_on_session_exit=*/true), |
| kTestValue.size(), value_fd); |
| EXPECT_FALSE(error.get()); |
| EXPECT_FALSE(base::PathExists(GetTestLoginScreenStoragePath(kTestKey))); |
| |
| brillo::dbus_utils::FileDescriptor out_value_fd; |
| uint64_t out_value_size; |
| impl_->LoginScreenStorageRetrieve(&error, kTestKey, &out_value_size, |
| &out_value_fd); |
| EXPECT_FALSE(error.get()); |
| base::ScopedFD scoped_fd(out_value_fd.release()); |
| std::vector<uint8_t> out_value; |
| EXPECT_TRUE(shared_memory_util_->ReadDataFromSharedMemory( |
| scoped_fd, out_value_size, &out_value)); |
| EXPECT_EQ(out_value, |
| std::vector<uint8_t>(kTestValue.begin(), kTestValue.end())); |
| } |
| |
| TEST_F(SessionManagerImplTest, LoginScreenStorage_StorePersistent) { |
| const string kTestKey("testkey"); |
| const string kTestValue("testvalue"); |
| const vector<uint8_t> kTestValueVector = |
| std::vector<uint8_t>(kTestValue.begin(), kTestValue.end()); |
| auto value_fd = |
| shared_memory_util_->WriteDataToSharedMemory(kTestValueVector); |
| |
| brillo::ErrorPtr error; |
| impl_->LoginScreenStorageStore( |
| &error, kTestKey, |
| MakeLoginScreenStorageMetadata(/*clear_on_session_exit=*/false), |
| kTestValue.size(), value_fd); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(base::PathExists(GetTestLoginScreenStoragePath(kTestKey))); |
| |
| brillo::dbus_utils::FileDescriptor out_value_fd; |
| uint64_t out_value_size; |
| impl_->LoginScreenStorageRetrieve(&error, kTestKey, &out_value_size, |
| &out_value_fd); |
| EXPECT_FALSE(error.get()); |
| base::ScopedFD scoped_fd(out_value_fd.release()); |
| std::vector<uint8_t> out_value; |
| EXPECT_TRUE(shared_memory_util_->ReadDataFromSharedMemory( |
| scoped_fd, out_value_size, &out_value)); |
| EXPECT_EQ(out_value, |
| std::vector<uint8_t>(kTestValue.begin(), kTestValue.end())); |
| } |
| |
| TEST_F(SessionManagerImplTest, |
| LoginScreenStorage_StorePersistentFailsInSession) { |
| const string kTestKey("testkey"); |
| const string kTestValue("testvalue"); |
| const vector<uint8_t> kTestValueVector = |
| std::vector<uint8_t>(kTestValue.begin(), kTestValue.end()); |
| auto value_fd = |
| shared_memory_util_->WriteDataToSharedMemory(kTestValueVector); |
| |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| brillo::ErrorPtr error; |
| impl_->LoginScreenStorageStore( |
| &error, kTestKey, |
| MakeLoginScreenStorageMetadata(/*clear_on_session_exit=*/false), |
| kTestValue.size(), value_fd); |
| EXPECT_TRUE(error.get()); |
| EXPECT_FALSE(base::PathExists(GetTestLoginScreenStoragePath(kTestKey))); |
| brillo::dbus_utils::FileDescriptor out_value_fd; |
| uint64_t out_value_size; |
| impl_->LoginScreenStorageRetrieve(&error, kTestKey, &out_value_size, |
| &out_value_fd); |
| EXPECT_TRUE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_NoSession) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| ExpectStorePolicy(device_policy_service_, policy_blob, kAllKeyFlags, |
| SignatureCheck::kEnabled); |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_SessionStarted) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| ExpectStorePolicy(device_policy_service_, policy_blob, |
| PolicyService::KEY_ROTATE, SignatureCheck::kEnabled); |
| |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_NoSignatureConsumer) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| ExpectNoStorePolicy(device_policy_service_); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_NoSignatureEnterprise) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| SetDeviceMode("enterprise"); |
| ExpectNoStorePolicy(device_policy_service_); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_NoSignatureEnterpriseAD) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| SetDeviceMode("enterprise_ad"); |
| ExpectStorePolicy(device_policy_service_, policy_blob, kAllKeyFlags, |
| SignatureCheck::kDisabled); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StorePolicyEx_DeleteComponentPolicy) { |
| PolicyDescriptor descriptor; |
| descriptor.set_account_type(ACCOUNT_TYPE_DEVICE); |
| descriptor.set_account_id(kEmptyAccountId); |
| descriptor.set_domain(POLICY_DOMAIN_EXTENSIONS); |
| descriptor.set_component_id("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); |
| std::vector<uint8_t> descriptor_blob = |
| StringToBlob(descriptor.SerializeAsString()); |
| |
| SetDeviceMode("enterprise_ad"); |
| ExpectDeletePolicy(device_policy_service_); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx(capturer.CreateMethodResponse<>(), |
| StringToBlob(descriptor.SerializeAsString()), |
| std::vector<uint8_t>() /* policy_blob */); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrievePolicyEx) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*device_policy_service_, Retrieve(MakeChromePolicyNamespace(), _)) |
| .WillOnce(DoAll(SetArgPointee<1>(policy_blob), Return(true))); |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE, kEmptyAccountId), |
| &out_blob)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_EQ(policy_blob, out_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, ListStoredComponentPolicies) { |
| // Create a descriptor to query component ids. |
| // Note: The component_id() field must be empty for this! |
| PolicyDescriptor descriptor; |
| descriptor.set_account_type(ACCOUNT_TYPE_DEVICE); |
| descriptor.set_account_id(kEmptyAccountId); |
| descriptor.set_domain(POLICY_DOMAIN_SIGNIN_EXTENSIONS); |
| std::vector<uint8_t> descriptor_blob = |
| StringToBlob(descriptor.SerializeAsString()); |
| |
| // Tell the mock store to return some component ids for ListComponentIds. |
| std::vector<std::string> expected_component_ids({"id1", "id2"}); |
| EXPECT_CALL(*device_policy_service_, ListComponentIds(descriptor.domain())) |
| .WillOnce(Return(expected_component_ids)); |
| |
| // Query component ids and validate the result. |
| brillo::ErrorPtr error; |
| std::vector<std::string> component_ids; |
| EXPECT_TRUE(impl_->ListStoredComponentPolicies(&error, descriptor_blob, |
| &component_ids)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_EQ(expected_component_ids, component_ids); |
| } |
| |
| TEST_F(SessionManagerImplTest, GetServerBackedStateKeys_TimeSync) { |
| EXPECT_CALL(state_key_generator_, RequestStateKeys(_)); |
| |
| ResponseCapturer capturer; |
| impl_->GetServerBackedStateKeys( |
| capturer.CreateMethodResponse<std::vector<std::vector<uint8_t>>>()); |
| ASSERT_NO_FATAL_FAILURE(GotLastSyncInfo(true)); |
| } |
| |
| TEST_F(SessionManagerImplTest, GetServerBackedStateKeys_NoTimeSync) { |
| EXPECT_CALL(state_key_generator_, RequestStateKeys(_)).Times(0); |
| ResponseCapturer capturer; |
| impl_->GetServerBackedStateKeys( |
| capturer.CreateMethodResponse<std::vector<std::vector<uint8_t>>>()); |
| } |
| |
| TEST_F(SessionManagerImplTest, GetServerBackedStateKeys_TimeSyncDoneBefore) { |
| ASSERT_NO_FATAL_FAILURE(GotLastSyncInfo(true)); |
| |
| EXPECT_CALL(state_key_generator_, RequestStateKeys(_)); |
| ResponseCapturer capturer; |
| impl_->GetServerBackedStateKeys( |
| capturer.CreateMethodResponse<std::vector<std::vector<uint8_t>>>()); |
| } |
| |
| TEST_F(SessionManagerImplTest, GetServerBackedStateKeys_FailedTimeSync) { |
| ASSERT_NO_FATAL_FAILURE(GotLastSyncInfo(false)); |
| |
| EXPECT_CALL(state_key_generator_, RequestStateKeys(_)).Times(0); |
| ResponseCapturer capturer; |
| impl_->GetServerBackedStateKeys( |
| capturer.CreateMethodResponse<std::vector<std::vector<uint8_t>>>()); |
| |
| EXPECT_CALL(*system_clock_proxy_, |
| DoCallMethod(_, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, _)) |
| .Times(1); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(SessionManagerImplTest, GetServerBackedStateKeys_TimeSyncAfterFail) { |
| ASSERT_NO_FATAL_FAILURE(GotLastSyncInfo(false)); |
| |
| ResponseCapturer capturer; |
| impl_->GetServerBackedStateKeys( |
| capturer.CreateMethodResponse<std::vector<std::vector<uint8_t>>>()); |
| |
| dbus::ObjectProxy::ResponseCallback time_sync_callback; |
| EXPECT_CALL(*system_clock_proxy_, |
| DoCallMethod(_, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, _)) |
| .WillOnce(MovePointee<2>(&time_sync_callback)); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_TRUE(Mock::VerifyAndClearExpectations(system_clock_proxy_.get())); |
| ASSERT_FALSE(time_sync_callback.is_null()); |
| |
| EXPECT_CALL(state_key_generator_, RequestStateKeys(_)).Times(1); |
| std::unique_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendBool(true); |
| std::move(time_sync_callback).Run(response.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_NoSession) { |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx(capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), |
| policy_blob); |
| ASSERT_TRUE(capturer.response()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, capturer.response()->GetErrorName()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_SessionStarted) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], |
| Store(MakeChromePolicyNamespace(), policy_blob, |
| PolicyService::KEY_ROTATE | PolicyService::KEY_INSTALL_NEW, |
| SignatureCheck::kEnabled, _)) |
| .WillOnce(Return(true)); |
| |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx(capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), |
| policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_SecondSession) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ASSERT_TRUE(user_policy_services_[kSaneEmail]); |
| |
| // Store policy for the signed-in user. |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], |
| Store(MakeChromePolicyNamespace(), policy_blob, |
| PolicyService::KEY_ROTATE | PolicyService::KEY_INSTALL_NEW, |
| SignatureCheck::kEnabled, _)) |
| .WillOnce(Return(true)); |
| |
| { |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx(capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), |
| policy_blob); |
| Mock::VerifyAndClearExpectations(user_policy_services_[kSaneEmail]); |
| } |
| |
| // Storing policy for another username fails before their session starts. |
| constexpr char kEmail2[] = "user2@somewhere.com"; |
| { |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx(capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kEmail2), |
| policy_blob); |
| ASSERT_TRUE(capturer.response()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, capturer.response()->GetErrorName()); |
| } |
| |
| // Now start another session for the 2nd user. |
| ExpectAndRunStartSession(kEmail2); |
| ASSERT_TRUE(user_policy_services_[kEmail2]); |
| |
| // Storing policy for that user now succeeds. |
| EXPECT_CALL(*user_policy_services_[kEmail2], |
| Store(MakeChromePolicyNamespace(), policy_blob, |
| PolicyService::KEY_ROTATE | PolicyService::KEY_INSTALL_NEW, |
| SignatureCheck::kEnabled, _)) |
| .WillOnce(Return(true)); |
| { |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx(capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kEmail2), |
| policy_blob); |
| } |
| Mock::VerifyAndClearExpectations(user_policy_services_[kEmail2]); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_NoSignatureConsumer) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], Store(_, _, _, _, _)) |
| .Times(0); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_NoSignatureEnterprise) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| SetDeviceMode("enterprise"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], Store(_, _, _, _, _)) |
| .Times(0); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreUserPolicyEx_NoSignatureEnterpriseAD) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| SetDeviceMode("enterprise_ad"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], |
| Store(MakeChromePolicyNamespace(), policy_blob, |
| PolicyService::KEY_ROTATE | PolicyService::KEY_INSTALL_NEW, |
| SignatureCheck::kDisabled, _)) |
| .WillOnce(Return(true)); |
| |
| ResponseCapturer capturer; |
| impl_->StoreUnsignedPolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), policy_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveUserPolicyEx_NoSession) { |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), &out_blob)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveUserPolicyEx_SessionStarted) { |
| ExpectAndRunStartSession(kSaneEmail); |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], |
| Retrieve(MakeChromePolicyNamespace(), _)) |
| .WillOnce(DoAll(SetArgPointee<1>(policy_blob), Return(true))); |
| |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), &out_blob)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_EQ(policy_blob, out_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveUserPolicyEx_SecondSession) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ASSERT_TRUE(user_policy_services_[kSaneEmail]); |
| |
| // Retrieve policy for the signed-in user. |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| EXPECT_CALL(*user_policy_services_[kSaneEmail], |
| Retrieve(MakeChromePolicyNamespace(), _)) |
| .WillOnce(DoAll(SetArgPointee<1>(policy_blob), Return(true))); |
| { |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_USER, kSaneEmail), |
| &out_blob)); |
| EXPECT_FALSE(error.get()); |
| Mock::VerifyAndClearExpectations(user_policy_services_[kSaneEmail]); |
| EXPECT_EQ(policy_blob, out_blob); |
| } |
| |
| // Retrieving policy for another username fails before their session starts. |
| constexpr char kEmail2[] = "user2@somewhere.com"; |
| { |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_USER, kEmail2), &out_blob)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, error->GetCode()); |
| } |
| |
| // Now start another session for the 2nd user. |
| ExpectAndRunStartSession(kEmail2); |
| ASSERT_TRUE(user_policy_services_[kEmail2]); |
| |
| // Retrieving policy for that user now succeeds. |
| EXPECT_CALL(*user_policy_services_[kEmail2], |
| Retrieve(MakeChromePolicyNamespace(), _)) |
| .WillOnce(DoAll(SetArgPointee<1>(policy_blob), Return(true))); |
| { |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_USER, kEmail2), &out_blob)); |
| EXPECT_FALSE(error.get()); |
| Mock::VerifyAndClearExpectations(user_policy_services_[kEmail2]); |
| EXPECT_EQ(policy_blob, out_blob); |
| } |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveUserPolicyExWithoutSession) { |
| ASSERT_FALSE(user_policy_services_.count(kSaneEmail)); |
| |
| const std::vector<uint8_t> policy_blob = StringToBlob("fake policy"); |
| |
| // Set up what MockUserPolicyServiceFactory will return. |
| hidden_user_home_expected_username_ = kSaneEmail; |
| hidden_user_home_policy_service_ = std::make_unique<MockPolicyService>(); |
| MockPolicyService* policy_service = hidden_user_home_policy_service_.get(); |
| |
| EXPECT_CALL(*policy_service, Retrieve(MakeChromePolicyNamespace(), _)) |
| .WillOnce(DoAll(SetArgPointee<1>(policy_blob), Return(true))); |
| |
| // Retrieve policy for a user who does not have a session. |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, MakePolicyDescriptor(ACCOUNT_TYPE_SESSIONLESS_USER, kSaneEmail), |
| &out_blob)); |
| Mock::VerifyAndClearExpectations(policy_service); |
| EXPECT_FALSE(error.get()); |
| EXPECT_EQ(policy_blob, out_blob); |
| // Retrieval of policy without user session should not create a persistent |
| // PolicyService. |
| ASSERT_FALSE(user_policy_services_.count(kSaneEmail)); |
| |
| // Make sure the policy service is deleted. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreDeviceLocalAccountPolicyNoAccount) { |
| const std::vector<uint8_t> policy_blob = CreatePolicyFetchResponseBlob(); |
| base::FilePath policy_path = GetDeviceLocalAccountPolicyPath(kSaneEmail); |
| |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT, kSaneEmail), |
| policy_blob); |
| ASSERT_TRUE(capturer.response()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, capturer.response()->GetErrorName()); |
| VerifyAndClearExpectations(); |
| |
| EXPECT_FALSE(base::PathExists(policy_path)); |
| } |
| |
| TEST_F(SessionManagerImplTest, StoreDeviceLocalAccountPolicySuccess) { |
| const std::vector<uint8_t> policy_blob = CreatePolicyFetchResponseBlob(); |
| base::FilePath policy_path = GetDeviceLocalAccountPolicyPath(kSaneEmail); |
| SetupDeviceLocalAccount(kSaneEmail); |
| EXPECT_FALSE(base::PathExists(policy_path)); |
| EXPECT_CALL(owner_key_, Verify(_, _)).WillOnce(Return(true)); |
| |
| brillo::FakeMessageLoop io_loop(nullptr); |
| io_loop.SetAsCurrent(); |
| |
| ResponseCapturer capturer; |
| impl_->StorePolicyEx( |
| capturer.CreateMethodResponse<>(), |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT, kSaneEmail), |
| policy_blob); |
| VerifyAndClearExpectations(); |
| |
| io_loop.Run(); |
| EXPECT_TRUE(base::PathExists(policy_path)); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveDeviceLocalAccountPolicyNoAccount) { |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->RetrievePolicyEx( |
| &error, |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT, kSaneEmail), |
| &out_blob)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kGetServiceFail, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveDeviceLocalAccountPolicySuccess) { |
| const std::vector<uint8_t> policy_blob = CreatePolicyFetchResponseBlob(); |
| base::FilePath policy_path = GetDeviceLocalAccountPolicyPath(kSaneEmail); |
| SetupDeviceLocalAccount(kSaneEmail); |
| ASSERT_TRUE(base::CreateDirectory(policy_path.DirName())); |
| ASSERT_TRUE(WriteBlobToFile(policy_path, policy_blob)); |
| |
| std::vector<uint8_t> out_blob; |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RetrievePolicyEx( |
| &error, |
| MakePolicyDescriptor(ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT, kSaneEmail), |
| &out_blob)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_EQ(policy_blob, out_blob); |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrieveActiveSessions) { |
| ExpectStartSession(kSaneEmail); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| { |
| std::map<std::string, std::string> active_users = |
| impl_->RetrieveActiveSessions(); |
| EXPECT_EQ(active_users.size(), 1); |
| EXPECT_EQ(active_users[kSaneEmail], SanitizeUserName(kSaneEmail)); |
| } |
| VerifyAndClearExpectations(); |
| |
| constexpr char kEmail2[] = "user2@somewhere"; |
| ExpectStartSession(kEmail2); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kEmail2, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| { |
| std::map<std::string, std::string> active_users = |
| impl_->RetrieveActiveSessions(); |
| EXPECT_EQ(active_users.size(), 2); |
| EXPECT_EQ(active_users[kSaneEmail], SanitizeUserName(kSaneEmail)); |
| EXPECT_EQ(active_users[kEmail2], SanitizeUserName(kEmail2)); |
| } |
| } |
| |
| TEST_F(SessionManagerImplTest, RetrievePrimarySession) { |
| ExpectGuestSession(); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kGuestUserName, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| { |
| std::string username; |
| std::string sanitized_username; |
| impl_->RetrievePrimarySession(&username, &sanitized_username); |
| EXPECT_EQ(username, ""); |
| EXPECT_EQ(sanitized_username, ""); |
| } |
| VerifyAndClearExpectations(); |
| |
| ExpectStartSession(kSaneEmail); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| { |
| std::string username; |
| std::string sanitized_username; |
| impl_->RetrievePrimarySession(&username, &sanitized_username); |
| EXPECT_EQ(username, kSaneEmail); |
| EXPECT_EQ(sanitized_username, SanitizeUserName(kSaneEmail)); |
| } |
| VerifyAndClearExpectations(); |
| |
| constexpr char kEmail2[] = "user2@somewhere"; |
| ExpectStartSession(kEmail2); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartSession(&error, kEmail2, kNothing)); |
| EXPECT_FALSE(error.get()); |
| } |
| { |
| std::string username; |
| std::string sanitized_username; |
| impl_->RetrievePrimarySession(&username, &sanitized_username); |
| EXPECT_EQ(username, kSaneEmail); |
| EXPECT_EQ(sanitized_username, SanitizeUserName(kSaneEmail)); |
| } |
| } |
| |
| TEST_F(SessionManagerImplTest, IsGuestSessionActive) { |
| EXPECT_FALSE(impl_->IsGuestSessionActive()); |
| ExpectAndRunGuestSession(); |
| EXPECT_TRUE(impl_->IsGuestSessionActive()); |
| ExpectAndRunStartSession(kSaneEmail); |
| EXPECT_FALSE(impl_->IsGuestSessionActive()); |
| } |
| |
| TEST_F(SessionManagerImplTest, RestartJobBadSocket) { |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->RestartJob(&error, base::ScopedFD(), {})); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ("GetPeerCredsFailed", error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, RestartJobBadPid) { |
| int sockets[2] = {-1, -1}; |
| ASSERT_GE(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets), 0); |
| base::ScopedFD fd0_closer(sockets[0]); |
| base::ScopedFD fd1(sockets[1]); |
| |
| EXPECT_CALL(manager_, IsBrowser(getpid())).WillRepeatedly(Return(false)); |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->RestartJob(&error, fd1, {})); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kUnknownPid, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, RestartJobSuccess) { |
| int sockets[2] = {-1, -1}; |
| ASSERT_GE(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets), 0); |
| base::ScopedFD fd0_closer(sockets[0]); |
| base::ScopedFD fd1(sockets[1]); |
| |
| const std::vector<std::string> kArgv = { |
| "program", |
| "--switch1", |
| "--switch2=switch2_value", |
| "--switch3=escaped_\"_quote", |
| "--switch4=white space", |
| "arg1", |
| "arg 2", |
| }; |
| |
| EXPECT_CALL(manager_, IsBrowser(getpid())).WillRepeatedly(Return(true)); |
| EXPECT_CALL(manager_, SetBrowserArgs(ElementsAreArray(kArgv))).Times(1); |
| EXPECT_CALL(manager_, RestartBrowser()).Times(1); |
| ExpectGuestSession(); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->RestartJob(&error, fd1, kArgv)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, SupervisedUserCreation) { |
| impl_->HandleSupervisedUserCreationStarting(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleSupervisedUserCreationFinished(); |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ExpectLockScreen(); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_DuringSupervisedUserCreation) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ExpectLockScreen(); |
| EXPECT_CALL(*exported_object(), SendSignal(_)).Times(AnyNumber()); |
| |
| impl_->HandleSupervisedUserCreationStarting(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleLockScreenShown(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleLockScreenDismissed(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleSupervisedUserCreationFinished(); |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_InterleavedSupervisedUserCreation) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ExpectLockScreen(); |
| EXPECT_CALL(*exported_object(), SendSignal(_)).Times(AnyNumber()); |
| |
| impl_->HandleSupervisedUserCreationStarting(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleLockScreenShown(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleSupervisedUserCreationFinished(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| impl_->HandleLockScreenDismissed(); |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_MultiSession) { |
| ExpectAndRunStartSession("user@somewhere"); |
| ExpectAndRunStartSession("user2@somewhere"); |
| ExpectLockScreen(); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_NoSession) { |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->LockScreen(&error)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kSessionDoesNotExist, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_Guest) { |
| ExpectAndRunGuestSession(); |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->LockScreen(&error)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kSessionExists, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockScreen_UserAndGuest) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ExpectAndRunGuestSession(); |
| ExpectLockScreen(); |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| ASSERT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, LockUnlockScreen) { |
| ExpectAndRunStartSession(kSaneEmail); |
| ExpectLockScreen(); |
| brillo::ErrorPtr error; |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kScreenLockedImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_TRUE(impl_->LockScreen(&error)); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kScreenIsLockedSignal))) |
| .Times(1); |
| impl_->HandleLockScreenShown(); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| EXPECT_TRUE(impl_->IsScreenLocked()); |
| |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kScreenIsUnlockedSignal))) |
| .Times(1); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kScreenUnlockedImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| impl_->HandleLockScreenDismissed(); |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| |
| EXPECT_FALSE(impl_->IsScreenLocked()); |
| } |
| |
| TEST_F(SessionManagerImplTest, EndSessionBeforeSuspend) { |
| const base::TimeTicks crash_time = tick_clock_->NowTicks(); |
| auto set_expectations = [&](bool should_stop) { |
| EXPECT_CALL(manager_, GetLastBrowserRestartTime()) |
| .WillRepeatedly(Return(crash_time)); |
| EXPECT_CALL(manager_, ScheduleShutdown()).Times(should_stop ? 1 : 0); |
| }; |
| |
| // The session should be ended in response to a SuspendImminent signal. |
| set_expectations(true); |
| dbus::Signal imminent_signal(power_manager::kPowerManagerInterface, |
| power_manager::kSuspendImminentSignal); |
| suspend_imminent_callback_.Run(&imminent_signal); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // It should also be ended if a small amount of time passes between the |
| // restart and the signal. |
| tick_clock_->Advance(SessionManagerImpl::kCrashBeforeSuspendInterval); |
| set_expectations(true); |
| suspend_imminent_callback_.Run(&imminent_signal); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // We shouldn't end the session after the specified interval has elapsed. |
| tick_clock_->Advance(base::TimeDelta::FromSeconds(1)); |
| set_expectations(false); |
| suspend_imminent_callback_.Run(&imminent_signal); |
| } |
| |
| TEST_F(SessionManagerImplTest, EndSessionDuringAndAfterSuspend) { |
| EXPECT_CALL(manager_, GetLastBrowserRestartTime()) |
| .WillRepeatedly(Return(base::TimeTicks())); |
| |
| // Initially, we should restart Chrome if it crashes. |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| |
| // Right after suspend starts, we should end the session instead. |
| dbus::Signal imminent_signal(power_manager::kPowerManagerInterface, |
| power_manager::kSuspendImminentSignal); |
| suspend_imminent_callback_.Run(&imminent_signal); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| // We should also end it if some time passes... |
| tick_clock_->Advance(base::TimeDelta::FromSeconds(20)); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| // ... and right after resume finishes... |
| dbus::Signal done_signal(power_manager::kPowerManagerInterface, |
| power_manager::kSuspendDoneSignal); |
| suspend_done_callback_.Run(&done_signal); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| // ... and for a period of time after that. |
| tick_clock_->Advance(SessionManagerImpl::kCrashAfterSuspendInterval); |
| EXPECT_TRUE(impl_->ShouldEndSession(nullptr)); |
| |
| // If we wait long enough, we should go back to restarting Chrome. |
| tick_clock_->Advance(base::TimeDelta::FromSeconds(1)); |
| EXPECT_FALSE(impl_->ShouldEndSession(nullptr)); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartDeviceWipe) { |
| // Just make sure the device is being restart as sanity check of |
| // InitiateDeviceWipe() invocation. |
| ExpectDeviceRestart(); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartDeviceWipe(&error)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartDeviceWipe_AlreadyLoggedIn) { |
| base::FilePath logged_in_path(SessionManagerImpl::kLoggedInFlag); |
| ASSERT_FALSE(utils_.Exists(logged_in_path)); |
| ASSERT_TRUE(utils_.AtomicFileWrite(logged_in_path, "1")); |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StartDeviceWipe(&error)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kSessionExists, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartRemoteDeviceWipe) { |
| ExpectDeviceRestart(); |
| EXPECT_CALL(*device_policy_service_, ValidateRemoteDeviceWipeCommand(_)) |
| .WillOnce(Return(true)); |
| |
| brillo::ErrorPtr error; |
| std::vector<uint8_t> in_signed_command; |
| EXPECT_TRUE(impl_->StartRemoteDeviceWipe(&error, in_signed_command)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartRemoteDeviceWipe_BadSignature) { |
| EXPECT_CALL(*device_policy_service_, ValidateRemoteDeviceWipeCommand(_)) |
| .WillOnce(Return(false)); |
| |
| brillo::ErrorPtr error; |
| std::vector<uint8_t> in_signed_command; |
| EXPECT_FALSE(impl_->StartRemoteDeviceWipe(&error, in_signed_command)); |
| EXPECT_TRUE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, InitiateDeviceWipe_TooLongReason) { |
| ASSERT_TRUE( |
| utils_.RemoveFile(base::FilePath(SessionManagerImpl::kLoggedInFlag))); |
| ExpectDeviceRestart(); |
| impl_->InitiateDeviceWipe( |
| "overly long test message with\nspecial/chars$\t\xa4\xd6 1234567890"); |
| std::string contents; |
| base::FilePath reset_path = real_utils_.PutInsideBaseDirForTesting( |
| base::FilePath(SessionManagerImpl::kResetFile)); |
| ASSERT_TRUE(base::ReadFileToString(reset_path, &contents)); |
| ASSERT_EQ( |
| "fast safe keepimg reason=" |
| "overly_long_test_message_with_special_chars_____12", |
| contents); |
| } |
| |
| TEST_F(SessionManagerImplTest, ClearForcedReEnrollmentVpd) { |
| ResponseCapturer capturer; |
| EXPECT_CALL(*device_policy_service_, ClearForcedReEnrollmentFlags(_)) |
| .Times(1); |
| impl_->ClearForcedReEnrollmentVpd(capturer.CreateMethodResponse<>()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ImportValidateAndStoreGeneratedKey) { |
| base::FilePath key_file_path; |
| string key("key_contents"); |
| ASSERT_TRUE( |
| base::CreateTemporaryFileInDir(tmpdir_.GetPath(), &key_file_path)); |
| ASSERT_EQ(base::WriteFile(key_file_path, key.c_str(), key.size()), |
| key.size()); |
| |
| // Start a session, to set up NSSDB for the user. |
| ExpectStartOwnerSession(kSaneEmail); |
| brillo::ErrorPtr error; |
| ASSERT_TRUE(impl_->StartSession(&error, kSaneEmail, kNothing)); |
| EXPECT_FALSE(error.get()); |
| |
| EXPECT_CALL(*device_policy_service_, |
| ValidateAndStoreOwnerKey(StrEq(kSaneEmail), StringToBlob(key), |
| IncludesSlot(nss_.GetSlot()))) |
| .WillOnce(Return(true)); |
| |
| impl_->OnKeyGenerated(kSaneEmail, key_file_path); |
| EXPECT_FALSE(base::PathExists(key_file_path)); |
| } |
| |
| TEST_F(SessionManagerImplTest, DisconnectLogFile) { |
| // Write a log file and create a relative symlink pointing at it. |
| constexpr char kData[] = "fake log data"; |
| const base::FilePath kLogFile = log_dir_.GetPath().Append("ui.real"); |
| ASSERT_EQ(strlen(kData), base::WriteFile(kLogFile, kData, strlen(kData))); |
| ASSERT_TRUE(base::CreateSymbolicLink(kLogFile.BaseName(), log_symlink_)); |
| |
| struct stat st; |
| ASSERT_EQ(0, stat(kLogFile.value().c_str(), &st)); |
| const ino_t orig_inode = st.st_ino; |
| |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // The file should still contain the same data... |
| std::string data; |
| ASSERT_TRUE(base::ReadFileToString(kLogFile, &data)); |
| EXPECT_EQ(kData, data); |
| |
| // ... but its inode should've changed. |
| ASSERT_EQ(0, stat(kLogFile.value().c_str(), &st)); |
| const ino_t updated_inode = st.st_ino; |
| EXPECT_NE(orig_inode, updated_inode); |
| |
| // Start a second session. The log file shouldn't be modified this time. |
| constexpr char kEmail2[] = "user2@somewhere.com"; |
| ExpectAndRunStartSession(kEmail2); |
| ASSERT_EQ(0, stat(kLogFile.value().c_str(), &st)); |
| EXPECT_EQ(updated_inode, st.st_ino); |
| } |
| |
| TEST_F(SessionManagerImplTest, DontDisconnectLogFileInOtherDir) { |
| // Write a log file to a subdirectory and create an absolute symlink. |
| constexpr char kData[] = "fake log data"; |
| const base::FilePath kSubdir = log_dir_.GetPath().Append("subdir"); |
| ASSERT_TRUE(base::CreateDirectory(kSubdir)); |
| const base::FilePath kLogFile = kSubdir.Append("ui.real"); |
| ASSERT_EQ(strlen(kData), base::WriteFile(kLogFile, kData, strlen(kData))); |
| ASSERT_TRUE(base::CreateSymbolicLink(kLogFile, log_symlink_)); |
| |
| struct stat st; |
| ASSERT_EQ(0, stat(kLogFile.value().c_str(), &st)); |
| const ino_t orig_inode = st.st_ino; |
| |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // The inode should stay the same since the symlink points to a file in a |
| // different directory. |
| ASSERT_EQ(0, stat(kLogFile.value().c_str(), &st)); |
| EXPECT_EQ(orig_inode, st.st_ino); |
| } |
| |
| #if USE_CHEETS |
| TEST_F(SessionManagerImplTest, StopArcInstance) { |
| EXPECT_CALL(*init_controller_, TriggerImpulse(_, _, _)) |
| .WillRepeatedly( |
| InvokeWithoutArgs([]() { return dbus::Response::CreateEmpty(); })); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::USER_REQUEST))) |
| .Times(1); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| EXPECT_FALSE(error.get()); |
| |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StopArcInstance_BackupsArcBugReport) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| EXPECT_CALL(*init_controller_, TriggerImpulse(_, _, _)) |
| .WillRepeatedly( |
| InvokeWithoutArgs([] { return dbus::Response::CreateEmpty(); })); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::USER_REQUEST))) |
| .Times(1); |
| |
| EXPECT_CALL(*debugd_proxy_, CallMethodAndBlock(_, _)) |
| .WillOnce(WithArg<0>(Invoke([](dbus::MethodCall* method_call) { |
| EXPECT_EQ(method_call->GetInterface(), debugd::kDebugdInterface); |
| EXPECT_EQ(method_call->GetMember(), debugd::kBackupArcBugReport); |
| return dbus::Response::CreateEmpty(); |
| }))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| EXPECT_FALSE(error.get()); |
| |
| EXPECT_TRUE( |
| impl_->StopArcInstance(&error, kSaneEmail, true /*should_backup_log*/)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, StartArcMiniContainer) { |
| { |
| int64_t start_time = 0; |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| |
| // StartArcInstance() does not update start time for login screen. |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::USER_REQUEST))) |
| .Times(1); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, UpgradeArcContainer) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| // Then, upgrade it to a fully functional one. |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_TRUE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| EXPECT_NE(0, start_time); |
| ASSERT_FALSE(error.get()); |
| } |
| // The ID for the container for login screen is passed to the dbus call. |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::USER_REQUEST))) |
| .Times(1); |
| |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(error.get()); |
| } |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, |
| UpgradeArcContainer_BackupsArcBugReportOnFailure) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(ReturnNull()); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::UPGRADE_FAILURE))) |
| .Times(1); |
| |
| EXPECT_CALL(*arc_sideload_status_, IsAdbSideloadAllowed()) |
| .WillRepeatedly(Return(false)); |
| |
| EXPECT_CALL(metrics_, SendArcBugReportBackupTime(_)).Times(1); |
| EXPECT_CALL(*debugd_proxy_, CallMethodAndBlock(_, _)) |
| .WillOnce(WithArg<0>(Invoke([](dbus::MethodCall* method_call) { |
| EXPECT_EQ(method_call->GetInterface(), debugd::kDebugdInterface); |
| EXPECT_EQ(method_call->GetMember(), debugd::kBackupArcBugReport); |
| return dbus::Response::CreateEmpty(); |
| }))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| EXPECT_FALSE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_TRUE(error.get()); |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, UpgradeArcContainerWithSupervisionTransition) { |
| ExpectAndRunStartSession(kSaneEmail); |
| SetUpArcMiniContainer(); |
| |
| // Expect continue-arc-boot and start-arc-network impulses. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetSupervisionTransition(1) |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_supervision_transition( |
| login_manager:: |
| UpgradeArcContainerRequest_SupervisionTransition_CHILD_TO_REGULAR); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, DisableSystemDefaultApp) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| StartArcMiniContainerRequest request; |
| request.set_disable_system_default_app(true); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetDisableSystemDefaultApp(true) |
| .Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| } |
| |
| TEST_P(SessionManagerPackagesCacheTest, PackagesCache) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| bool skip_packages_cache_setup = false; |
| bool copy_cache_setup = false; |
| switch (std::get<0>(GetParam())) { |
| case UpgradeArcContainerRequest_PackageCacheMode_SKIP_SETUP_COPY_ON_INIT: |
| skip_packages_cache_setup = true; |
| FALLTHROUGH; |
| case UpgradeArcContainerRequest_PackageCacheMode_COPY_ON_INIT: |
| copy_cache_setup = true; |
| break; |
| case UpgradeArcContainerRequest_PackageCacheMode_DEFAULT: |
| break; |
| default: |
| NOTREACHED(); |
| } |
| |
| // Then, upgrade it to a fully functional one. |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetSkipPackagesCache(skip_packages_cache_setup) |
| .SetCopyPackagesCache(copy_cache_setup) |
| .SetSkipGmsCoreCache(std::get<1>(GetParam())) |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_packages_cache_mode(std::get<0>(GetParam())); |
| upgrade_request.set_skip_gms_core_cache(std::get<1>(GetParam())); |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_TRUE(android_container_.running()); |
| |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| , |
| SessionManagerPackagesCacheTest, |
| ::testing::Combine( |
| ::testing::Values(UpgradeArcContainerRequest::DEFAULT, |
| UpgradeArcContainerRequest::COPY_ON_INIT, |
| UpgradeArcContainerRequest::SKIP_SETUP_COPY_ON_INIT), |
| ::testing::Bool())); |
| |
| TEST_P(SessionManagerPlayStoreAutoUpdateTest, PlayStoreAutoUpdate) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| StartArcMiniContainerRequest request; |
| request.set_play_store_auto_update(GetParam()); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetPlayStoreAutoUpdate(GetParam()) |
| .Build(), |
| |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| , |
| SessionManagerPlayStoreAutoUpdateTest, |
| ::testing::ValuesIn( |
| {StartArcMiniContainerRequest_PlayStoreAutoUpdate_AUTO_UPDATE_DEFAULT, |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate_AUTO_UPDATE_ON, |
| StartArcMiniContainerRequest_PlayStoreAutoUpdate_AUTO_UPDATE_OFF})); |
| |
| TEST_F(SessionManagerImplTest, UpgradeArcContainerForDemoSession) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| // Then, upgrade it to a fully functional one. |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetIsDemoSession(true) |
| .SetDemoSessionAppsPath( |
| "/run/imageloader/0.1/demo_apps/img.squash") |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_is_demo_session(true); |
| upgrade_request.set_demo_session_apps_path( |
| "/run/imageloader/0.1/demo_apps/img.squash"); |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_TRUE(android_container_.running()); |
| |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, |
| UpgradeArcContainerForDemoSessionWithoutDemoApps) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| // Then, upgrade it to a fully functional one. |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse( |
| SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder().SetIsDemoSession(true).Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_is_demo_session(true); |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_TRUE(android_container_.running()); |
| |
| EXPECT_TRUE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| EXPECT_FALSE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, UpgradeArcContainer_AdbSideloadingEnabled) { |
| ExpectAndRunStartSession(kSaneEmail); |
| SetUpArcMiniContainer(); |
| |
| // Expect continue-arc-boot and start-arc-network impulses. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetEnableAdbSideload(true) |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| // Pretend ADB sideloading is already enabled. |
| EXPECT_CALL(*arc_sideload_status_, IsAdbSideloadAllowed()) |
| .WillRepeatedly(Return(true)); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, |
| UpgradeArcContainer_AdbSideloadingEnabled_ManagedAccount_Disallowed) { |
| ExpectAndRunStartSession(kSaneEmail); |
| SetUpArcMiniContainer(); |
| |
| // Expect continue-arc-boot and start-arc-network impulses. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetEnableAdbSideload(false) |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| // Pretend ADB sideloading is already enabled. |
| EXPECT_CALL(*arc_sideload_status_, IsAdbSideloadAllowed()) |
| .WillRepeatedly(Return(true)); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_is_account_managed(true); |
| upgrade_request.set_is_managed_adb_sideloading_allowed(false); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, |
| UpgradeArcContainer_AdbSideloadingEnabled_ManagedAccount_Allowed) { |
| ExpectAndRunStartSession(kSaneEmail); |
| SetUpArcMiniContainer(); |
| |
| // Expect continue-arc-boot and start-arc-network impulses. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetEnableAdbSideload(true) |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| // Pretend ADB sideloading is already enabled. |
| EXPECT_CALL(*arc_sideload_status_, IsAdbSideloadAllowed()) |
| .WillRepeatedly(Return(true)); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_is_account_managed(true); |
| upgrade_request.set_is_managed_adb_sideloading_allowed(true); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcNativeBridgeExperiment) { |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetNativeBridgeExperiment(true) |
| .Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| StartArcMiniContainerRequest request; |
| request.set_native_bridge_experiment(true); |
| // Use for login screen mode for minimalistic test. |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcFilePickerExperiment) { |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetArcFilePickerExperiment(true) |
| .Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| StartArcMiniContainerRequest request; |
| request.set_arc_file_picker_experiment(true); |
| // Use for login screen mode for minimalistic test. |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcCustomTabsExperiment) { |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetArcCustomTabExperiment(true) |
| .Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| StartArcMiniContainerRequest request; |
| request.set_arc_custom_tabs_experiment(true); |
| // Use for login screen mode for minimalistic test. |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcLcdDensity) { |
| constexpr int arc_lcd_density = 240; |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder() |
| .SetArcLcdDensity(arc_lcd_density) |
| .Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| StartArcMiniContainerRequest request; |
| request.set_lcd_density(arc_lcd_density); |
| // Use for login screen mode for minimalistic test. |
| EXPECT_TRUE(impl_->StartArcMiniContainer(&error, SerializeAsBlob(request))); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcNoSession) { |
| SetUpArcMiniContainer(); |
| |
| brillo::ErrorPtr error; |
| UpgradeArcContainerRequest request = CreateUpgradeArcContainerRequest(); |
| EXPECT_FALSE(impl_->UpgradeArcContainer(&error, SerializeAsBlob(request))); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kSessionDoesNotExist, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcLowDisk) { |
| ExpectAndRunStartSession(kSaneEmail); |
| SetUpArcMiniContainer(); |
| // Emulate no free disk space. |
| ON_CALL(utils_, AmountOfFreeDiskSpace(_)).WillByDefault(Return(0)); |
| |
| brillo::ErrorPtr error; |
| |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::LOW_DISK_SPACE))) |
| .Times(1); |
| |
| UpgradeArcContainerRequest request = CreateUpgradeArcContainerRequest(); |
| EXPECT_FALSE(impl_->UpgradeArcContainer(&error, SerializeAsBlob(request))); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kLowFreeDisk, error->GetCode()); |
| } |
| |
| TEST_F(SessionManagerImplTest, ArcUpgradeCrash) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // Overrides dev mode state. |
| ON_CALL(utils_, GetDevModeState()) |
| .WillByDefault(Return(DevModeState::DEV_MODE_ON)); |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse( |
| SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().SetDevMode(true).Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse( |
| SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder().SetDevMode(true).Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStopArcInstanceImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| { |
| brillo::ErrorPtr error; |
| UpgradeArcContainerRequest request = CreateUpgradeArcContainerRequest(); |
| EXPECT_TRUE(impl_->UpgradeArcContainer(&error, SerializeAsBlob(request))); |
| EXPECT_FALSE(error.get()); |
| } |
| EXPECT_TRUE(android_container_.running()); |
| |
| EXPECT_CALL(*exported_object(), |
| SendSignal(SignalEq(login_manager::kArcInstanceStopped, |
| ArcContainerStopReason::CRASH))) |
| .Times(1); |
| |
| android_container_.SimulateCrash(); |
| EXPECT_FALSE(android_container_.running()); |
| |
| // This should now fail since the container was cleaned up already. |
| { |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StopArcInstance(&error, std::string() /*account_id*/, |
| false /*should_backup_log*/)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kContainerShutdownFail, error->GetCode()); |
| } |
| } |
| |
| TEST_F(SessionManagerImplTest, LocaleAndPreferredLanguages) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| // First, start ARC for login screen. |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kStartArcInstanceImpulse, |
| StartArcInstanceExpectationsBuilder().Build(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| |
| // Then, upgrade it to a fully functional one. |
| { |
| brillo::ErrorPtr error; |
| int64_t start_time = 0; |
| EXPECT_FALSE(impl_->GetArcStartTimeTicks(&error, &start_time)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotStarted, error->GetCode()); |
| } |
| |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kContinueArcBootImpulse, |
| UpgradeContainerExpectationsBuilder() |
| .SetLocale("fr_FR") |
| .SetPreferredLanguages("ru,en") |
| .Build(), |
| InitDaemonController::TriggerMode::SYNC)) |
| .WillOnce(Return(ByMove(dbus::Response::CreateEmpty()))); |
| |
| auto upgrade_request = CreateUpgradeArcContainerRequest(); |
| upgrade_request.set_locale("fr_FR"); |
| upgrade_request.add_preferred_languages("ru"); |
| upgrade_request.add_preferred_languages("en"); |
| EXPECT_TRUE( |
| impl_->UpgradeArcContainer(&error, SerializeAsBlob(upgrade_request))); |
| EXPECT_FALSE(error.get()); |
| EXPECT_TRUE(android_container_.running()); |
| } |
| #else // !USE_CHEETS |
| |
| TEST_F(SessionManagerImplTest, ArcUnavailable) { |
| ExpectAndRunStartSession(kSaneEmail); |
| |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->StartArcMiniContainer( |
| &error, SerializeAsBlob(StartArcMiniContainerRequest()))); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotAvailable, error->GetCode()); |
| } |
| #endif |
| |
| TEST_F(SessionManagerImplTest, SetArcCpuRestrictionFails) { |
| #if USE_CHEETS |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->SetArcCpuRestriction( |
| &error, static_cast<uint32_t>(NUM_CONTAINER_CPU_RESTRICTION_STATES))); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kArcCpuCgroupFail, error->GetCode()); |
| #else |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->SetArcCpuRestriction( |
| &error, static_cast<uint32_t>(CONTAINER_CPU_RESTRICTION_BACKGROUND))); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotAvailable, error->GetCode()); |
| #endif |
| } |
| |
| TEST_F(SessionManagerImplTest, EmitArcBooted) { |
| #if USE_CHEETS |
| EXPECT_CALL(*init_controller_, |
| TriggerImpulse(SessionManagerImpl::kArcBootedImpulse, |
| ElementsAre(StartsWith("CHROMEOS_USER=")), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(nullptr))); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->EmitArcBooted(&error, kSaneEmail)); |
| EXPECT_FALSE(error.get()); |
| } |
| |
| EXPECT_CALL( |
| *init_controller_, |
| TriggerImpulse(SessionManagerImpl::kArcBootedImpulse, ElementsAre(), |
| InitDaemonController::TriggerMode::ASYNC)) |
| .WillOnce(Return(ByMove(nullptr))); |
| { |
| brillo::ErrorPtr error; |
| EXPECT_TRUE(impl_->EmitArcBooted(&error, std::string())); |
| EXPECT_FALSE(error.get()); |
| } |
| #else |
| brillo::ErrorPtr error; |
| EXPECT_FALSE(impl_->EmitArcBooted(&error, kSaneEmail)); |
| ASSERT_TRUE(error.get()); |
| EXPECT_EQ(dbus_error::kNotAvailable, error->GetCode()); |
| #endif |
| } |
| |
| TEST_F(SessionManagerImplTest, EnableAdbSideload) { |
| EXPECT_CALL(*arc_sideload_status_, EnableAdbSideload(_)); |
| ResponseCapturer capturer; |
| impl_->EnableAdbSideload(capturer.CreateMethodResponse<bool>()); |
| } |
| |
| TEST_F(SessionManagerImplTest, EnableAdbSideloadAfterLoggedIn) { |
| base::FilePath logged_in_path(SessionManagerImpl::kLoggedInFlag); |
| ASSERT_FALSE(utils_.Exists(logged_in_path)); |
| ASSERT_TRUE(utils_.AtomicFileWrite(logged_in_path, "1")); |
| |
| EXPECT_CALL(*arc_sideload_status_, EnableAdbSideload(_)).Times(0); |
| |
| ResponseCapturer capturer; |
| impl_->EnableAdbSideload(capturer.CreateMethodResponse<bool>()); |
| |
| ASSERT_NE(capturer.response(), nullptr); |
| EXPECT_EQ(dbus_error::kSessionExists, capturer.response()->GetErrorName()); |
| } |
| |
| TEST_F(SessionManagerImplTest, QueryAdbSideload) { |
| EXPECT_CALL(*arc_sideload_status_, QueryAdbSideload(_)); |
| ResponseCapturer capturer; |
| impl_->QueryAdbSideload(capturer.CreateMethodResponse<bool>()); |
| } |
| |
| class StartTPMFirmwareUpdateTest : public SessionManagerImplTest { |
| public: |
| void SetUp() override { |
| SessionManagerImplTest::SetUp(); |
| |
| ON_CALL(utils_, Exists(_)) |
| .WillByDefault(Invoke(this, &StartTPMFirmwareUpdateTest::FileExists)); |
| ON_CALL(utils_, ReadFileToString(_, _)) |
| .WillByDefault(Invoke(this, &StartTPMFirmwareUpdateTest::ReadFile)); |
| ON_CALL(utils_, AtomicFileWrite(_, _)) |
| .WillByDefault( |
| Invoke(this, &StartTPMFirmwareUpdateTest::AtomicWriteFile)); |
| SetDeviceMode("consumer"); |
| |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, |
| "/lib/firmware/tpm/dummy.bin"); |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateSRKVulnerableROCAFile, |
| ""); |
| } |
| |
| void TearDown() override { |
| brillo::ErrorPtr error; |
| bool result = impl_->StartTPMFirmwareUpdate(&error, update_mode_); |
| if (expected_error_.empty()) { |
| EXPECT_TRUE(result); |
| EXPECT_FALSE(error); |
| const auto& contents = file_contents_.find( |
| SessionManagerImpl::kTPMFirmwareUpdateRequestFlagFile); |
| ASSERT_NE(contents, file_contents_.end()); |
| EXPECT_EQ(update_mode_, contents->second); |
| |
| if (update_mode_ == "preserve_stateful") { |
| EXPECT_EQ(1, file_contents_.count( |
| SessionManagerImpl::kStatefulPreservationRequestFile)); |
| EXPECT_EQ(1, crossystem_.VbGetSystemPropertyInt( |
| Crossystem::kClearTpmOwnerRequest)); |
| } |
| } else { |
| EXPECT_FALSE(result); |
| ASSERT_TRUE(error); |
| EXPECT_EQ(expected_error_, error->GetCode()); |
| } |
| |
| SessionManagerImplTest::TearDown(); |
| } |
| |
| void SetFileContents(const std::string& path, const std::string& contents) { |
| file_contents_[path] = contents; |
| } |
| |
| void DeleteFile(const std::string& path) { file_contents_.erase(path); } |
| |
| bool FileExists(const base::FilePath& path) { |
| const auto entry = file_contents_.find(path.MaybeAsASCII()); |
| return entry != file_contents_.end(); |
| } |
| |
| bool ReadFile(const base::FilePath& path, std::string* str_out) { |
| const auto entry = file_contents_.find(path.MaybeAsASCII()); |
| if (entry == file_contents_.end()) { |
| return false; |
| } |
| *str_out = entry->second; |
| return true; |
| } |
| |
| bool AtomicWriteFile(const base::FilePath& path, const std::string& value) { |
| file_contents_[path.value()] = value; |
| return file_write_status_; |
| } |
| |
| void ExpectError(const std::string& error) { expected_error_ = error; } |
| |
| void SetUpdateMode(const std::string& mode) { update_mode_ = mode; } |
| |
| std::string update_mode_ = "first_boot"; |
| std::string expected_error_; |
| std::map<std::string, std::string> file_contents_; |
| bool file_write_status_ = true; |
| }; |
| |
| TEST_F(StartTPMFirmwareUpdateTest, Success) { |
| ExpectDeviceRestart(); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, AlreadyLoggedIn) { |
| SetFileContents(SessionManagerImpl::kLoggedInFlag, ""); |
| ExpectError(dbus_error::kSessionExists); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, BadUpdateMode) { |
| SetUpdateMode("no_such_thing"); |
| ExpectError(dbus_error::kInvalidParameter); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterpriseFirstBootNotSet) { |
| SetDeviceMode("enterprise"); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterpriseFirstBootAllowed) { |
| SetDeviceMode("enterprise"); |
| em::ChromeDeviceSettingsProto settings; |
| settings.mutable_tpm_firmware_update_settings() |
| ->set_allow_user_initiated_powerwash(true); |
| SetDevicePolicy(settings); |
| ExpectDeviceRestart(); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterprisePreserveStatefulNotSet) { |
| SetUpdateMode("preserve_stateful"); |
| SetDeviceMode("enterprise"); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterprisePreserveStatefulAllowed) { |
| SetUpdateMode("preserve_stateful"); |
| SetDeviceMode("enterprise"); |
| em::ChromeDeviceSettingsProto settings; |
| settings.mutable_tpm_firmware_update_settings() |
| ->set_allow_user_initiated_preserve_device_state(true); |
| SetDevicePolicy(settings); |
| ExpectDeviceRestart(); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterpriseCleanupDisallowed) { |
| SetUpdateMode("cleanup"); |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, ""); |
| SetDeviceMode("enterprise"); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, EnterpriseCleanupAllowed) { |
| SetUpdateMode("cleanup"); |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, ""); |
| em::ChromeDeviceSettingsProto settings; |
| settings.mutable_tpm_firmware_update_settings() |
| ->set_allow_user_initiated_preserve_device_state(true); |
| SetDevicePolicy(settings); |
| ExpectDeviceRestart(); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, AvailabilityNotDecided) { |
| DeleteFile(SessionManagerImpl::kTPMFirmwareUpdateLocationFile); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, NoUpdateAvailable) { |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, ""); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, CleanupSRKVulnerable) { |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, ""); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, CleanupSRKNotVulnerable) { |
| SetFileContents(SessionManagerImpl::kTPMFirmwareUpdateLocationFile, ""); |
| DeleteFile(SessionManagerImpl::kTPMFirmwareUpdateSRKVulnerableROCAFile); |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, RequestFileWriteFailure) { |
| file_write_status_ = false; |
| ExpectError(dbus_error::kNotAvailable); |
| } |
| |
| TEST_F(StartTPMFirmwareUpdateTest, PreserveStateful) { |
| update_mode_ = "preserve_stateful"; |
| ExpectDeviceRestart(); |
| } |
| |
| } // namespace login_manager |