blob: 01b319e8ea5e04bb046ebbcb8a646f96888129c8 [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"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +020099 {"/ietf-hardware:hardware/component[name='ne:psu']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200100 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/class", "iana-hardware:sensor"},
101 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/parent", "ne:psu"},
102 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/oper-status", "ok"},
103 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value", "0"},
104 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-precision", "0"},
105 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-scale", "milli"},
106 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200107 {"/ietf-hardware:hardware/component[name='ne:psu:current-12V']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200108 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/class", "iana-hardware:sensor"},
109 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/parent", "ne:psu"},
110 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/oper-status", "ok"},
111 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value", "0"},
112 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-precision", "0"},
113 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-scale", "milli"},
114 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200115 {"/ietf-hardware:hardware/component[name='ne:psu:current-5Vsb']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200116 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/class", "iana-hardware:sensor"},
117 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/parent", "ne:psu"},
118 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/oper-status", "ok"},
119 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value", "0"},
120 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-precision", "0"},
121 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-scale", "milli"},
122 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/sensor-data/value-type", "amperes"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200123 {"/ietf-hardware:hardware/component[name='ne:psu:current-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200124 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/class", "iana-hardware:module"},
125 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/parent", "ne:psu"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200126 {"/ietf-hardware:hardware/component[name='ne:psu:fan']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200127 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/class", "iana-hardware:fan"},
128 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/parent", "ne:psu:fan"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200129 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200130 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/class", "iana-hardware:sensor"},
131 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/parent", "ne:psu:fan:fan1"},
132 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/oper-status", "ok"},
133 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value", "0"},
134 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-precision", "0"},
135 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-scale", "units"},
136 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/sensor-data/value-type", "rpm"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200137 {"/ietf-hardware:hardware/component[name='ne:psu:fan:fan1:rpm']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200138 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/class", "iana-hardware:sensor"},
139 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/parent", "ne:psu"},
140 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/oper-status", "ok"},
141 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value", "0"},
142 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-precision", "0"},
143 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-scale", "micro"},
144 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/sensor-data/value-type", "watts"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200145 {"/ietf-hardware:hardware/component[name='ne:psu:power-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200146 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/class", "iana-hardware:sensor"},
147 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/parent", "ne:psu"},
148 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/oper-status", "ok"},
149 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value", "0"},
150 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-precision", "0"},
151 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-scale", "micro"},
152 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/sensor-data/value-type", "watts"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200153 {"/ietf-hardware:hardware/component[name='ne:psu:power-out']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200154 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/class", "iana-hardware:sensor"},
155 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/parent", "ne:psu"},
156 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/oper-status", "ok"},
157 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value", "0"},
158 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-precision", "0"},
159 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-scale", "milli"},
160 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/sensor-data/value-type", "celsius"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200161 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-1']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200162 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/class", "iana-hardware:sensor"},
163 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/parent", "ne:psu"},
164 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/oper-status", "ok"},
165 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value", "0"},
166 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-precision", "0"},
167 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-scale", "milli"},
168 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/sensor-data/value-type", "celsius"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200169 {"/ietf-hardware:hardware/component[name='ne:psu:temperature-2']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200170 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/class", "iana-hardware:sensor"},
171 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/parent", "ne:psu"},
172 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/oper-status", "ok"},
173 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value", "0"},
174 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-precision", "0"},
175 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-scale", "milli"},
176 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/sensor-data/value-type", "volts-DC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200177 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-12V']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200178 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/class", "iana-hardware:sensor"},
179 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/parent", "ne:psu"},
180 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/oper-status", "ok"},
181 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value", "0"},
182 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-precision", "0"},
183 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-scale", "milli"},
184 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/sensor-data/value-type", "volts-DC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200185 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-5Vsb']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200186 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/class", "iana-hardware:sensor"},
187 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/parent", "ne:psu"},
188 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/oper-status", "ok"},
189 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value", "0"},
190 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-precision", "0"},
191 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-scale", "milli"},
192 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/sensor-data/value-type", "volts-AC"},
Tomáš Pecka7eb0c422023-04-21 15:36:33 +0200193 {"/ietf-hardware:hardware/component[name='ne:psu:voltage-in']/state/oper-state", "enabled"},
Tomáš Pecka3649ae12023-04-14 10:40:56 +0200194 };
195 break;
196 case 2:
197 break;
198 case 3:
199 // Here I simulate read failure by a file from the hwmon directory. This happens when the user wants data from
200 // a PSU that's no longer there and the watcher thread didn't unbind it yet.
201 fakeI2c->removeHwmonFile("temp1_input");
202 break;
203 case 4:
204 break;
205 }
206
207 REQUIRE(psu->readValues() == expected);
208
209 counter++;
210 }
211
212 waitForCompletionAndBitMore(seq1);
213}