blob: fbf36c4eff21551cbb1105cdfe749483460af175 [file] [log] [blame]
Tomáš Pecka3649ae12023-04-14 10:40:56 +02001#include "trompeloeil_doctest.h"
2#include <fstream>
3#include "fs-helpers/utils.h"
4#include "ietf-hardware/FspYhPsu.h"
5#include "pretty_printers.h"
6#include "test_log_setup.h"
7#include "test_sysrepo_helpers.h"
8#include "tests/configure.cmake.h"
9
10using namespace std::literals;
11
12class FakeI2C : public velia::ietf_hardware::TransientI2C {
13public:
14 FakeI2C(const std::string& fakeHwmonRoot)
15 : TransientI2C({}, {}, {})
16 , m_fakeHwmonRoot(fakeHwmonRoot)
17 {
18 }
19
20 MAKE_CONST_MOCK0(isPresent, bool(), override);
21 MAKE_CONST_MOCK0(bind_mock, void());
22 MAKE_CONST_MOCK0(unbind_mock, void());
23
24 void removeHwmonFile(const std::string& name) const
25 {
26 std::filesystem::remove(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / name);
27 }
28
29 void bind() const override
30 {
31 bind_mock();
32 removeDirectoryTreeIfExists(m_fakeHwmonRoot);
33 std::filesystem::create_directory(m_fakeHwmonRoot);
34 std::filesystem::create_directory(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)));
35
36 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"}) {
37 std::ofstream ofs(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / filename);
38 // I don't really care about the values here, I just need the HWMon class to think that the files exist.
39 ofs << 0 << "\n";
40 }
41 }
42 void unbind() const override
43 {
44 unbind_mock();
45 removeDirectoryTreeIfExists(m_fakeHwmonRoot);
46 m_hwmonNo++;
47 }
48
49private:
50 std::filesystem::path m_fakeHwmonRoot;
51 mutable std::atomic<int> m_hwmonNo = 1;
52};
53
54TEST_CASE("FspYhPsu")
55{
56 TEST_INIT_LOGS;
57 std::atomic<int> counter = 0;
58 const auto fakeHwmonRoot = CMAKE_CURRENT_BINARY_DIR + "/tests/psu"s;
59 removeDirectoryTreeIfExists(fakeHwmonRoot);
60 auto fakeI2c = std::make_shared<FakeI2C>(fakeHwmonRoot);
61 trompeloeil::sequence seq1;
62 std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu;
63 std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
64
65 auto i2cPresence = [&counter] {
66 switch (counter) {
67 case 0:
68 case 2:
69 case 4:
70 return false;
71 case 1:
72 case 3:
73 return true;
74 }
75
76 REQUIRE(false);
77 __builtin_unreachable();
78 };
79
80 ALLOW_CALL(*fakeI2c, isPresent()).LR_RETURN(i2cPresence());
81 REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 1).IN_SEQUENCE(seq1);
82 REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 2).IN_SEQUENCE(seq1);
83 REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 3).IN_SEQUENCE(seq1);
84 REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 4).IN_SEQUENCE(seq1);
85
86 psu = std::make_shared<velia::ietf_hardware::FspYhPsu>(fakeHwmonRoot, "psu", fakeI2c);
87
88 for (auto i : {0, 1, 2, 3, 4}) {
89 std::this_thread::sleep_for(std::chrono::seconds(4));
90 velia::ietf_hardware::DataTree expected;
91
92 switch (i) {
93 case 0:
94 break;
95 case 1:
96 expected = {
97 {"/ietf-hardware:hardware/component[name='ne:psu']/class", "iana-hardware:power-supply"},
98 {"/ietf-hardware:hardware/component[name='ne:psu']/parent", "ne"},
99 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/class", "iana-hardware:sensor"},
100 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/parent", "ne:psu"},
101 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/oper-status", "ok"},
102 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value", "0"},
103 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-precision", "0"},
104 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-scale", "milli"},
105 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-type", "amperes"},
106 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/class", "iana-hardware:sensor"},
107 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/parent", "ne:psu"},
108 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/oper-status", "ok"},
109 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value", "0"},
110 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-precision", "0"},
111 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-scale", "milli"},
112 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-type", "amperes"},
113 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/class", "iana-hardware:sensor"},
114 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/parent", "ne:psu"},
115 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/oper-status", "ok"},
116 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value", "0"},
117 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-precision", "0"},
118 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-scale", "milli"},
119 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-type", "amperes"},
120 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/class", "iana-hardware:module"},
121 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/parent", "ne:psu"},
122 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/class", "iana-hardware:fan"},
123 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/parent", "ne:psu:fan"},
124 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/class", "iana-hardware:sensor"},
125 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/parent", "ne:psu:fan:fan1"},
126 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/oper-status", "ok"},
127 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value", "0"},
128 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-precision", "0"},
129 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-scale", "units"},
130 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-type", "rpm"},
131 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/class", "iana-hardware:sensor"},
132 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/parent", "ne:psu"},
133 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/oper-status", "ok"},
134 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value", "0"},
135 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-precision", "0"},
136 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-scale", "micro"},
137 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-type", "watts"},
138 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/class", "iana-hardware:sensor"},
139 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/parent", "ne:psu"},
140 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/oper-status", "ok"},
141 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value", "0"},
142 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-precision", "0"},
143 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-scale", "micro"},
144 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-type", "watts"},
145 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/class", "iana-hardware:sensor"},
146 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/parent", "ne:psu"},
147 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/oper-status", "ok"},
148 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value", "0"},
149 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-precision", "0"},
150 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-scale", "milli"},
151 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-type", "celsius"},
152 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/class", "iana-hardware:sensor"},
153 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/parent", "ne:psu"},
154 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/oper-status", "ok"},
155 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value", "0"},
156 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-precision", "0"},
157 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-scale", "milli"},
158 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-type", "celsius"},
159 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/class", "iana-hardware:sensor"},
160 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/parent", "ne:psu"},
161 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/oper-status", "ok"},
162 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value", "0"},
163 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-precision", "0"},
164 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-scale", "milli"},
165 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-type", "volts-DC"},
166 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/class", "iana-hardware:sensor"},
167 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/parent", "ne:psu"},
168 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/oper-status", "ok"},
169 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value", "0"},
170 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-precision", "0"},
171 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-scale", "milli"},
172 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-type", "volts-DC"},
173 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/class", "iana-hardware:sensor"},
174 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/parent", "ne:psu"},
175 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/oper-status", "ok"},
176 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value", "0"},
177 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-precision", "0"},
178 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-scale", "milli"},
179 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-type", "volts-AC"},
180 };
181 break;
182 case 2:
183 break;
184 case 3:
185 // Here I simulate read failure by a file from the hwmon directory. This happens when the user wants data from
186 // a PSU that's no longer there and the watcher thread didn't unbind it yet.
187 fakeI2c->removeHwmonFile("temp1_input");
188 break;
189 case 4:
190 break;
191 }
192
193 REQUIRE(psu->readValues() == expected);
194
195 counter++;
196 }
197
198 waitForCompletionAndBitMore(seq1);
199}