1*cad9ecf6SJagpal Singh Gill #include "inventory/modbus_inventory.hpp"
2*cad9ecf6SJagpal Singh Gill #include "modbus_server_tester.hpp"
3*cad9ecf6SJagpal Singh Gill #include "port/base_port.hpp"
4*cad9ecf6SJagpal Singh Gill
5*cad9ecf6SJagpal Singh Gill #include <fcntl.h>
6*cad9ecf6SJagpal Singh Gill
7*cad9ecf6SJagpal Singh Gill #include <xyz/openbmc_project/Inventory/Source/Modbus/FRU/client.hpp>
8*cad9ecf6SJagpal Singh Gill
9*cad9ecf6SJagpal Singh Gill #include <gtest/gtest.h>
10*cad9ecf6SJagpal Singh Gill
11*cad9ecf6SJagpal Singh Gill using namespace std::literals;
12*cad9ecf6SJagpal Singh Gill using namespace testing;
13*cad9ecf6SJagpal Singh Gill using InventorySourceIntf =
14*cad9ecf6SJagpal Singh Gill sdbusplus::client::xyz::openbmc_project::inventory::source::modbus::FRU<>;
15*cad9ecf6SJagpal Singh Gill
16*cad9ecf6SJagpal Singh Gill namespace TestIntf = phosphor::modbus::test;
17*cad9ecf6SJagpal Singh Gill namespace ModbusIntf = phosphor::modbus::rtu;
18*cad9ecf6SJagpal Singh Gill namespace PortIntf = phosphor::modbus::rtu::port;
19*cad9ecf6SJagpal Singh Gill namespace PortConfigIntf = PortIntf::config;
20*cad9ecf6SJagpal Singh Gill namespace InventoryIntf = phosphor::modbus::rtu::inventory;
21*cad9ecf6SJagpal Singh Gill namespace InventoryConfigIntf = InventoryIntf::config;
22*cad9ecf6SJagpal Singh Gill
23*cad9ecf6SJagpal Singh Gill class MockPort : public PortIntf::BasePort
24*cad9ecf6SJagpal Singh Gill {
25*cad9ecf6SJagpal Singh Gill public:
MockPort(sdbusplus::async::context & ctx,const PortConfigIntf::Config & config,const std::string & devicePath)26*cad9ecf6SJagpal Singh Gill MockPort(sdbusplus::async::context& ctx,
27*cad9ecf6SJagpal Singh Gill const PortConfigIntf::Config& config,
28*cad9ecf6SJagpal Singh Gill const std::string& devicePath) : BasePort(ctx, config, devicePath)
29*cad9ecf6SJagpal Singh Gill {}
30*cad9ecf6SJagpal Singh Gill };
31*cad9ecf6SJagpal Singh Gill
32*cad9ecf6SJagpal Singh Gill class InventoryTest : public ::testing::Test
33*cad9ecf6SJagpal Singh Gill {
34*cad9ecf6SJagpal Singh Gill public:
35*cad9ecf6SJagpal Singh Gill PortConfigIntf::Config portConfig;
36*cad9ecf6SJagpal Singh Gill static constexpr const char* clientDevicePath =
37*cad9ecf6SJagpal Singh Gill "/tmp/ttyInventoryTestPort0";
38*cad9ecf6SJagpal Singh Gill static constexpr const char* serverDevicePath =
39*cad9ecf6SJagpal Singh Gill "/tmp/ttyInventoryTestPort1";
40*cad9ecf6SJagpal Singh Gill static constexpr const auto defaultBaudeRate = "b115200";
41*cad9ecf6SJagpal Singh Gill static constexpr const auto deviceName = "Test1";
42*cad9ecf6SJagpal Singh Gill static constexpr auto serviceName = "xyz.openbmc_project.TestModbusRTU";
43*cad9ecf6SJagpal Singh Gill int socat_pid = -1;
44*cad9ecf6SJagpal Singh Gill sdbusplus::async::context ctx;
45*cad9ecf6SJagpal Singh Gill int fdClient = -1;
46*cad9ecf6SJagpal Singh Gill std::unique_ptr<TestIntf::ServerTester> serverTester;
47*cad9ecf6SJagpal Singh Gill int fdServer = -1;
48*cad9ecf6SJagpal Singh Gill
InventoryTest()49*cad9ecf6SJagpal Singh Gill InventoryTest()
50*cad9ecf6SJagpal Singh Gill {
51*cad9ecf6SJagpal Singh Gill portConfig.name = "TestPort1";
52*cad9ecf6SJagpal Singh Gill portConfig.portMode = PortConfigIntf::PortMode::rs485;
53*cad9ecf6SJagpal Singh Gill portConfig.baudRate = 115200;
54*cad9ecf6SJagpal Singh Gill portConfig.rtsDelay = 1;
55*cad9ecf6SJagpal Singh Gill
56*cad9ecf6SJagpal Singh Gill std::string socatCmd = std::format(
57*cad9ecf6SJagpal Singh Gill "socat -x -v -d -d pty,link={},rawer,echo=0,parenb,{} pty,link={},rawer,echo=0,parenb,{} & echo $!",
58*cad9ecf6SJagpal Singh Gill serverDevicePath, defaultBaudeRate, clientDevicePath,
59*cad9ecf6SJagpal Singh Gill defaultBaudeRate);
60*cad9ecf6SJagpal Singh Gill
61*cad9ecf6SJagpal Singh Gill // Start socat in the background and capture its PID
62*cad9ecf6SJagpal Singh Gill FILE* fp = popen(socatCmd.c_str(), "r");
63*cad9ecf6SJagpal Singh Gill EXPECT_NE(fp, nullptr) << "Failed to start socat: " << strerror(errno);
64*cad9ecf6SJagpal Singh Gill EXPECT_GT(fscanf(fp, "%d", &socat_pid), 0);
65*cad9ecf6SJagpal Singh Gill pclose(fp);
66*cad9ecf6SJagpal Singh Gill
67*cad9ecf6SJagpal Singh Gill // Wait for socat to start up
68*cad9ecf6SJagpal Singh Gill sleep(1);
69*cad9ecf6SJagpal Singh Gill
70*cad9ecf6SJagpal Singh Gill fdClient = open(clientDevicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
71*cad9ecf6SJagpal Singh Gill EXPECT_NE(fdClient, -1)
72*cad9ecf6SJagpal Singh Gill << "Failed to open serial port " << clientDevicePath
73*cad9ecf6SJagpal Singh Gill << " with error: " << strerror(errno);
74*cad9ecf6SJagpal Singh Gill
75*cad9ecf6SJagpal Singh Gill fdServer = open(serverDevicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
76*cad9ecf6SJagpal Singh Gill EXPECT_NE(fdServer, -1)
77*cad9ecf6SJagpal Singh Gill << "Failed to open serial port " << serverDevicePath
78*cad9ecf6SJagpal Singh Gill << " with error: " << strerror(errno);
79*cad9ecf6SJagpal Singh Gill
80*cad9ecf6SJagpal Singh Gill ctx.request_name(serviceName);
81*cad9ecf6SJagpal Singh Gill
82*cad9ecf6SJagpal Singh Gill serverTester = std::make_unique<TestIntf::ServerTester>(ctx, fdServer);
83*cad9ecf6SJagpal Singh Gill }
84*cad9ecf6SJagpal Singh Gill
~InventoryTest()85*cad9ecf6SJagpal Singh Gill ~InventoryTest() noexcept override
86*cad9ecf6SJagpal Singh Gill {
87*cad9ecf6SJagpal Singh Gill if (fdClient != -1)
88*cad9ecf6SJagpal Singh Gill {
89*cad9ecf6SJagpal Singh Gill close(fdClient);
90*cad9ecf6SJagpal Singh Gill fdClient = -1;
91*cad9ecf6SJagpal Singh Gill }
92*cad9ecf6SJagpal Singh Gill if (fdServer != -1)
93*cad9ecf6SJagpal Singh Gill {
94*cad9ecf6SJagpal Singh Gill close(fdServer);
95*cad9ecf6SJagpal Singh Gill fdServer = -1;
96*cad9ecf6SJagpal Singh Gill }
97*cad9ecf6SJagpal Singh Gill kill(socat_pid, SIGTERM);
98*cad9ecf6SJagpal Singh Gill }
99*cad9ecf6SJagpal Singh Gill
testInventorySourceCreation(std::string objPath)100*cad9ecf6SJagpal Singh Gill auto testInventorySourceCreation(std::string objPath)
101*cad9ecf6SJagpal Singh Gill -> sdbusplus::async::task<void>
102*cad9ecf6SJagpal Singh Gill {
103*cad9ecf6SJagpal Singh Gill InventoryConfigIntf::Config::port_address_map_t addressMap;
104*cad9ecf6SJagpal Singh Gill addressMap[portConfig.name] = {{.start = TestIntf::testDeviceAddress,
105*cad9ecf6SJagpal Singh Gill .end = TestIntf::testDeviceAddress}};
106*cad9ecf6SJagpal Singh Gill InventoryConfigIntf::Config deviceConfig = {
107*cad9ecf6SJagpal Singh Gill .name = deviceName,
108*cad9ecf6SJagpal Singh Gill .addressMap = addressMap,
109*cad9ecf6SJagpal Singh Gill .registers = {{"Model",
110*cad9ecf6SJagpal Singh Gill TestIntf::testReadHoldingRegisterModelOffset,
111*cad9ecf6SJagpal Singh Gill TestIntf::testReadHoldingRegisterModelCount}},
112*cad9ecf6SJagpal Singh Gill .parity = ModbusIntf::Parity::none,
113*cad9ecf6SJagpal Singh Gill .baudRate = 115200};
114*cad9ecf6SJagpal Singh Gill InventoryIntf::Device::serial_port_map_t ports;
115*cad9ecf6SJagpal Singh Gill ports[portConfig.name] =
116*cad9ecf6SJagpal Singh Gill std::make_unique<MockPort>(ctx, portConfig, clientDevicePath);
117*cad9ecf6SJagpal Singh Gill
118*cad9ecf6SJagpal Singh Gill auto inventoryDevice =
119*cad9ecf6SJagpal Singh Gill std::make_unique<InventoryIntf::Device>(ctx, deviceConfig, ports);
120*cad9ecf6SJagpal Singh Gill
121*cad9ecf6SJagpal Singh Gill co_await inventoryDevice->probePorts();
122*cad9ecf6SJagpal Singh Gill
123*cad9ecf6SJagpal Singh Gill // Create InventorySource client interface to read back D-Bus properties
124*cad9ecf6SJagpal Singh Gill auto properties = co_await InventorySourceIntf(ctx)
125*cad9ecf6SJagpal Singh Gill .service(serviceName)
126*cad9ecf6SJagpal Singh Gill .path(objPath)
127*cad9ecf6SJagpal Singh Gill .properties();
128*cad9ecf6SJagpal Singh Gill
129*cad9ecf6SJagpal Singh Gill constexpr auto defaultInventoryValue = "Unknown";
130*cad9ecf6SJagpal Singh Gill
131*cad9ecf6SJagpal Singh Gill EXPECT_EQ(properties.name,
132*cad9ecf6SJagpal Singh Gill std::format("{} {} {}", deviceName,
133*cad9ecf6SJagpal Singh Gill TestIntf::testDeviceAddress, portConfig.name))
134*cad9ecf6SJagpal Singh Gill << "Name mismatch";
135*cad9ecf6SJagpal Singh Gill EXPECT_EQ(properties.address, TestIntf::testDeviceAddress)
136*cad9ecf6SJagpal Singh Gill << "Address mismatch";
137*cad9ecf6SJagpal Singh Gill EXPECT_EQ(properties.link_tty, portConfig.name) << "Link TTY mismatch";
138*cad9ecf6SJagpal Singh Gill EXPECT_EQ(properties.model, TestIntf::testReadHoldingRegisterModelStr)
139*cad9ecf6SJagpal Singh Gill << "Model mismatch";
140*cad9ecf6SJagpal Singh Gill EXPECT_EQ(properties.serial_number, defaultInventoryValue)
141*cad9ecf6SJagpal Singh Gill << "Part Number mismatch";
142*cad9ecf6SJagpal Singh Gill
143*cad9ecf6SJagpal Singh Gill co_return;
144*cad9ecf6SJagpal Singh Gill }
145*cad9ecf6SJagpal Singh Gill
SetUp()146*cad9ecf6SJagpal Singh Gill void SetUp() override
147*cad9ecf6SJagpal Singh Gill {
148*cad9ecf6SJagpal Singh Gill // Process request for probe device call
149*cad9ecf6SJagpal Singh Gill ctx.spawn(serverTester->processRequests());
150*cad9ecf6SJagpal Singh Gill
151*cad9ecf6SJagpal Singh Gill // Process request to read `Model` holding register call
152*cad9ecf6SJagpal Singh Gill ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
153*cad9ecf6SJagpal Singh Gill sdbusplus::async::execution::then([&]() {
154*cad9ecf6SJagpal Singh Gill ctx.spawn(serverTester->processRequests());
155*cad9ecf6SJagpal Singh Gill }));
156*cad9ecf6SJagpal Singh Gill }
157*cad9ecf6SJagpal Singh Gill };
158*cad9ecf6SJagpal Singh Gill
TEST_F(InventoryTest,TestAddInventorySource)159*cad9ecf6SJagpal Singh Gill TEST_F(InventoryTest, TestAddInventorySource)
160*cad9ecf6SJagpal Singh Gill {
161*cad9ecf6SJagpal Singh Gill auto objPath =
162*cad9ecf6SJagpal Singh Gill std::format("{}/{}_{}_{}", InventorySourceIntf::namespace_path,
163*cad9ecf6SJagpal Singh Gill deviceName, TestIntf::testDeviceAddress, portConfig.name);
164*cad9ecf6SJagpal Singh Gill
165*cad9ecf6SJagpal Singh Gill ctx.spawn(testInventorySourceCreation(objPath));
166*cad9ecf6SJagpal Singh Gill
167*cad9ecf6SJagpal Singh Gill ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
168*cad9ecf6SJagpal Singh Gill sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
169*cad9ecf6SJagpal Singh Gill
170*cad9ecf6SJagpal Singh Gill ctx.run();
171*cad9ecf6SJagpal Singh Gill }
172