| // Copyright 2021 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "rmad/interface/rmad_interface_impl.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/functional/bind.h> |
| #include <base/functional/callback_helpers.h> |
| #include <base/logging.h> |
| #include <base/memory/scoped_refptr.h> |
| #include <base/strings/stringprintf.h> |
| #include <base/test/task_environment.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "rmad/daemon/daemon_callback.h" |
| #include "rmad/logs/logs_constants.h" |
| #include "rmad/metrics/mock_metrics_utils.h" |
| #include "rmad/metrics/state_metrics.h" |
| #include "rmad/state_handler/mock_state_handler.h" |
| #include "rmad/state_handler/state_handler_manager.h" |
| #include "rmad/system/mock_power_manager_client.h" |
| #include "rmad/system/mock_runtime_probe_client.h" |
| #include "rmad/system/mock_shill_client.h" |
| #include "rmad/system/mock_tpm_manager_client.h" |
| #include "rmad/udev/mock_udev_device.h" |
| #include "rmad/udev/mock_udev_utils.h" |
| #include "rmad/utils/json_store.h" |
| #include "rmad/utils/mock_cmd_utils.h" |
| |
| using testing::_; |
| using testing::Assign; |
| using testing::DoAll; |
| using testing::InSequence; |
| using testing::Invoke; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::ReturnRef; |
| using testing::SetArgPointee; |
| using testing::StrictMock; |
| |
| namespace rmad { |
| |
| constexpr char kJsonStoreFileName[] = "json_store_file"; |
| constexpr char kCurrentStateSetJson[] = R"({"state_history": [ 1 ]})"; |
| constexpr char kCurrentStateNotSetJson[] = "{}"; |
| constexpr char kCurrentStateInvalidStateJson[] = R"("state_history": [0])"; |
| constexpr char kCurrentStateWithRepeatableHistoryJson[] = |
| R"({"state_history": [ 1, 2 ]})"; |
| constexpr char kCurrentStateWithUnrepeatableHistoryJson[] = |
| R"({"state_history": [ 1, 2, 3 ]})"; |
| constexpr char kCurrentStateWithUnsupportedStateJson[] = |
| R"({"state_history": [ 1, 2, 4 ]})"; |
| constexpr char kInitializeCurrentStateFailJson[] = |
| R"({"state_history": [ 1 ]})"; |
| constexpr char kInitializeNextStateFailJson[] = |
| R"({"state_history": [ 1, 2 ]})"; |
| constexpr char kInitializePreviousStateFailJson[] = |
| R"({"state_history": [ 1, 2 ]})"; |
| constexpr char kInvalidJson[] = R"(alfkjklsfsgdkjnbknd^^)"; |
| |
| constexpr char kStateHistoryWithMetricsJson[] = |
| R"({ |
| "state_history": [ 1, 2 ], |
| "metrics": { |
| "replaced_component_names": [], |
| "additional_activities": ["RMAD_ADDITIONAL_ACTIVITY_REBOOT"], |
| "first_setup_timestamp": 123.456, |
| "occurred_errors": ["RMAD_ERROR_MISSING_COMPONENT"], |
| "ro_firmware_verified": true, |
| "running_time": 333.333, |
| "setup_timestamp": 456.789, |
| "state_metrics": { |
| "1": { |
| "state_case": 1, |
| "state_is_aborted": false, |
| "state_setup_timestamp": 0.0, |
| "state_overall_time": 123.456, |
| "state_transition_count": 2, |
| "state_get_log_count": 3, |
| "state_save_log_count": 4 |
| }, |
| "2": { |
| "state_case": 2, |
| "state_is_aborted": true, |
| "state_setup_timestamp": 123.456, |
| "state_overall_time": 332.544, |
| "state_transition_count": 1, |
| "state_get_log_count": 0, |
| "state_save_log_count": 0 |
| } |
| } |
| } |
| })"; |
| |
| constexpr char kFakeRawLog[] = "fake_log"; |
| |
| constexpr char kDeviceFileFormat[] = "/dev/sd%c1"; |
| constexpr char kMountSuccessDeviceId = 'e'; |
| |
| constexpr base::TimeDelta kTestTransitionInterval = base::Seconds(1); |
| constexpr base::TimeDelta kInitialStateOverallTime = base::Seconds(0); |
| |
| class RmadInterfaceImplTest : public testing::Test { |
| public: |
| RmadInterfaceImplTest() { |
| welcome_proto_.set_allocated_welcome(new WelcomeState()); |
| components_repair_proto_.set_allocated_components_repair( |
| new ComponentsRepairState()); |
| device_destination_proto_.set_allocated_device_destination( |
| new DeviceDestinationState()); |
| } |
| |
| base::FilePath CreateInputFile(std::string filename, |
| const char* str, |
| int size) { |
| base::FilePath file_path = temp_dir_.GetPath().AppendASCII(filename); |
| base::WriteFile(file_path, str, size); |
| return file_path; |
| } |
| |
| scoped_refptr<BaseStateHandler> CreateMockHandler( |
| scoped_refptr<JsonStore> json_store, |
| const RmadState& state, |
| bool is_repeatable, |
| RmadErrorCode initialize_error, |
| RmadErrorCode get_next_state_case_error, |
| RmadState::StateCase next_state) { |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| auto mock_handler = base::MakeRefCounted<NiceMock<MockStateHandler>>( |
| json_store, daemon_callback); |
| RmadState::StateCase state_case = state.state_case(); |
| ON_CALL(*mock_handler, GetStateCase()).WillByDefault(Return(state_case)); |
| ON_CALL(*mock_handler, GetState(_)).WillByDefault(ReturnRef(state)); |
| ON_CALL(*mock_handler, IsRepeatable()).WillByDefault(Return(is_repeatable)); |
| ON_CALL(*mock_handler, InitializeState()) |
| .WillByDefault(Return(initialize_error)); |
| ON_CALL(*mock_handler, GetNextStateCase(_)) |
| .WillByDefault(Return(BaseStateHandler::GetNextStateCaseReply{ |
| .error = get_next_state_case_error, .state_case = next_state})); |
| ON_CALL(*mock_handler, TryGetNextStateCaseAtBoot()) |
| .WillByDefault(Return(BaseStateHandler::GetNextStateCaseReply{ |
| .error = get_next_state_case_error, .state_case = next_state})); |
| return mock_handler; |
| } |
| |
| std::unique_ptr<StateHandlerManager> CreateStateHandlerManagerWithHandlers( |
| scoped_refptr<JsonStore> json_store, |
| std::vector<scoped_refptr<BaseStateHandler>> mock_handlers) { |
| auto state_handler_manager = |
| std::make_unique<StateHandlerManager>(json_store); |
| for (auto mock_handler : mock_handlers) { |
| state_handler_manager->RegisterStateHandler(mock_handler); |
| } |
| return state_handler_manager; |
| } |
| |
| std::unique_ptr<StateHandlerManager> CreateStateHandlerManager( |
| scoped_refptr<JsonStore> json_store) { |
| std::vector<scoped_refptr<BaseStateHandler>> mock_handlers; |
| mock_handlers.push_back(CreateMockHandler(json_store, welcome_proto_, true, |
| RMAD_ERROR_OK, RMAD_ERROR_OK, |
| RmadState::kComponentsRepair)); |
| mock_handlers.push_back(CreateMockHandler( |
| json_store, components_repair_proto_, true, RMAD_ERROR_OK, |
| RMAD_ERROR_OK, RmadState::kDeviceDestination)); |
| mock_handlers.push_back(CreateMockHandler( |
| json_store, device_destination_proto_, false, RMAD_ERROR_OK, |
| RMAD_ERROR_OK, RmadState::kWpDisableMethod)); |
| return CreateStateHandlerManagerWithHandlers(json_store, mock_handlers); |
| } |
| |
| std::unique_ptr<StateHandlerManager> |
| CreateStateHandlerManagerGetNextStateCaseFail( |
| scoped_refptr<JsonStore> json_store) { |
| std::vector<scoped_refptr<BaseStateHandler>> mock_handlers; |
| mock_handlers.push_back(CreateMockHandler( |
| json_store, welcome_proto_, true, RMAD_ERROR_OK, |
| RMAD_ERROR_REQUEST_ARGS_MISSING, RmadState::kWelcome)); |
| return CreateStateHandlerManagerWithHandlers(json_store, mock_handlers); |
| } |
| |
| std::unique_ptr<StateHandlerManager> CreateStateHandlerManagerMissingHandler( |
| scoped_refptr<JsonStore> json_store) { |
| std::vector<scoped_refptr<BaseStateHandler>> mock_handlers; |
| mock_handlers.push_back(CreateMockHandler(json_store, welcome_proto_, true, |
| RMAD_ERROR_OK, RMAD_ERROR_OK, |
| RmadState::kComponentsRepair)); |
| return CreateStateHandlerManagerWithHandlers(json_store, mock_handlers); |
| } |
| |
| std::unique_ptr<StateHandlerManager> |
| CreateStateHandlerManagerInitializeStateFail( |
| scoped_refptr<JsonStore> json_store) { |
| std::vector<scoped_refptr<BaseStateHandler>> mock_handlers; |
| mock_handlers.push_back(CreateMockHandler( |
| json_store, welcome_proto_, true, RMAD_ERROR_MISSING_COMPONENT, |
| RMAD_ERROR_OK, RmadState::kComponentsRepair)); |
| mock_handlers.push_back(CreateMockHandler( |
| json_store, components_repair_proto_, true, RMAD_ERROR_OK, |
| RMAD_ERROR_OK, RmadState::kDeviceDestination)); |
| mock_handlers.push_back( |
| CreateMockHandler(json_store, device_destination_proto_, false, |
| RMAD_ERROR_DEVICE_INFO_INVALID, RMAD_ERROR_OK, |
| RmadState::kWpDisableMethod)); |
| return CreateStateHandlerManagerWithHandlers(json_store, mock_handlers); |
| } |
| |
| std::unique_ptr<RuntimeProbeClient> CreateRuntimeProbeClient( |
| bool has_cellular) { |
| auto mock_runtime_probe_client = |
| std::make_unique<NiceMock<MockRuntimeProbeClient>>(); |
| ComponentsWithIdentifier components; |
| if (has_cellular) { |
| components.push_back(std::make_pair(RMAD_COMPONENT_CELLULAR, "")); |
| } |
| ON_CALL(*mock_runtime_probe_client, ProbeCategories(_, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<2>(components), Return(true))); |
| return mock_runtime_probe_client; |
| } |
| |
| std::unique_ptr<ShillClient> CreateShillClient(bool* cellular_disabled) { |
| auto mock_shill_client = std::make_unique<NiceMock<MockShillClient>>(); |
| if (cellular_disabled) { |
| ON_CALL(*mock_shill_client, DisableCellular()) |
| .WillByDefault(DoAll(Assign(cellular_disabled, true), Return(true))); |
| } else { |
| ON_CALL(*mock_shill_client, DisableCellular()) |
| .WillByDefault(Return(true)); |
| } |
| return mock_shill_client; |
| } |
| |
| std::unique_ptr<TpmManagerClient> CreateTpmManagerClient( |
| RoVerificationStatus ro_verification_status) { |
| auto mock_tpm_manager_client = |
| std::make_unique<NiceMock<MockTpmManagerClient>>(); |
| ON_CALL(*mock_tpm_manager_client, GetRoVerificationStatus(_)) |
| .WillByDefault( |
| DoAll(SetArgPointee<0>(ro_verification_status), Return(true))); |
| return mock_tpm_manager_client; |
| } |
| |
| std::unique_ptr<PowerManagerClient> CreatePowerManagerClient() { |
| return std::make_unique<NiceMock<MockPowerManagerClient>>(); |
| } |
| |
| std::unique_ptr<UdevUtils> CreateUdevUtils(int num_devices = 0) { |
| auto mock_udev_utils = std::make_unique<NiceMock<MockUdevUtils>>(); |
| ON_CALL(*mock_udev_utils, EnumerateBlockDevices()) |
| .WillByDefault(Invoke([num_devices]() { |
| std::vector<std::unique_ptr<UdevDevice>> devices; |
| for (int i = 0; i < num_devices; ++i) { |
| auto mock_device = std::make_unique<NiceMock<MockUdevDevice>>(); |
| ON_CALL(*mock_device, IsRemovable()).WillByDefault(Return(true)); |
| ON_CALL(*mock_device, GetDeviceNode()) |
| .WillByDefault( |
| Return(base::StringPrintf(kDeviceFileFormat, 'a' + i))); |
| devices.push_back(std::move(mock_device)); |
| } |
| return devices; |
| })); |
| return mock_udev_utils; |
| } |
| |
| std::unique_ptr<CmdUtils> CreateCmdUtils( |
| const std::vector<std::string>& statuses = {}, |
| const std::vector<std::string>& logs = {}) { |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); |
| ON_CALL(*mock_cmd_utils, |
| GetOutput(std::vector<std::string>( |
| {"/usr/sbin/croslog", "--identifier=rmad"}), |
| _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(kFakeRawLog), Return(true))); |
| { |
| InSequence seq; |
| for (std::string status : statuses) { |
| EXPECT_CALL( |
| *mock_cmd_utils, |
| GetOutput(std::vector<std::string>( |
| {"/sbin/initctl", "status", "system-services"}), |
| _)) |
| .WillOnce(DoAll(SetArgPointee<1>(status), Return(true))); |
| } |
| EXPECT_CALL(*mock_cmd_utils, |
| GetOutput(std::vector<std::string>( |
| {"/sbin/initctl", "status", "system-services"}), |
| _)) |
| .WillRepeatedly(DoAll(SetArgPointee<1>("running"), Return(true))); |
| } |
| { |
| InSequence seq; |
| for (std::string log : logs) { |
| EXPECT_CALL(*mock_cmd_utils, |
| GetOutput(std::vector<std::string>( |
| {"/usr/sbin/croslog", "--identifier=rmad"}), |
| _)) |
| .WillOnce(DoAll(SetArgPointee<1>(log), Return(true))); |
| } |
| EXPECT_CALL(*mock_cmd_utils, |
| GetOutput(std::vector<std::string>( |
| {"/usr/sbin/croslog", "--identifier=rmad"}), |
| _)) |
| .WillRepeatedly(DoAll(SetArgPointee<1>("fake_log"), Return(true))); |
| } |
| return mock_cmd_utils; |
| } |
| |
| std::unique_ptr<MetricsUtils> CreateMetricsUtils(bool success) { |
| auto mock_metrics_utils = std::make_unique<NiceMock<MockMetricsUtils>>(); |
| ON_CALL(*mock_metrics_utils, RecordAll(_)).WillByDefault(Return(success)); |
| return mock_metrics_utils; |
| } |
| |
| void MountAndWriteLogCallback( |
| uint8_t device_id, |
| const std::string& text_log, |
| const std::string& json_log, |
| const std::string& system_log, |
| const std::string& diagnostics_log, |
| base::OnceCallback<void(const std::optional<std::string>&)> callback) { |
| if (device_id == kMountSuccessDeviceId) { |
| std::move(callback).Run("rma.log"); |
| } else { |
| std::move(callback).Run(std::nullopt); |
| } |
| } |
| |
| void MountDiagnosticsAppCallback( |
| uint8_t device_id, |
| base::OnceCallback<void(const std::optional<DiagnosticsAppInfo>&)> |
| callback) { |
| if (device_id == kMountSuccessDeviceId) { |
| std::move(callback).Run( |
| DiagnosticsAppInfo{.swbn_path = "diagnostics_app.swbn", |
| .crx_path = "diagnostics_app.crx"}); |
| } else { |
| std::move(callback).Run(std::nullopt); |
| } |
| } |
| |
| protected: |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| working_dir_path_ = temp_dir_.GetPath().Append("working_dir"); |
| unencrypted_rma_dir_path_ = temp_dir_.GetPath().Append("rma-data"); |
| ASSERT_TRUE(base::CreateDirectory(working_dir_path_)); |
| ASSERT_TRUE(base::CreateDirectory(unencrypted_rma_dir_path_)); |
| } |
| |
| RmadState welcome_proto_; |
| RmadState components_repair_proto_; |
| RmadState device_destination_proto_; |
| base::ScopedTempDir temp_dir_; |
| base::FilePath working_dir_path_; |
| base::FilePath unencrypted_rma_dir_path_; |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| }; |
| |
| TEST_F(RmadInterfaceImplTest, Setup) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| bool cellular_disabled = false; |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(true), |
| CreateShillClient(&cellular_disabled), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), |
| CreateCmdUtils({"waiting"}), CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| EXPECT_TRUE(cellular_disabled); |
| |
| // Verify the repair start was recorded to logs. |
| base::Value logs(base::Value::Type::DICT); |
| json_store->GetValue(kLogs, &logs); |
| const base::Value::List* events = logs.GetDict().FindList(kEvents); |
| EXPECT_EQ(1, events->size()); |
| |
| const base::Value::Dict& event = (*events)[0].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), event.FindInt(kStateId)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, Setup_WaitForServices_Timeout) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| bool cellular_disabled = false; |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(true), |
| CreateShillClient(&cellular_disabled), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), |
| CreateCmdUtils(std::vector<std::string>(10, "waiting")), |
| CreateMetricsUtils(true)); |
| EXPECT_FALSE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_Set_HasCellular) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| bool cellular_disabled = false; |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(true), |
| CreateShillClient(&cellular_disabled), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| EXPECT_TRUE(cellular_disabled); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_Set_NoCellular) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| bool cellular_disabled = false; |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(&cellular_disabled), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| EXPECT_FALSE(cellular_disabled); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, |
| GetCurrentState_NotInRma_RoVerificationNotTriggered) { |
| base::FilePath json_store_file_path = |
| temp_dir_.GetPath().AppendASCII("missing.json"); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| bool cellular_disabled = false; |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(&cellular_disabled), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, rmad_interface.GetCurrentStateCase()); |
| |
| EXPECT_FALSE(cellular_disabled); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_RMA_NOT_REQUIRED, reply.error()); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, reply.state().state_case()); |
| EXPECT_TRUE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_NotInRma_RoVerificationPass) { |
| base::FilePath json_store_file_path = |
| temp_dir_.GetPath().AppendASCII("missing.json"); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_PASS), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, |
| GetCurrentState_NotInRma_RoVerificationUnsupportedTriggered) { |
| base::FilePath json_store_file_path = |
| temp_dir_.GetPath().AppendASCII("missing.json"); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_UNSUPPORTED_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_CorruptedFile) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| // Make the file read-only. |
| base::SetPosixFilePermissions(json_store_file_path, 0444); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_FALSE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_EmptyFile) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_NotSet) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateNotSetJson, |
| std::size(kCurrentStateNotSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_WithHistory) { |
| base::FilePath json_store_file_path = CreateInputFile( |
| kJsonStoreFileName, kCurrentStateWithRepeatableHistoryJson, |
| std::size(kCurrentStateWithRepeatableHistoryJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_WithUnsupportedState) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateWithUnsupportedStateJson, |
| std::size(kCurrentStateWithUnsupportedStateJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| // TODO(gavindodd): Use mock log to check for expected error. |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_InvalidState) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateInvalidStateJson, |
| std::size(kCurrentStateInvalidStateJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_InvalidJson) { |
| base::FilePath json_store_file_path = CreateInputFile( |
| kJsonStoreFileName, kInvalidJson, std::size(kInvalidJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetCurrentState_InitializeStateFail) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kInitializeCurrentStateFailJson, |
| std::size(kInitializeCurrentStateFailJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerInitializeStateFail(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_MISSING_COMPONENT, reply.error()); |
| EXPECT_FALSE(reply.has_state()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionNextState) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_TRUE(rmad_interface.CanAbort()); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| auto callback1 = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetCurrentState(base::BindOnce(callback1)); |
| |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| |
| TransitionNextStateRequest request; |
| auto callback2 = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback2)); |
| EXPECT_TRUE(rmad_interface.CanAbort()); |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| EXPECT_NEAR(state_metrics[static_cast<int>(RmadState::kWelcome)].overall_time, |
| kInitialStateOverallTime.InSecondsF(), 1e-4); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| |
| auto callback3 = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kDeviceDestination, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_FALSE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback3)); |
| EXPECT_EQ(RmadState::kDeviceDestination, |
| rmad_interface.GetCurrentStateCase()); |
| EXPECT_FALSE(rmad_interface.CanAbort()); |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| EXPECT_NEAR(state_metrics[static_cast<int>(RmadState::kComponentsRepair)] |
| .overall_time, |
| kTestTransitionInterval.InSecondsF(), 1e-4); |
| EXPECT_EQ(RmadState::kDeviceDestination, |
| rmad_interface.GetCurrentStateCase()); |
| |
| // Verify that state transitions were recorded to logs. |
| base::Value logs(base::Value::Type::DICT); |
| json_store->GetValue(kLogs, &logs); |
| const base::Value::List* events = logs.GetDict().FindList(kEvents); |
| EXPECT_EQ(3, events->size()); |
| |
| const base::Value::Dict& event = (*events)[0].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), event.FindInt(kStateId)); |
| |
| const base::Value::Dict& event1 = (*events)[1].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), |
| event1.FindDict(kDetails)->FindInt(kFromStateId)); |
| EXPECT_EQ(static_cast<int>(RmadState::kComponentsRepair), |
| event1.FindDict(kDetails)->FindInt(kToStateId)); |
| |
| const base::Value::Dict& event2 = (*events)[2].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kComponentsRepair), |
| event2.FindDict(kDetails)->FindInt(kFromStateId)); |
| EXPECT_EQ(static_cast<int>(RmadState::kDeviceDestination), |
| event2.FindDict(kDetails)->FindInt(kToStateId)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionNextStateAfterInterval) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateNotSetJson, |
| std::size(kCurrentStateNotSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| // Set up again after a while. |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| |
| TransitionNextStateRequest request; |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| EXPECT_NEAR(state_metrics[static_cast<int>(RmadState::kWelcome)].overall_time, |
| kInitialStateOverallTime.InSecondsF(), 1e-4); |
| |
| // Verify that state transitions were recorded to logs. |
| base::Value logs(base::Value::Type::DICT); |
| json_store->GetValue(kLogs, &logs); |
| const base::Value::List* events = logs.GetDict().FindList(kEvents); |
| EXPECT_EQ(2, events->size()); |
| |
| const base::Value::Dict& event = (*events)[0].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), event.FindInt(kStateId)); |
| |
| const base::Value::Dict& event1 = (*events)[1].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), |
| event1.FindDict(kDetails)->FindInt(kFromStateId)); |
| EXPECT_EQ(static_cast<int>(RmadState::kComponentsRepair), |
| event1.FindDict(kDetails)->FindInt(kToStateId)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TryTransitionNextState) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_TRUE(rmad_interface.CanAbort()); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| rmad_interface.TryTransitionNextStateFromCurrentState(); |
| EXPECT_TRUE(rmad_interface.CanAbort()); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| rmad_interface.TryTransitionNextStateFromCurrentState(); |
| EXPECT_FALSE(rmad_interface.CanAbort()); |
| EXPECT_EQ(RmadState::kDeviceDestination, |
| rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionNextState_MissingHandler) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerMissingHandler(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| TransitionNextStateRequest request; |
| rmad_interface.TransitionNextState(request, base::DoNothing()); |
| // Missing state handler of the next state detected, stay in the current |
| // state. |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionNextState_InitializeNextStateFail) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kInitializeNextStateFailJson, |
| std::size(kInitializeNextStateFailJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerInitializeStateFail(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| TransitionNextStateRequest request; |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_DEVICE_INFO_INVALID, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionNextState_GetNextStateCaseFail) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerGetNextStateCaseFail(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_TRUE(rmad_interface.CanAbort()); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| TransitionNextStateRequest request; |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_REQUEST_ARGS_MISSING, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionPreviousState) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| |
| TransitionNextStateRequest request; |
| auto callback1 = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionNextState(request, base::BindOnce(callback1)); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| task_environment_.FastForwardBy(kTestTransitionInterval); |
| |
| auto callback2 = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionPreviousState(base::BindOnce(callback2)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| EXPECT_NEAR(state_metrics[static_cast<int>(RmadState::kWelcome)].overall_time, |
| kInitialStateOverallTime.InSecondsF(), 1e-4); |
| EXPECT_NEAR(state_metrics[static_cast<int>(RmadState::kComponentsRepair)] |
| .overall_time, |
| kTestTransitionInterval.InSecondsF(), 1e-4); |
| |
| // Verify that state transitions were recorded to logs. |
| base::Value logs(base::Value::Type::DICT); |
| json_store->GetValue(kLogs, &logs); |
| const base::Value::List* events = logs.GetDict().FindList(kEvents); |
| EXPECT_EQ(3, events->size()); |
| |
| const base::Value::Dict& event = (*events)[0].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), event.FindInt(kStateId)); |
| |
| const base::Value::Dict& event1 = (*events)[1].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), |
| event1.FindDict(kDetails)->FindInt(kFromStateId)); |
| EXPECT_EQ(static_cast<int>(RmadState::kComponentsRepair), |
| event1.FindDict(kDetails)->FindInt(kToStateId)); |
| |
| const base::Value::Dict& event2 = (*events)[2].GetDict(); |
| EXPECT_EQ(static_cast<int>(RmadState::kComponentsRepair), |
| event2.FindDict(kDetails)->FindInt(kFromStateId)); |
| EXPECT_EQ(static_cast<int>(RmadState::kWelcome), |
| event2.FindDict(kDetails)->FindInt(kToStateId)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionPreviousState_NoHistory) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_TRANSITION_FAILED, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionPreviousState(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, TransitionPreviousState_MissingHandler) { |
| base::FilePath json_store_file_path = CreateInputFile( |
| kJsonStoreFileName, kCurrentStateWithRepeatableHistoryJson, |
| std::size(kCurrentStateWithRepeatableHistoryJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerMissingHandler(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_TRANSITION_FAILED, reply.error()); |
| EXPECT_EQ(RmadState::kWelcome, reply.state().state_case()); |
| EXPECT_FALSE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionPreviousState(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, |
| TransitionPreviousState_InitializePreviousStateFail) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kInitializePreviousStateFailJson, |
| std::size(kInitializePreviousStateFailJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManagerInitializeStateFail(json_store), |
| CreateRuntimeProbeClient(false), CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetStateReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_MISSING_COMPONENT, reply.error()); |
| EXPECT_EQ(RmadState::kComponentsRepair, reply.state().state_case()); |
| EXPECT_TRUE(reply.can_go_back()); |
| EXPECT_TRUE(reply.can_abort()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.TransitionPreviousState(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, AbortRma) { |
| base::FilePath json_store_file_path = CreateInputFile( |
| kJsonStoreFileName, kCurrentStateWithRepeatableHistoryJson, |
| std::size(kCurrentStateWithRepeatableHistoryJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| // Check that the state file exists now. |
| EXPECT_TRUE(base::PathExists(json_store_file_path)); |
| |
| auto callback = [](const AbortRmaReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_RMA_NOT_REQUIRED, reply.error()); |
| EXPECT_TRUE(quit_daemon); |
| }; |
| rmad_interface.AbortRma(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, rmad_interface.GetCurrentStateCase()); |
| |
| // Check the the state file is cleared. |
| EXPECT_FALSE(base::PathExists(json_store_file_path)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, AbortRma_NoHistory) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kCurrentStateSetJson, |
| std::size(kCurrentStateSetJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| // Check that the state file exists now. |
| EXPECT_TRUE(base::PathExists(json_store_file_path)); |
| |
| auto callback = [](const AbortRmaReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_RMA_NOT_REQUIRED, reply.error()); |
| EXPECT_TRUE(quit_daemon); |
| }; |
| rmad_interface.AbortRma(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::STATE_NOT_SET, rmad_interface.GetCurrentStateCase()); |
| |
| // Check the the state file is cleared. |
| EXPECT_FALSE(base::PathExists(json_store_file_path)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, AbortRma_Failed) { |
| base::FilePath json_store_file_path = CreateInputFile( |
| kJsonStoreFileName, kCurrentStateWithUnrepeatableHistoryJson, |
| std::size(kCurrentStateWithUnrepeatableHistoryJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kDeviceDestination, |
| rmad_interface.GetCurrentStateCase()); |
| |
| // Check that the state file exists now. |
| EXPECT_TRUE(base::PathExists(json_store_file_path)); |
| |
| auto callback = [](const AbortRmaReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_ABORT_FAILED, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.AbortRma(base::BindOnce(callback)); |
| EXPECT_EQ(RmadState::kDeviceDestination, |
| rmad_interface.GetCurrentStateCase()); |
| |
| // Check the the state file still exists. |
| EXPECT_TRUE(base::PathExists(json_store_file_path)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetLog) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, kStateHistoryWithMetricsJson, |
| std::size(kStateHistoryWithMetricsJson) - 1); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), |
| CreateCmdUtils({}, {"test_log"}), CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kComponentsRepair, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback1 = [](const GetLogReply& reply, bool quit_daemon) { |
| EXPECT_FALSE(reply.log().empty()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetLog(base::BindOnce(callback1)); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| auto state_it = |
| state_metrics.find(static_cast<int>(RmadState::kComponentsRepair)); |
| EXPECT_NE(state_it, state_metrics.end()); |
| EXPECT_EQ(state_it->second.get_log_count, 1); |
| |
| auto callback2 = [](const GetLogReply& reply, bool quit_daemon) { |
| EXPECT_FALSE(reply.log().empty()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetLog(base::BindOnce(callback2)); |
| |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| state_it = state_metrics.find(static_cast<int>(RmadState::kComponentsRepair)); |
| EXPECT_NE(state_it, state_metrics.end()); |
| EXPECT_EQ(state_it->second.get_log_count, 2); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, SaveLog_Success) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(10), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| // Inject fake |ExecuteMountAndWriteLog| callback. |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| daemon_callback->SetExecuteMountAndWriteLogCallback( |
| base::BindRepeating(&RmadInterfaceImplTest::MountAndWriteLogCallback, |
| base::Unretained(this))); |
| EXPECT_TRUE(rmad_interface.SetUp(daemon_callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const SaveLogReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ("rma.log", reply.save_path()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.SaveLog("", base::BindOnce(callback)); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| auto state_it = state_metrics.find(static_cast<int>(RmadState::kWelcome)); |
| EXPECT_NE(state_it, state_metrics.end()); |
| EXPECT_EQ(state_it->second.save_log_count, 1); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, SaveLog_NoExternalDisk) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(0), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const SaveLogReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_USB_NOT_FOUND, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.SaveLog("", base::BindOnce(callback)); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| auto state_it = state_metrics.find(static_cast<int>(RmadState::kWelcome)); |
| EXPECT_NE(state_it, state_metrics.end()); |
| EXPECT_EQ(state_it->second.save_log_count, 0); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, SaveLog_NoValidPartition) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(3), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| // Inject fake |ExecuteMountAndWriteLog| callback. |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| daemon_callback->SetExecuteMountAndWriteLogCallback( |
| base::BindRepeating(&RmadInterfaceImplTest::MountAndWriteLogCallback, |
| base::Unretained(this))); |
| EXPECT_TRUE(rmad_interface.SetUp(daemon_callback)); |
| |
| auto callback = [](const SaveLogReply& reply, bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_CANNOT_SAVE_LOG, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.SaveLog("", base::BindOnce(callback)); |
| |
| std::map<int, StateMetricsData> state_metrics; |
| EXPECT_TRUE( |
| MetricsUtils::GetMetricsValue(json_store, kStateMetrics, &state_metrics)); |
| auto state_it = state_metrics.find(static_cast<int>(RmadState::kWelcome)); |
| EXPECT_NE(state_it, state_metrics.end()); |
| EXPECT_EQ(state_it->second.save_log_count, 0); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, RecordBrowserActionMetric) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const RecordBrowserActionMetricReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| RecordBrowserActionMetricRequest request; |
| request.set_diagnostics(true); |
| request.set_os_update(true); |
| |
| rmad_interface.RecordBrowserActionMetric(request, base::BindOnce(callback)); |
| |
| std::vector<std::string> additional_activities; |
| EXPECT_TRUE(MetricsUtils::GetMetricsValue( |
| json_store, kMetricsAdditionalActivities, &additional_activities)); |
| EXPECT_EQ(additional_activities, |
| std::vector<std::string>( |
| {AdditionalActivity_Name(RMAD_ADDITIONAL_ACTIVITY_DIAGNOSTICS), |
| AdditionalActivity_Name(RMAD_ADDITIONAL_ACTIVITY_OS_UPDATE)})); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, ExtractExternalDiagnosticsApp_Success) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(10), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| // Inject fake |ExecuteMountAndCopyDiagnosticsApp| callback. |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| daemon_callback->SetExecuteMountAndCopyDiagnosticsAppCallback( |
| base::BindRepeating(&RmadInterfaceImplTest::MountDiagnosticsAppCallback, |
| base::Unretained(this))); |
| EXPECT_TRUE(rmad_interface.SetUp(daemon_callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const ExtractExternalDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ("diagnostics_app.swbn", reply.diagnostics_app_swbn_path()); |
| EXPECT_EQ("diagnostics_app.crx", reply.diagnostics_app_crx_path()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.ExtractExternalDiagnosticsApp(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, ExtractExternalDiagnosticsApp_NoExternalDisk) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(0), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| // Inject fake |ExecuteMountAndCopyDiagnosticsApp| callback. |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| daemon_callback->SetExecuteMountAndCopyDiagnosticsAppCallback( |
| base::BindRepeating(&RmadInterfaceImplTest::MountDiagnosticsAppCallback, |
| base::Unretained(this))); |
| EXPECT_TRUE(rmad_interface.SetUp(daemon_callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const ExtractExternalDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_USB_NOT_FOUND, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.ExtractExternalDiagnosticsApp(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, ExtractExternalDiagnosticsApp_NoValidPartition) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(3), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| // Inject fake |ExecuteMountAndCopyDiagnosticsApp| callback. |
| auto daemon_callback = base::MakeRefCounted<DaemonCallback>(); |
| daemon_callback->SetExecuteMountAndCopyDiagnosticsAppCallback( |
| base::BindRepeating(&RmadInterfaceImplTest::MountDiagnosticsAppCallback, |
| base::Unretained(this))); |
| EXPECT_TRUE(rmad_interface.SetUp(daemon_callback)); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const ExtractExternalDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_DIAGNOSTICS_APP_NOT_FOUND, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.ExtractExternalDiagnosticsApp(base::BindOnce(callback)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, InstallExtractedDiagnosticsApp_Success) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| // Create diagnostics app in working directory. |
| EXPECT_TRUE( |
| base::WriteFile(working_dir_path_.Append("diagnostics_app.swbn"), "123")); |
| EXPECT_TRUE( |
| base::WriteFile(working_dir_path_.Append("diagnostics_app.crx"), "456")); |
| |
| auto callback = [](const InstallExtractedDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.InstallExtractedDiagnosticsApp(base::BindOnce(callback)); |
| |
| // Check that the files are copied to unencrypted RMA directory. |
| std::string swbn_data, crx_data; |
| EXPECT_TRUE(base::ReadFileToString( |
| unencrypted_rma_dir_path_.Append("diagnostics_app.swbn"), &swbn_data)); |
| EXPECT_EQ("123", swbn_data); |
| EXPECT_TRUE(base::ReadFileToString( |
| unencrypted_rma_dir_path_.Append("diagnostics_app.crx"), &crx_data)); |
| EXPECT_EQ("456", crx_data); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, InstallExtractedDiagnosticsApp_NotFound) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const InstallExtractedDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_DIAGNOSTICS_APP_NOT_FOUND, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.InstallExtractedDiagnosticsApp(base::BindOnce(callback)); |
| |
| EXPECT_FALSE(base::PathExists( |
| unencrypted_rma_dir_path_.Append("diagnostics_app.swbn"))); |
| EXPECT_FALSE(base::PathExists( |
| unencrypted_rma_dir_path_.Append("diagnostics_app.crx"))); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetInstalledDiagnosticsApp_Success) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| // Create diagnostics app in unencrypted RMA directory. |
| const base::FilePath diagnostics_app_swbn_path = |
| unencrypted_rma_dir_path_.Append("diagnostics_app.swbn"); |
| const base::FilePath diagnostics_app_crx_path = |
| unencrypted_rma_dir_path_.Append("diagnostics_app.crx"); |
| EXPECT_TRUE(base::WriteFile(diagnostics_app_swbn_path, "123")); |
| EXPECT_TRUE(base::WriteFile(diagnostics_app_crx_path, "456")); |
| |
| auto callback = [](const base::FilePath& diagnostics_app_swbn_path, |
| const base::FilePath& diagnostics_app_crx_path, |
| const GetInstalledDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_OK, reply.error()); |
| EXPECT_EQ(diagnostics_app_swbn_path.value(), |
| reply.diagnostics_app_swbn_path()); |
| EXPECT_EQ(diagnostics_app_crx_path.value(), |
| reply.diagnostics_app_crx_path()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetInstalledDiagnosticsApp(base::BindOnce( |
| callback, diagnostics_app_swbn_path, diagnostics_app_crx_path)); |
| } |
| |
| TEST_F(RmadInterfaceImplTest, GetInstalledDiagnosticsApp_NotFound) { |
| base::FilePath json_store_file_path = |
| CreateInputFile(kJsonStoreFileName, "", 0); |
| auto json_store = |
| base::MakeRefCounted<JsonStore>(json_store_file_path, false); |
| RmadInterfaceImpl rmad_interface( |
| json_store, working_dir_path_, unencrypted_rma_dir_path_, |
| CreateStateHandlerManager(json_store), CreateRuntimeProbeClient(false), |
| CreateShillClient(nullptr), |
| CreateTpmManagerClient(RMAD_RO_VERIFICATION_NOT_TRIGGERED), |
| CreatePowerManagerClient(), CreateUdevUtils(), CreateCmdUtils(), |
| CreateMetricsUtils(true)); |
| EXPECT_TRUE(rmad_interface.SetUp(base::MakeRefCounted<DaemonCallback>())); |
| EXPECT_EQ(RmadState::kWelcome, rmad_interface.GetCurrentStateCase()); |
| |
| auto callback = [](const GetInstalledDiagnosticsAppReply& reply, |
| bool quit_daemon) { |
| EXPECT_EQ(RMAD_ERROR_DIAGNOSTICS_APP_NOT_FOUND, reply.error()); |
| EXPECT_FALSE(quit_daemon); |
| }; |
| rmad_interface.GetInstalledDiagnosticsApp(base::BindOnce(callback)); |
| } |
| |
| } // namespace rmad |