| #include "common/entity_manager_interface.hpp" |
| #include "modbus_server_tester.hpp" |
| #include "port/port_factory.hpp" |
| #include "test_base.hpp" |
| |
| #include <xyz/openbmc_project/Configuration/USBPort/aserver.hpp> |
| #include <xyz/openbmc_project/Inventory/Item/client.hpp> |
| |
| #include <gtest/gtest.h> |
| |
| using namespace std::literals; |
| |
| class PortTest; |
| |
| namespace PortIntf = phosphor::modbus::rtu::port; |
| namespace PortConfigIntf = PortIntf::config; |
| namespace RTUIntf = phosphor::modbus::rtu; |
| using PortFactoryIntf = PortIntf::PortFactory; |
| using USBPortConfigServerIntf = |
| sdbusplus::aserver::xyz::openbmc_project::configuration::USBPort<PortTest>; |
| |
| struct properties_t |
| { |
| std::string name = {}; |
| std::string mode = {}; |
| uint64_t baud_rate = {}; |
| uint64_t rts_delay = {}; |
| }; |
| |
| class MockPort : public PortIntf::BasePort |
| { |
| public: |
| MockPort(sdbusplus::async::context& ctx, |
| const PortConfigIntf::Config& config, |
| const std::string& devicePath) : BasePort(ctx, config, devicePath) |
| {} |
| }; |
| |
| class PortTest : public BaseTest |
| { |
| public: |
| static constexpr properties_t properties = {"TestPort", "RS485", 115200, 1}; |
| static constexpr auto clientDevicePath = "/tmp/ttyPortV0"; |
| static constexpr auto serverDevicePath = "/tmp/ttyPortV1"; |
| static constexpr auto serviceName = "xyz.openbmc_project.TestModbusPort"; |
| bool getPortConfigPassed = false; |
| |
| PortTest() : BaseTest(clientDevicePath, serverDevicePath, serviceName) {} |
| |
| void SetUp() override |
| { |
| getPortConfigPassed = false; |
| BaseTest::SetUp(); |
| } |
| |
| auto TestHoldingRegisters(PortConfigIntf::Config& config, MockPort& port, |
| uint16_t registerOffset, bool res) |
| -> sdbusplus::async::task<void> |
| { |
| std::vector<uint16_t> registers( |
| TestIntf::testSuccessReadHoldingRegisterCount); |
| |
| auto ret = co_await port.readHoldingRegisters( |
| TestIntf::testDeviceAddress, registerOffset, config.baudRate, |
| RTUIntf::Parity::none, registers); |
| |
| EXPECT_EQ(ret, res) << "Failed to read holding registers"; |
| |
| if (!res) |
| { |
| co_return; |
| } |
| |
| for (auto i = 0; i < TestIntf::testSuccessReadHoldingRegisterCount; i++) |
| { |
| EXPECT_EQ(registers[i], |
| TestIntf::testSuccessReadHoldingRegisterResponse[i]); |
| } |
| |
| co_return; |
| } |
| |
| template <typename Config, typename Properties> |
| static inline void VerifyConfig(const Config& config, |
| const Properties& property) |
| { |
| EXPECT_EQ(config, property); |
| } |
| |
| auto TestGetUSBPortConfig( |
| const USBPortConfigServerIntf::properties_t properties, bool shouldPass) |
| -> sdbusplus::async::task<void> |
| { |
| static constexpr auto objectPath = |
| "/xyz/openbmc_project/inventory/system/board/Ventura_Modbus/DevTTYUSB0"; |
| |
| auto configServer = std::make_unique<USBPortConfigServerIntf>( |
| ctx, objectPath, properties); |
| |
| auto config = co_await PortFactoryIntf::getConfig( |
| ctx, std::string(objectPath), USBPortConfigServerIntf::interface); |
| |
| if (!shouldPass) |
| { |
| VerifyConfig(config, nullptr); |
| co_return; |
| } |
| |
| VerifyConfig(config->name, properties.name); |
| VerifyConfig(config->portMode, PortConfigIntf::PortMode::rs485); |
| VerifyConfig(config->baudRate, properties.baud_rate); |
| VerifyConfig(config->rtsDelay, properties.rts_delay); |
| |
| getPortConfigPassed = true; |
| |
| co_return; |
| } |
| }; |
| |
| TEST_F(PortTest, TestUpdateConfig) |
| { |
| PortConfigIntf::Config config = {}; |
| auto res = PortConfigIntf::updateBaseConfig(config, properties); |
| EXPECT_TRUE(res) << "Failed to update config"; |
| |
| EXPECT_EQ(config.name, properties.name); |
| EXPECT_EQ(config.portMode, PortConfigIntf::PortMode::rs485); |
| EXPECT_EQ(config.baudRate, properties.baud_rate); |
| EXPECT_EQ(config.rtsDelay, properties.rts_delay); |
| } |
| |
| TEST_F(PortTest, TestGetUSBPortConfigSucess) |
| { |
| using InventoryIntf = |
| sdbusplus::client::xyz::openbmc_project::inventory::Item<>; |
| sdbusplus::server::manager_t manager{ctx, InventoryIntf::namespace_path}; |
| |
| const USBPortConfigServerIntf::properties_t properties = { |
| .type = "USBPort", |
| .name = "USBPort1", |
| .device_address = "0xa", |
| .device_interface = 1, |
| .port = 1, |
| .mode = "RS485", |
| .baud_rate = 115200, |
| .rts_delay = 100}; |
| |
| ctx.spawn(TestGetUSBPortConfig(properties, true)); |
| |
| ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) | |
| sdbusplus::async::execution::then([&]() { ctx.request_stop(); })); |
| |
| ctx.request_name(entity_manager::EntityManagerInterface::serviceName); |
| ctx.run(); |
| |
| EXPECT_EQ(getPortConfigPassed, true); |
| } |
| |
| TEST_F(PortTest, TestGetUSBPortConfigFailureForInvalidPortMode) |
| { |
| using InventoryIntf = |
| sdbusplus::client::xyz::openbmc_project::inventory::Item<>; |
| sdbusplus::server::manager_t manager{ctx, InventoryIntf::namespace_path}; |
| |
| const USBPortConfigServerIntf::properties_t properties = { |
| .type = "USBPort", |
| .name = "USBPort1", |
| .device_address = "0xa", |
| .device_interface = 1, |
| .port = 1, |
| .mode = "RSXXX", // Invalid port mode |
| .baud_rate = 115200, |
| .rts_delay = 100}; |
| |
| ctx.spawn(TestGetUSBPortConfig(properties, false)); |
| |
| ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) | |
| sdbusplus::async::execution::then([&]() { ctx.request_stop(); })); |
| |
| ctx.request_name(entity_manager::EntityManagerInterface::serviceName); |
| ctx.run(); |
| |
| EXPECT_EQ(getPortConfigPassed, false); |
| } |
| |
| TEST_F(PortTest, TestReadHoldingRegisterSuccess) |
| { |
| PortConfigIntf::Config config = {}; |
| auto res = PortConfigIntf::updateBaseConfig(config, properties); |
| EXPECT_TRUE(res) << "Failed to update config"; |
| |
| MockPort port(ctx, config, clientDevicePath); |
| |
| ctx.spawn(TestHoldingRegisters( |
| config, port, TestIntf::testSuccessReadHoldingRegisterOffset, true)); |
| |
| ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) | |
| sdbusplus::async::execution::then([&]() { ctx.request_stop(); })); |
| |
| ctx.run(); |
| } |
| |
| TEST_F(PortTest, TestReadHoldingRegisterFailure) |
| { |
| PortConfigIntf::Config config = {}; |
| auto res = PortConfigIntf::updateBaseConfig(config, properties); |
| EXPECT_TRUE(res) << "Failed to update config"; |
| |
| MockPort port(ctx, config, clientDevicePath); |
| |
| ctx.spawn(TestHoldingRegisters( |
| config, port, TestIntf::testFailureReadHoldingRegister, false)); |
| |
| ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) | |
| sdbusplus::async::execution::then([&]() { ctx.request_stop(); })); |
| |
| ctx.run(); |
| } |