blob: 5c74c30cce90821916bd9b815ad116e0bc1c9d06 [file] [log] [blame] [edit]
#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();
}