| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "runtime_probe/functions/ec_component.h" |
| |
| #include <fcntl.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/scoped_file.h> |
| #include <base/json/json_reader.h> |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| #include <brillo/files/file_util.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <libec/get_version_command.h> |
| #include <libec/i2c_passthru_command.h> |
| |
| #include "runtime_probe/probe_function.h" |
| #include "runtime_probe/utils/ec_component_manifest.h" |
| #include "runtime_probe/utils/function_test_utils.h" |
| #include "runtime_probe/utils/ish_component_manifest.h" |
| |
| namespace runtime_probe { |
| namespace { |
| |
| using ::testing::_; |
| using ::testing::ByMove; |
| using ::testing::Invoke; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| |
| // Status codes defined in ec/include/ec_commands.h . |
| constexpr uint32_t kEcResultSuccess = 0; |
| constexpr uint32_t kEcResultTimeout = 10; |
| constexpr uint8_t kEcI2cStatusSuccess = 0; |
| |
| constexpr auto kEcDevPath("dev/cros_ec"); |
| constexpr auto kIshDevPath("dev/cros_ish"); |
| |
| class EcComponentFunctionTest : public BaseFunctionTest { |
| protected: |
| void SetUp() override { |
| run_command_count_ = 0; |
| // Default to EC device. |
| SetUpEcDevice(); |
| |
| auto syscaller = mock_context()->mock_syscaller(); |
| EXPECT_CALL(*syscaller, Usleep(_)).WillRepeatedly(Return()); |
| } |
| |
| class FakeGetEcVersionCommand : public ec::GetVersionCommand { |
| using ec::GetVersionCommand::GetVersionCommand; |
| |
| public: |
| struct ec_response_get_version* Resp() override { return &resp_.value(); } |
| |
| bool EcCommandRun(int fd) override { |
| const auto file_path = brillo::GetFDPath(fd); |
| if (base::EndsWith(file_path.value(), kEcDevPath)) { |
| resp_ = ec_resp_; |
| } else if (base::EndsWith(file_path.value(), kIshDevPath)) { |
| resp_ = ish_resp_; |
| } |
| return resp_.has_value(); |
| } |
| |
| std::optional<struct ec_response_get_version> resp_; |
| std::optional<struct ec_response_get_version> ec_resp_; |
| std::optional<struct ec_response_get_version> ish_resp_; |
| }; |
| |
| class FakeI2cPassthruCommand : public ec::I2cPassthruCommand { |
| public: |
| static std::unique_ptr<FakeI2cPassthruCommand> Create( |
| int* run_counter, |
| bool run_success, |
| uint32_t result, |
| uint8_t i2c_status, |
| const std::vector<uint8_t>& resp_data) { |
| auto cmd = |
| ec::I2cPassthruCommand::Create<FakeI2cPassthruCommand>(0, 0, {0}, 1); |
| cmd->run_counter_ = run_counter; |
| cmd->run_success_ = run_success; |
| cmd->result_ = result; |
| cmd->i2c_status_ = i2c_status; |
| cmd->resp_data_ = resp_data; |
| return cmd; |
| } |
| |
| bool Run(int fd) override { |
| if (run_counter_ != nullptr) { |
| ++*run_counter_; |
| } |
| return run_success_; |
| } |
| |
| uint32_t Result() const override { return result_; } |
| uint8_t I2cStatus() const override { return i2c_status_; } |
| base::span<const uint8_t> RespData() const override { |
| return {resp_data_.begin(), resp_data_.end()}; |
| } |
| |
| private: |
| bool run_success_ = false; |
| uint32_t result_ = 0; |
| uint8_t i2c_status_ = 0; |
| std::vector<uint8_t> resp_data_; |
| int* run_counter_ = nullptr; |
| }; |
| |
| class MockEcComponentFunction : public EcComponentFunction { |
| using EcComponentFunction::EcComponentFunction; |
| |
| public: |
| std::unique_ptr<ec::GetVersionCommand> GetGetVersionCommand() |
| const override { |
| auto cmd = std::make_unique<FakeGetEcVersionCommand>(); |
| cmd->ec_resp_ = ec_response_get_version_; |
| cmd->ish_resp_ = ish_response_get_version_; |
| return cmd; |
| } |
| |
| MOCK_METHOD(std::unique_ptr<ec::I2cPassthruCommand>, |
| GetI2cReadCommand, |
| (uint8_t port, |
| uint8_t addr7, |
| uint8_t offset, |
| const std::vector<uint8_t>& write_data, |
| uint8_t read_len), |
| (const override)); |
| |
| std::optional<struct ec_response_get_version> ec_response_get_version_{ |
| {.version_string_ro = "ro_version", |
| .version_string_rw = "model-0.0.0-abcdefa", |
| .current_image = EC_IMAGE_RW}}; |
| std::optional<struct ec_response_get_version> ish_response_get_version_{ |
| {.version_string_ro = "ro_version", |
| .version_string_rw = "model-ish-0.0.0-abcdefa", |
| .current_image = EC_IMAGE_RW}}; |
| }; |
| |
| void SetUpEcDevice() { SetFile(kEcDevPath, ""); } |
| |
| void SetUpIshDevice() { SetFile(kIshDevPath, ""); } |
| |
| void SetUpEcComponentManifest(const std::string& image_name, |
| const std::string& case_name) { |
| const std::string file_path = |
| base::StringPrintf("cme/component_manifest.%s.json", case_name.c_str()); |
| mock_context()->fake_cros_config()->SetString( |
| kCrosConfigImageNamePath, kCrosConfigImageNameKey, image_name); |
| const base::FilePath manifest_dir = |
| base::FilePath{kCmePath}.Append(image_name); |
| SetDirectory(manifest_dir); |
| ASSERT_TRUE(base::CopyFile( |
| GetTestDataPath().Append(file_path), |
| GetPathUnderRoot(manifest_dir.Append(kEcComponentManifestName)))); |
| } |
| |
| void SetUpIshComponentManifest(const std::string& ish_project_name, |
| const std::string& case_name) { |
| const std::string file_path = |
| base::StringPrintf("cme/component_manifest.%s.json", case_name.c_str()); |
| const base::FilePath manifest_dir = |
| base::FilePath{kIshCmePath}.Append(ish_project_name); |
| SetDirectory(manifest_dir); |
| ASSERT_TRUE(base::CopyFile( |
| GetTestDataPath().Append(file_path), |
| GetPathUnderRoot(manifest_dir.Append(kEcComponentManifestName)))); |
| } |
| |
| void SetFakeEcComponentManifest(const std::string& content) { |
| const std::string image_name = "fake_image"; |
| mock_context()->fake_cros_config()->SetString( |
| kCrosConfigImageNamePath, kCrosConfigImageNameKey, image_name); |
| SetFile({kCmePath, image_name, kEcComponentManifestName}, content); |
| } |
| |
| void SetI2cReadSuccess(MockEcComponentFunction* probe_function, |
| uint8_t port, |
| uint8_t addr7) { |
| auto create_cmd_func = [this] { |
| auto cmd = FakeI2cPassthruCommand::Create( |
| &(this->run_command_count_), true, kEcResultSuccess, |
| kEcI2cStatusSuccess, std::vector<uint8_t>{0x00}); |
| return cmd; |
| }; |
| ON_CALL(*probe_function, GetI2cReadCommand(port, addr7, _, _, _)) |
| .WillByDefault(Invoke(create_cmd_func)); |
| } |
| |
| void ExpectI2cReadSuccess(MockEcComponentFunction* probe_function, |
| uint8_t port, |
| uint8_t addr7) { |
| auto cmd = FakeI2cPassthruCommand::Create( |
| &(this->run_command_count_), true, kEcResultSuccess, |
| kEcI2cStatusSuccess, std::vector<uint8_t>{0x00}); |
| EXPECT_CALL(*probe_function, GetI2cReadCommand(port, addr7, _, _, _)) |
| .WillOnce(Return(ByMove(std::move(cmd)))); |
| } |
| |
| void ExpectI2cReadSuccessWithResult(MockEcComponentFunction* probe_function, |
| uint8_t port, |
| uint8_t addr7, |
| uint8_t offset, |
| const std::vector<uint8_t>& write_data, |
| uint8_t len, |
| base::span<const uint8_t> return_value, |
| int* run_counter = nullptr) { |
| std::vector<uint8_t> return_value_copy(return_value.begin(), |
| return_value.end()); |
| auto create_cmd_func = [this, return_value_copy, run_counter]() { |
| if (run_counter == nullptr) { |
| return FakeI2cPassthruCommand::Create( |
| &(this->run_command_count_), true, kEcResultSuccess, |
| kEcI2cStatusSuccess, return_value_copy); |
| } |
| return FakeI2cPassthruCommand::Create(run_counter, true, kEcResultSuccess, |
| kEcI2cStatusSuccess, |
| return_value_copy); |
| }; |
| EXPECT_CALL(*probe_function, |
| GetI2cReadCommand(port, addr7, offset, write_data, len)) |
| .WillRepeatedly(Invoke(create_cmd_func)); |
| } |
| |
| void ExpectI2cReadWithLowPowerMode(MockEcComponentFunction* probe_function, |
| uint8_t port, |
| uint8_t addr7, |
| uint8_t offset, |
| const std::vector<uint8_t>& write_data, |
| uint8_t len, |
| base::span<const uint8_t> return_value, |
| int* command_counter_succ, |
| int* command_counter_fail) { |
| std::vector<uint8_t> return_value_copy(return_value.begin(), |
| return_value.end()); |
| auto create_cmd_func_succ = [command_counter_succ, return_value_copy]() { |
| auto cmd = FakeI2cPassthruCommand::Create( |
| command_counter_succ, true, kEcResultSuccess, kEcI2cStatusSuccess, |
| return_value_copy); |
| return cmd; |
| }; |
| auto create_cmd_func_fail = [command_counter_fail, return_value_copy]() { |
| auto cmd = FakeI2cPassthruCommand::Create( |
| command_counter_fail, false, kEcResultTimeout, kEcI2cStatusSuccess, |
| return_value_copy); |
| return cmd; |
| }; |
| |
| EXPECT_CALL(*probe_function, |
| GetI2cReadCommand(port, addr7, offset, write_data, len)) |
| .Times(2) |
| .WillOnce(Invoke(create_cmd_func_fail)) |
| .WillOnce(Invoke(create_cmd_func_succ)); |
| } |
| |
| void SetI2cReadFailed(MockEcComponentFunction* probe_function, |
| uint8_t port, |
| uint8_t addr7) { |
| auto create_cmd_func = [this] { |
| auto cmd = FakeI2cPassthruCommand::Create( |
| &(this->run_command_count_), false, kEcResultTimeout, |
| kEcI2cStatusSuccess, std::vector<uint8_t>()); |
| return cmd; |
| }; |
| ON_CALL(*probe_function, GetI2cReadCommand(port, addr7, _, _, _)) |
| .WillByDefault(Invoke(create_cmd_func)); |
| } |
| |
| int run_command_count_; |
| }; |
| |
| class EcComponentFunctionTestNoExpect : public EcComponentFunctionTest { |
| protected: |
| void SetUp() override { |
| EcComponentFunctionTest::SetUp(); |
| SetUpEcComponentManifest("image1", "no_expect"); |
| } |
| }; |
| |
| class EcComponentFunctionTestWithExpect : public EcComponentFunctionTest { |
| protected: |
| void SetUp() override { |
| EcComponentFunctionTest::SetUp(); |
| SetUpEcComponentManifest("image1", "with_expect"); |
| } |
| }; |
| |
| class EcComponentFunctionTestWithSimilarCommands |
| : public EcComponentFunctionTest { |
| protected: |
| void SetUp() override { |
| EcComponentFunctionTest::SetUp(); |
| SetUpEcComponentManifest("image1", "with_similar_commands"); |
| } |
| }; |
| |
| TEST_F(EcComponentFunctionTestWithSimilarCommands, |
| ProbeWithCommandResultsReused) { |
| auto arguments = base::JSONReader::Read("{\"type\": \"base_sensor\"}", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 1, 0x01, 0x00, |
| std::vector<uint8_t>{0xaa, 0xbb}, 0, {}); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 1, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, {0x11}); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 1, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, {0xbb}); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 1, 0x01, 0xaa, |
| std::vector<uint8_t>{}, 1, {0xff}); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "component_i2c_response_11_bb" |
| }, |
| { |
| "component_name": "component_i2c_with_different_cmds", |
| "component_type": "base_sensor" |
| } |
| ] |
| )JSON")); |
| |
| // The number of invocation count is: |
| // - 3 for probing component_i2c_response_11_22. |
| // - 0 for probing component_i2c_response_11_bb. |
| // - 2 for probing component_i2c_with_different_cmds. |
| // - 0 for probing component_i2c_with_different_cmds_2. |
| EXPECT_EQ(run_command_count_, 5); |
| } |
| |
| class EcComponentFunctionTestWithIsh : public EcComponentFunctionTestNoExpect { |
| protected: |
| void SetUp() override { |
| EcComponentFunctionTestNoExpect::SetUp(); |
| SetUpIshDevice(); |
| SetUpIshComponentManifest("model-ish", "no_expect_ish"); |
| } |
| }; |
| |
| TEST_F(EcComponentFunctionTest, ProbeWithInvalidManifestFailed) { |
| auto arguments = |
| base::JSONReader::Read("{}", base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| ExpectUnorderedListEqual(EvalProbeFunction(probe_function.get()), |
| CreateProbeResultFromJson("[]")); |
| } |
| |
| TEST_F(EcComponentFunctionTestNoExpect, ProbeWithTypeSucceed) { |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "bc12", |
| "name": null |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 |
| SetI2cReadSuccess(probe_function.get(), 2, 0x5f); |
| // bc12_2 |
| SetI2cReadSuccess(probe_function.get(), 3, 0x5f); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_1" |
| }, |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_2" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestNoExpect, ProbeWithNameSucceed) { |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "name": "bc12_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 |
| SetI2cReadSuccess(probe_function.get(), 2, 0x5f); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_1" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestNoExpect, ProbeWithLowPowerModeSucceed) { |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "bc12", |
| "name": "bc12_3" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| int command_counter_1_succ = 0; |
| int command_counter_1_fail = 0; |
| ExpectI2cReadWithLowPowerMode( |
| probe_function.get(), 4, 0x5f, 0, std::vector<uint8_t>{}, 1, {0x00}, |
| &command_counter_1_succ, &command_counter_1_fail); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_3" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestNoExpect, ProbeWithTypeAndNameSucceed) { |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "bc12", |
| "name": "bc12_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 |
| SetI2cReadSuccess(probe_function.get(), 2, 0x5f); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_1" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestNoExpect, ProbeI2cFailed) { |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "bc12", |
| "name": "bc12_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 |
| SetI2cReadFailed(probe_function.get(), 2, 0x5f); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson("[]")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cValueMatch) { |
| constexpr uint8_t kMatchValueForReg0[] = {0x00}; |
| constexpr uint8_t kMatchValueForReg1[] = {0x01}; |
| constexpr uint8_t kMatchValueForReg2[] = {0x02}; |
| constexpr uint8_t kMatchValueForReg3[] = {0x03}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| // base_sensor_1 without a mask |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x00, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg0); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg1); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg2); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x2, 0x03, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg3); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_1" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cMultiBytesValueMatch) { |
| constexpr uint8_t kMatchValueForReg3[] = {0x01, 0x02, 0x03, 0x04}; |
| constexpr uint8_t kMatchValuesForReg4[][4] = {{0x00, 0x11, 0x00, 0x22}, |
| {0x01, 0x11, 0x10, 0x22}, |
| {0x20, 0x11, 0x02, 0x22}, |
| {0xaa, 0x11, 0xbb, 0x22}}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_3" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| |
| for (const auto& match_value_for_reg4 : kMatchValuesForReg4) { |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x03, |
| std::vector<uint8_t>{}, 4, |
| kMatchValueForReg3); |
| // base_sensor_3 with mask 0x00ff00ff. |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x04, |
| std::vector<uint8_t>{}, 4, |
| match_value_for_reg4); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_3" |
| } |
| ] |
| )JSON")); |
| } |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cValueMismatch) { |
| constexpr uint8_t kMismatchValueForReg0[] = {0xff}; |
| constexpr uint8_t kMatchValueForReg1[] = {0x01}; |
| constexpr uint8_t kMatchValueForReg2[] = {0x02}; |
| constexpr uint8_t kMatchValueForReg3[] = {0x03}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x00, |
| std::vector<uint8_t>{}, 1, |
| kMismatchValueForReg0); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg1); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg2); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x2, 0x03, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg3); |
| |
| ExpectUnorderedListEqual(EvalProbeFunction(probe_function.get()), |
| CreateProbeResultFromJson("[]")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cValueLengthMismatch) { |
| constexpr uint8_t kMatchValueForReg0[] = {0x00}; |
| constexpr uint8_t kMismatchValueForReg1[] = {0x01, 0x12}; |
| constexpr uint8_t kMatchValueForReg2[] = {0x02}; |
| constexpr uint8_t kMatchValueForReg3[] = {0x03}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x00, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg0); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, |
| kMismatchValueForReg1); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg2); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x2, 0x03, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg3); |
| |
| ExpectUnorderedListEqual(EvalProbeFunction(probe_function.get()), |
| CreateProbeResultFromJson("[]")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cOnlyOneValueMismatch) { |
| constexpr uint8_t kMismatchValue[] = {0xff}; |
| constexpr uint8_t kMatchedValueForReg0[] = {0x00}; |
| constexpr uint8_t kMatchedValueForReg3[] = {0x22}; |
| constexpr uint8_t kMatchValueForReg3[] = {0x03}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_1" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x00, |
| std::vector<uint8_t>{}, 1, |
| kMatchedValueForReg0); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, kMismatchValue); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, |
| kMatchedValueForReg3); |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x2, 0x03, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg3); |
| |
| ExpectUnorderedListEqual(EvalProbeFunction(probe_function.get()), |
| CreateProbeResultFromJson("[]")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cOptionalValue) { |
| constexpr uint8_t kMismatchValue[] = {0xff}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_2" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // base_sensor_2 |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x02, |
| std::vector<uint8_t>{}, 1, kMismatchValue); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_2" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeI2cWithWriteData) { |
| constexpr uint8_t kUnusedI2cResponseValue[] = {0xff}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_4" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // base_sensor_2 |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x03, |
| std::vector<uint8_t>{0xaa, 0xbb, 0xcc}, 1, |
| kUnusedI2cResponseValue); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_4" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithExpect, ProbeWithLowPowerModeSucceed) { |
| constexpr uint8_t kMatchValueForReg0[] = {0x00}; |
| constexpr uint8_t kMatchValueForReg1[] = {0x01}; |
| auto arguments = base::JSONReader::Read(R"JSON( |
| { |
| "type": "base_sensor", |
| "name": "base_sensor_5" |
| } |
| )JSON", |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| int command_counter_1_succ = 0; |
| int command_counter_1_fail = 0; |
| ExpectI2cReadWithLowPowerMode( |
| probe_function.get(), 3, 0x01, 0x00, std::vector<uint8_t>{}, 1, |
| kMatchValueForReg0, &command_counter_1_succ, &command_counter_1_fail); |
| |
| int command_counter_2 = 0; |
| ExpectI2cReadSuccessWithResult(probe_function.get(), 3, 0x01, 0x01, |
| std::vector<uint8_t>{}, 1, kMatchValueForReg1, |
| &command_counter_2); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| EXPECT_EQ(command_counter_1_succ, 1); |
| EXPECT_EQ(command_counter_1_fail, 1); |
| EXPECT_EQ(command_counter_2, 1); |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_5" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithIsh, ProbeWithIshComponentsSucceed) { |
| auto arguments = |
| base::JSONReader::Read("{}", base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 in the EC component manifest. |
| SetI2cReadSuccess(probe_function.get(), 2, 0x5f); |
| // charger_1 in the ISH component manifest. |
| SetI2cReadSuccess(probe_function.get(), 4, 0x9); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_1" |
| }, |
| { |
| "component_type": "charger", |
| "component_name": "charger_1" |
| } |
| ] |
| )JSON")); |
| } |
| |
| TEST_F(EcComponentFunctionTestWithIsh, ProbeWithoutIshDevFailed) { |
| UnsetPath(kIshDevPath); |
| auto arguments = |
| base::JSONReader::Read("{}", base::JSON_PARSE_CHROMIUM_EXTENSIONS); |
| auto probe_function = |
| CreateProbeFunction<MockEcComponentFunction>(arguments->GetDict()); |
| |
| // bc12_1 in the EC component manifest. |
| SetI2cReadSuccess(probe_function.get(), 2, 0x5f); |
| // charger_1 in the ISH component manifest. |
| SetI2cReadSuccess(probe_function.get(), 4, 0x9); |
| |
| auto actual = EvalProbeFunction(probe_function.get()); |
| |
| ExpectUnorderedListEqual(actual, CreateProbeResultFromJson(R"JSON( |
| [ |
| { |
| "component_type": "bc12", |
| "component_name": "bc12_1" |
| } |
| ] |
| )JSON")); |
| } |
| |
| class EcComponentFunctionTestECVersion : public EcComponentFunctionTest { |
| protected: |
| void SetUp() override { |
| EcComponentFunctionTest::SetUp(); |
| SetFakeEcComponentManifest(R"JSON( |
| { |
| "manifest_version": 1, |
| "ec_version": "model-0.0.0-abcdefa", |
| "component_list": [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_2", |
| "i2c": { |
| "port": 3, |
| "addr": "0x01" |
| } |
| } |
| ] |
| } |
| )JSON"); |
| } |
| |
| void ExpectI2cRead(MockEcComponentFunction* probe_function) { |
| // Expect read the only component in fake manifest above. |
| ExpectI2cReadSuccess(probe_function, 3, 0x01); |
| } |
| |
| void ExpectNoI2cRead(MockEcComponentFunction* probe_function) { |
| EXPECT_CALL(*probe_function, GetI2cReadCommand(_, _, _, _, _)).Times(0); |
| } |
| |
| std::unique_ptr<MockEcComponentFunction> probe_function_{ |
| CreateProbeFunction<MockEcComponentFunction>(base::DictValue{})}; |
| }; |
| |
| TEST_F(EcComponentFunctionTestECVersion, MatchRO) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "model-0.0.0-abcdefa", |
| .version_string_rw = "rw_version", |
| .current_image = EC_IMAGE_RO}; |
| ExpectI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, MatchROB) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "model-0.0.0-abcdefa", |
| .version_string_rw = "rw_version", |
| .current_image = EC_IMAGE_RO_B}; |
| ExpectI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, MatchRW) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "ro_version", |
| .version_string_rw = "model-0.0.0-abcdefa", |
| .current_image = EC_IMAGE_RW}; |
| ExpectI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, MatchRWB) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "ro_version", |
| .version_string_rw = "model-0.0.0-abcdefa", |
| .current_image = EC_IMAGE_RW_B}; |
| ExpectI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, NotMatchRO) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "ro_version", |
| .version_string_rw = "rw_version", |
| .current_image = EC_IMAGE_RO}; |
| ExpectNoI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, NotMatchRW) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "ro_version", |
| .version_string_rw = "rw_version", |
| .current_image = EC_IMAGE_RW}; |
| ExpectNoI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, Unknown) { |
| probe_function_->ec_response_get_version_ = { |
| .version_string_ro = "model-0.0.0-abcdefa", |
| .version_string_rw = "model-0.0.0-abcdefa", |
| .current_image = EC_IMAGE_UNKNOWN}; |
| ExpectNoI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTestECVersion, GetECVersionFailed) { |
| probe_function_->ec_response_get_version_ = std::nullopt; |
| ExpectNoI2cRead(probe_function_.get()); |
| EvalProbeFunction(probe_function_.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTest, ProbeWithManifestPathSuccess) { |
| mock_context()->SetFactoryMode(true); |
| auto manifest_path = "/a/fake/path/manifest.json"; |
| SetFile(manifest_path, R"JSON( |
| { |
| "manifest_version": 1, |
| "ec_version": "model-0.0.0-abcdefa", |
| "component_list": [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_2", |
| "i2c": { |
| "port": 3, |
| "addr": "0x01" |
| } |
| } |
| ] |
| } |
| )JSON"); |
| base::DictValue argument; |
| argument.Set("manifest_path", GetPathUnderRoot(manifest_path).value()); |
| |
| auto probe_function = CreateProbeFunction<MockEcComponentFunction>(argument); |
| ExpectI2cReadSuccess(probe_function.get(), 3, 0x01); |
| EvalProbeFunction(probe_function.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTest, ProbeWithManifestPathNonFactoryMode) { |
| mock_context()->SetFactoryMode(false); |
| base::DictValue argument; |
| argument.Set("manifest_path", "/a/fake/path/manifest.json"); |
| ASSERT_FALSE(CreateProbeFunction<MockEcComponentFunction>(argument)); |
| } |
| |
| TEST_F(EcComponentFunctionTest, ProbeWithIshManifestPathSuccess) { |
| mock_context()->SetFactoryMode(true); |
| SetUpIshDevice(); |
| auto manifest_path = "/a/fake/path/manifest.json"; |
| SetFile(manifest_path, R"JSON( |
| { |
| "manifest_version": 1, |
| "ec_version": "model-ish-0.0.0-abcdefa", |
| "component_list": [ |
| { |
| "component_type": "base_sensor", |
| "component_name": "base_sensor_2", |
| "i2c": { |
| "port": 3, |
| "addr": "0x01" |
| } |
| } |
| ] |
| } |
| )JSON"); |
| base::DictValue argument; |
| argument.Set("ish_manifest_path", GetPathUnderRoot(manifest_path).value()); |
| |
| auto probe_function = CreateProbeFunction<MockEcComponentFunction>(argument); |
| ExpectI2cReadSuccess(probe_function.get(), 3, 0x01); |
| EvalProbeFunction(probe_function.get()); |
| } |
| |
| TEST_F(EcComponentFunctionTest, ProbeWithIshManifestPathNonFactoryMode) { |
| mock_context()->SetFactoryMode(false); |
| SetUpIshDevice(); |
| base::DictValue argument; |
| argument.Set("ish_manifest_path", "/a/fake/path/manifest.json"); |
| ASSERT_FALSE(CreateProbeFunction<MockEcComponentFunction>(argument)); |
| } |
| |
| } // namespace |
| } // namespace runtime_probe |