Add IpmbSensor unit tests
Because everything was packed into IpmbSensor.cpp, which also included
main(), this commit breaks it up into the patterns we have in other
sensors, with <X>main.cpp containing the things for main.
While this doesn't clean up everything, it at least makes
processResponse unit testable, and adds one minor test for it.
Change-Id: I1eabf650ff635211e5b9a94816c2ffce250ed252
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/src/IpmbSensorMain.cpp b/src/IpmbSensorMain.cpp
new file mode 100644
index 0000000..9223264
--- /dev/null
+++ b/src/IpmbSensorMain.cpp
@@ -0,0 +1,160 @@
+#include "IpmbSDRSensor.hpp"
+#include "IpmbSensor.hpp"
+#include "Utils.hpp"
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/container/flat_map.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <sdbusplus/message.hpp>
+
+#include <array>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <variant>
+#include <vector>
+
+std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
+boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
+boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>> sdrsensor;
+
+void sdrHandler(
+ boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>>
+ sdrsensor,
+ sdbusplus::message_t& message,
+ std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
+{
+ std::string objectName;
+ SensorBaseConfigMap values;
+ message.read(objectName, values);
+
+ auto findBus = values.find("Bus");
+ if (findBus == values.end())
+ {
+ return;
+ }
+
+ uint8_t busIndex = loadVariant<uint8_t>(values, "Bus");
+
+ auto& sdrsen = sdrsensor[busIndex];
+ sdrsen = nullptr;
+ sdrsen = std::make_shared<IpmbSDRDevice>(dbusConnection, busIndex);
+ sdrsen->getSDRRepositoryInfo();
+}
+
+void reinitSensors(sdbusplus::message_t& message)
+{
+ constexpr const size_t reinitWaitSeconds = 2;
+ std::string objectName;
+ boost::container::flat_map<std::string, std::variant<std::string>> values;
+ message.read(objectName, values);
+
+ auto findStatus = values.find(power::property);
+ if (findStatus != values.end())
+ {
+ bool powerStatus =
+ std::get<std::string>(findStatus->second).ends_with(".Running");
+ if (powerStatus)
+ {
+ if (!initCmdTimer)
+ {
+ // this should be impossible
+ return;
+ }
+ // we seem to send this command too fast sometimes, wait before
+ // sending
+ initCmdTimer->expires_after(
+ std::chrono::seconds(reinitWaitSeconds));
+
+ initCmdTimer->async_wait([](const boost::system::error_code ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ return; // we're being canceled
+ }
+
+ for (const auto& [name, sensor] : sensors)
+ {
+ if (sensor)
+ {
+ sensor->runInitCmd();
+ }
+ }
+ });
+ }
+ }
+}
+
+int main()
+{
+ boost::asio::io_context io;
+ auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
+ sdbusplus::asio::object_server objectServer(systemBus, true);
+ objectServer.add_manager("/xyz/openbmc_project/sensors");
+ systemBus->request_name("xyz.openbmc_project.IpmbSensor");
+
+ initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
+
+ boost::asio::post(
+ io, [&]() { createSensors(io, objectServer, sensors, systemBus); });
+
+ boost::asio::steady_timer configTimer(io);
+
+ std::function<void(sdbusplus::message_t&)> eventHandler =
+ [&](sdbusplus::message_t&) {
+ configTimer.expires_after(std::chrono::seconds(1));
+ // create a timer because normally multiple properties change
+ configTimer.async_wait([&](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ return; // we're being canceled
+ }
+ createSensors(io, objectServer, sensors, systemBus);
+ if (sensors.empty())
+ {
+ std::cout << "Configuration not detected\n";
+ }
+ });
+ };
+
+ std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
+ setupPropertiesChangedMatches(
+ *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
+
+ sdbusplus::bus::match_t powerChangeMatch(
+ static_cast<sdbusplus::bus_t&>(*systemBus),
+ "type='signal',interface='" + std::string(properties::interface) +
+ "',path='" + std::string(power::path) + "',arg0='" +
+ std::string(power::interface) + "'",
+ reinitSensors);
+
+ auto matchSignal = std::make_shared<sdbusplus::bus::match_t>(
+ static_cast<sdbusplus::bus_t&>(*systemBus),
+ "type='signal',member='PropertiesChanged',path_namespace='" +
+ std::string(inventoryPath) + "',arg0namespace='" +
+ configInterfaceName(sdrInterface) + "'",
+ [&systemBus](sdbusplus::message_t& msg) {
+ sdrHandler(sdrsensor, msg, systemBus);
+ });
+
+ // Watch for entity-manager to remove configuration interfaces
+ // so the corresponding sensors can be removed.
+ auto ifaceRemovedMatch = std::make_shared<sdbusplus::bus::match_t>(
+ static_cast<sdbusplus::bus_t&>(*systemBus),
+ "type='signal',member='InterfacesRemoved',arg0path='" +
+ std::string(inventoryPath) + "/'",
+ [](sdbusplus::message_t& msg) { interfaceRemoved(msg, sensors); });
+
+ setupManufacturingModeMatch(*systemBus);
+ io.run();
+ return 0;
+}