blob: 6578a0ca9a70a9998355ad871e277fb49d659c2e [file] [log] [blame]
#include "trompeloeil_doctest.h"
#include <fstream>
#include "fs-helpers/utils.h"
#include "ietf-hardware/FspYh.h"
#include "ietf-hardware/IETFHardware.h"
#include "pretty_printers.h"
#include "test_log_setup.h"
#include "test_sysrepo_helpers.h"
#include "tests/configure.cmake.h"
using namespace std::literals;
class FakeI2C : public velia::ietf_hardware::TransientI2C {
public:
FakeI2C(const std::string& fakeHwmonRoot)
: TransientI2C({}, {}, {})
, m_fakeHwmonRoot(fakeHwmonRoot)
{
}
MAKE_CONST_MOCK0(isPresent, bool(), override);
MAKE_CONST_MOCK0(bind_mock, void());
MAKE_CONST_MOCK0(unbind_mock, void());
void removeHwmonFile(const std::string& name) const
{
std::filesystem::remove(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / name);
}
void bind() const override
{
bind_mock();
removeDirectoryTreeIfExists(m_fakeHwmonRoot);
std::filesystem::create_directory(m_fakeHwmonRoot);
std::filesystem::create_directory(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)));
for (const auto& filename : {"name", "temp1_input", "temp2_input", "curr1_input", "curr2_input", "curr3_input", "in1_input", "in2_input", "in3_input", "power1_input", "power2_input", "fan1_input"}) {
std::ofstream ofs(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / filename);
// I don't really care about the values here, I just need the HWMon class to think that the files exist.
ofs << 0 << "\n";
}
}
void unbind() const override
{
unbind_mock();
removeDirectoryTreeIfExists(m_fakeHwmonRoot);
m_hwmonNo++;
}
private:
std::filesystem::path m_fakeHwmonRoot;
mutable std::atomic<int> m_hwmonNo = 1;
};
TEST_CASE("FspYhPsu")
{
TEST_INIT_LOGS;
std::atomic<int> counter = 0;
const auto fakeHwmonRoot = CMAKE_CURRENT_BINARY_DIR + "/tests/psu"s;
removeDirectoryTreeIfExists(fakeHwmonRoot);
auto fakeI2c = std::make_shared<FakeI2C>(fakeHwmonRoot);
trompeloeil::sequence seq1;
std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu;
std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
auto i2cPresence = [&counter] {
switch (counter) {
case 0:
case 2:
case 4:
return false;
case 1:
case 3:
return true;
}
REQUIRE(false);
__builtin_unreachable();
};
ALLOW_CALL(*fakeI2c, isPresent()).LR_RETURN(i2cPresence());
REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 1).IN_SEQUENCE(seq1);
REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 2).IN_SEQUENCE(seq1);
REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 3).IN_SEQUENCE(seq1);
REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 4).IN_SEQUENCE(seq1);
psu = std::make_shared<velia::ietf_hardware::FspYhPsu>(fakeHwmonRoot, "psu", fakeI2c);
const velia::ietf_hardware::DataTree expectedDisabled = {
{"/ietf-hardware:hardware/component[name='ne:psu']/class", "iana-hardware:power-supply"},
{"/ietf-hardware:hardware/component[name='ne:psu']/parent", "ne"},
{"/ietf-hardware:hardware/component[name='ne:psu']/state/oper-state", "disabled"}};
std::set<std::string> expectedThresholdsKeys;
for (auto i : {0, 1, 2, 3, 4}) {
std::this_thread::sleep_for(std::chrono::seconds(4));
velia::ietf_hardware::DataTree expected;
switch (i) {
case 0:
expected = expectedDisabled;
expectedThresholdsKeys.clear();
break;
case 1:
expected = {
{"/ietf-hardware:hardware/component[name='ne:psu']/class", "iana-hardware:power-supply"},
{"/ietf-hardware:hardware/component[name='ne:psu']/parent", "ne"},
{"/ietf-hardware:hardware/component[name='ne:psu']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-type", "amperes"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-type", "amperes"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-type", "amperes"},
{"/ietf-hardware:hardware/component[name='ne:psu:current-in']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan']/class", "iana-hardware:module"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/class", "iana-hardware:fan"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/parent", "ne:psu:fan"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/parent", "ne:psu:fan:fan1"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-scale", "units"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-type", "rpm"},
{"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-scale", "micro"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-type", "watts"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-in']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-scale", "micro"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-type", "watts"},
{"/ietf-hardware:hardware/component[name='ne:psu:power-out']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-type", "celsius"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-type", "celsius"},
{"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-type", "volts-DC"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-type", "volts-DC"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/state/oper-state", "enabled"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/class", "iana-hardware:sensor"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/parent", "ne:psu"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/oper-status", "ok"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-precision", "0"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-scale", "milli"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-type", "volts-AC"},
{"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/state/oper-state", "enabled"},
};
expectedThresholdsKeys = {
"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value",
"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value",
};
break;
case 2:
expected = expectedDisabled;
expectedThresholdsKeys.clear();
break;
case 3:
// Here I simulate read failure by a file from the hwmon directory. This happens when the user wants data from
// a PSU that's no longer there and the watcher thread didn't unbind it yet.
fakeI2c->removeHwmonFile("temp1_input");
expected = expectedDisabled;
expectedThresholdsKeys.clear();
break;
case 4:
expected = expectedDisabled;
expectedThresholdsKeys.clear();
break;
}
auto res = psu->readValues();
CAPTURE((int)counter);
REQUIRE(res.data == expected);
std::set<std::string> thresholdsKeys;
std::transform(res.thresholds.begin(), res.thresholds.end(), std::inserter(thresholdsKeys, thresholdsKeys.begin()), [](const auto& kv) { return kv.first; });
REQUIRE(thresholdsKeys == expectedThresholdsKeys);
counter++;
}
waitForCompletionAndBitMore(seq1);
}