blob: c7139f99da124f73fcb0a289618f50de1bb776c3 [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"
Tomáš Pecka23536bf2023-04-27 18:30:55 +02005#include "ietf-hardware/IETFHardware.h"
Tomáš Pecka3649ae12023-04-14 10:40:56 +02006#include "pretty_printers.h"
7#include "test_log_setup.h"
8#include "test_sysrepo_helpers.h"
9#include "tests/configure.cmake.h"
10
11using namespace std::literals;
12
13class FakeI2C : public velia::ietf_hardware::TransientI2C {
14public:
15 FakeI2C(const std::string& fakeHwmonRoot)
16 : TransientI2C({}, {}, {})
17 , m_fakeHwmonRoot(fakeHwmonRoot)
18 {
19 }
20
21 MAKE_CONST_MOCK0(isPresent, bool(), override);
22 MAKE_CONST_MOCK0(bind_mock, void());
23 MAKE_CONST_MOCK0(unbind_mock, void());
24
25 void removeHwmonFile(const std::string& name) const
26 {
27 std::filesystem::remove(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / name);
28 }
29
30 void bind() const override
31 {
32 bind_mock();
33 removeDirectoryTreeIfExists(m_fakeHwmonRoot);
34 std::filesystem::create_directory(m_fakeHwmonRoot);
35 std::filesystem::create_directory(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)));
36
37 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"}) {
38 std::ofstream ofs(m_fakeHwmonRoot / ("hwmon" + std::to_string(m_hwmonNo)) / filename);
39 // I don't really care about the values here, I just need the HWMon class to think that the files exist.
40 ofs << 0 << "\n";
41 }
42 }
43 void unbind() const override
44 {
45 unbind_mock();
46 removeDirectoryTreeIfExists(m_fakeHwmonRoot);
47 m_hwmonNo++;
48 }
49
50private:
51 std::filesystem::path m_fakeHwmonRoot;
52 mutable std::atomic<int> m_hwmonNo = 1;
53};
54
55TEST_CASE("FspYhPsu")
56{
57 TEST_INIT_LOGS;
58 std::atomic<int> counter = 0;
59 const auto fakeHwmonRoot = CMAKE_CURRENT_BINARY_DIR + "/tests/psu"s;
60 removeDirectoryTreeIfExists(fakeHwmonRoot);
61 auto fakeI2c = std::make_shared<FakeI2C>(fakeHwmonRoot);
62 trompeloeil::sequence seq1;
63 std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu;
64 std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
65
66 auto i2cPresence = [&counter] {
67 switch (counter) {
68 case 0:
69 case 2:
70 case 4:
71 return false;
72 case 1:
73 case 3:
74 return true;
75 }
76
77 REQUIRE(false);
78 __builtin_unreachable();
79 };
80
81 ALLOW_CALL(*fakeI2c, isPresent()).LR_RETURN(i2cPresence());
82 REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 1).IN_SEQUENCE(seq1);
83 REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 2).IN_SEQUENCE(seq1);
84 REQUIRE_CALL(*fakeI2c, bind_mock()).LR_WITH(counter == 3).IN_SEQUENCE(seq1);
85 REQUIRE_CALL(*fakeI2c, unbind_mock()).LR_WITH(counter == 4).IN_SEQUENCE(seq1);
86
87 psu = std::make_shared<velia::ietf_hardware::FspYhPsu>(fakeHwmonRoot, "psu", fakeI2c);
88
Tomáš Pecka23536bf2023-04-27 18:30:55 +020089 const velia::ietf_hardware::DataTree expectedDisabled = {
90 {"/ietf-hardware:hardware/component[name='ne:psu']/class", "iana-hardware:power-supply"},
91 {"/ietf-hardware:hardware/component[name='ne:psu']/parent", "ne"},
92 {"/ietf-hardware:hardware/component[name='ne:psu']/state/oper-state", "disabled"}
93 };
94
Tomáš Pecka3649ae12023-04-14 10:40:56 +020095 for (auto i : {0, 1, 2, 3, 4}) {
96 std::this_thread::sleep_for(std::chrono::seconds(4));
97 velia::ietf_hardware::DataTree expected;
98
99 switch (i) {
100 case 0:
Tomáš Pecka23536bf2023-04-27 18:30:55 +0200101 expected = expectedDisabled;
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200102 break;
103 case 1:
104 expected = {
105 {"/ietf-hardware:hardware/component[name='ne:psu']/class", "iana-hardware:power-supply"},
106 {"/ietf-hardware:hardware/component[name='ne:psu']/parent", "ne"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200107 {"/ietf-hardware:hardware/component[name='ne:psu']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200108 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/class", "iana-hardware:sensor"},
109 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/parent", "ne:psu"},
110 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/oper-status", "ok"},
111 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value", "0"},
112 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-precision", "0"},
113 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-scale", "milli"},
114 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200115 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200116 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/class", "iana-hardware:sensor"},
117 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/parent", "ne:psu"},
118 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/oper-status", "ok"},
119 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value", "0"},
120 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-precision", "0"},
121 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-scale", "milli"},
122 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200123 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200124 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/class", "iana-hardware:sensor"},
125 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/parent", "ne:psu"},
126 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/oper-status", "ok"},
127 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value", "0"},
128 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-precision", "0"},
129 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-scale", "milli"},
130 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200131 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200132 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/class", "iana-hardware:module"},
133 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/parent", "ne:psu"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200134 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200135 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/class", "iana-hardware:fan"},
136 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/parent", "ne:psu:fan"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200137 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200138 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/class", "iana-hardware:sensor"},
139 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/parent", "ne:psu:fan:fan1"},
140 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/oper-status", "ok"},
141 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value", "0"},
142 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-precision", "0"},
143 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-scale", "units"},
144 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-type", "rpm"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200145 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200146 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/class", "iana-hardware:sensor"},
147 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/parent", "ne:psu"},
148 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/oper-status", "ok"},
149 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value", "0"},
150 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-precision", "0"},
151 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-scale", "micro"},
152 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-type", "watts"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200153 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200154 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/class", "iana-hardware:sensor"},
155 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/parent", "ne:psu"},
156 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/oper-status", "ok"},
157 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value", "0"},
158 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-precision", "0"},
159 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-scale", "micro"},
160 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-type", "watts"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200161 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200162 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/class", "iana-hardware:sensor"},
163 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/parent", "ne:psu"},
164 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/oper-status", "ok"},
165 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value", "0"},
166 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-precision", "0"},
167 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-scale", "milli"},
168 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-type", "celsius"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200169 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200170 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/class", "iana-hardware:sensor"},
171 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/parent", "ne:psu"},
172 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/oper-status", "ok"},
173 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value", "0"},
174 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-precision", "0"},
175 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-scale", "milli"},
176 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-type", "celsius"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200177 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200178 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/class", "iana-hardware:sensor"},
179 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/parent", "ne:psu"},
180 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/oper-status", "ok"},
181 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value", "0"},
182 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-precision", "0"},
183 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-scale", "milli"},
184 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-type", "volts-DC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200185 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200186 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/class", "iana-hardware:sensor"},
187 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/parent", "ne:psu"},
188 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/oper-status", "ok"},
189 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value", "0"},
190 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-precision", "0"},
191 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-scale", "milli"},
192 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-type", "volts-DC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200193 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200194 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/class", "iana-hardware:sensor"},
195 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/parent", "ne:psu"},
196 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/oper-status", "ok"},
197 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value", "0"},
198 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-precision", "0"},
199 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-scale", "milli"},
200 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-type", "volts-AC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200201 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200202 };
203 break;
204 case 2:
Tomáš Pecka23536bf2023-04-27 18:30:55 +0200205 expected = expectedDisabled;
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200206 break;
207 case 3:
208 // Here I simulate read failure by a file from the hwmon directory. This happens when the user wants data from
209 // a PSU that's no longer there and the watcher thread didn't unbind it yet.
210 fakeI2c->removeHwmonFile("temp1_input");
Tomáš Pecka23536bf2023-04-27 18:30:55 +0200211 expected = expectedDisabled;
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200212 break;
213 case 4:
Tomáš Pecka23536bf2023-04-27 18:30:55 +0200214 expected = expectedDisabled;
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200215 break;
216 }
217
218 REQUIRE(psu->readValues() == expected);
219
220 counter++;
221 }
222
223 waitForCompletionAndBitMore(seq1);
224}