1 // SPDX-License-Identifier: Apache-2.0
2
3 #include "../functions.hpp"
4
5 #include <stdlib.h>
6
7 #include <array>
8 #include <cerrno>
9 #include <filesystem>
10 #include <fstream>
11 #include <map>
12 #include <string>
13 #include <vector>
14
15 #include <gtest/gtest.h>
16
17 using namespace std::string_literals;
18
TEST(GetExtensionsForIbmCompatibleSystem,testSingleMatch)19 TEST(GetExtensionsForIbmCompatibleSystem, testSingleMatch)
20 {
21 std::map<std::string, std::vector<std::string>> extensionMap{{
22 {"system-foo"s, {".EXT"s}},
23 }};
24 std::vector<std::string> compatibleSystem{"system-foo"s}, extensions;
25 auto found =
26 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
27 extensionMap, compatibleSystem, extensions);
28 EXPECT_TRUE(found);
29 EXPECT_EQ(extensions, std::vector<std::string>{".EXT"s});
30 }
31
TEST(GetExtensionsForIbmCompatibleSystem,testSingleNoMatchNoModify)32 TEST(GetExtensionsForIbmCompatibleSystem, testSingleNoMatchNoModify)
33 {
34 std::map<std::string, std::vector<std::string>> extensionMap{{
35 {"system-bar"s, {".EXT"s}},
36 }};
37 std::vector<std::string> compatibleSystem{"system-foo"s},
38 extensions{"foo"s};
39 auto found =
40 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
41 extensionMap, compatibleSystem, extensions);
42 EXPECT_FALSE(found);
43 EXPECT_EQ(extensions, std::vector<std::string>{"foo"s});
44 }
45
TEST(GetExtensionsForIbmCompatibleSystem,testMatchModify)46 TEST(GetExtensionsForIbmCompatibleSystem, testMatchModify)
47 {
48 std::map<std::string, std::vector<std::string>> extensionMap{{
49 {"system-bar"s, {".BAR"s}},
50 {"system-foo"s, {".FOO"s}},
51 }};
52 std::vector<std::string> compatibleSystem{"system-foo"s},
53 extensions{"foo"s};
54 auto found =
55 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
56 extensionMap, compatibleSystem, extensions);
57 EXPECT_TRUE(found);
58 EXPECT_EQ(extensions, std::vector<std::string>{".FOO"s});
59 }
60
TEST(GetExtensionsForIbmCompatibleSystem,testEmpty)61 TEST(GetExtensionsForIbmCompatibleSystem, testEmpty)
62 {
63 std::map<std::string, std::vector<std::string>> extensionMap;
64 std::vector<std::string> compatibleSystem{"system-foo"s},
65 extensions{"foo"s};
66 auto found =
67 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
68 extensionMap, compatibleSystem, extensions);
69 EXPECT_FALSE(found);
70 EXPECT_EQ(extensions, std::vector<std::string>{"foo"s});
71 }
72
TEST(GetExtensionsForIbmCompatibleSystem,testEmptyEmpty)73 TEST(GetExtensionsForIbmCompatibleSystem, testEmptyEmpty)
74 {
75 std::map<std::string, std::vector<std::string>> extensionMap;
76 std::vector<std::string> compatibleSystem, extensions{"foo"s};
77 auto found =
78 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
79 extensionMap, compatibleSystem, extensions);
80 EXPECT_FALSE(found);
81 EXPECT_EQ(extensions, std::vector<std::string>{"foo"s});
82 }
83
TEST(GetExtensionsForIbmCompatibleSystem,testMatchMultiCompat)84 TEST(GetExtensionsForIbmCompatibleSystem, testMatchMultiCompat)
85 {
86 std::map<std::string, std::vector<std::string>> extensionMap{{
87 {"system-bar"s, {".BAR"s}},
88 {"system-foo"s, {".FOO"s}},
89 }};
90 std::vector<std::string> compatibleSystem{"system-foo"s, "system"},
91 extensions;
92 auto found =
93 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
94 extensionMap, compatibleSystem, extensions);
95 EXPECT_TRUE(found);
96 EXPECT_EQ(extensions, std::vector<std::string>{".FOO"s});
97 }
98
TEST(GetExtensionsForIbmCompatibleSystem,testMultiMatchMultiCompat)99 TEST(GetExtensionsForIbmCompatibleSystem, testMultiMatchMultiCompat)
100 {
101 std::map<std::string, std::vector<std::string>> extensionMap{{
102 {"system-bar"s, {".BAR"s}},
103 {"system-foo"s, {".FOO"s}},
104 }};
105 std::vector<std::string> compatibleSystem{"system-foo"s, "system-bar"},
106 extensions;
107 auto found =
108 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
109 extensionMap, compatibleSystem, extensions);
110 EXPECT_TRUE(found);
111 EXPECT_EQ(extensions, std::vector<std::string>{".FOO"s});
112 }
113
TEST(GetExtensionsForIbmCompatibleSystem,testMultiMatchMultiCompat2)114 TEST(GetExtensionsForIbmCompatibleSystem, testMultiMatchMultiCompat2)
115 {
116 std::map<std::string, std::vector<std::string>> extensionMap{{
117 {"system-foo"s, {".FOO"s}},
118 {"system-bar"s, {".BAR"s}},
119 }};
120 std::vector<std::string> compatibleSystem{"system-foo"s, "system-bar"},
121 extensions;
122 auto found =
123 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
124 extensionMap, compatibleSystem, extensions);
125 EXPECT_TRUE(found);
126 EXPECT_EQ(extensions, std::vector<std::string>{".FOO"s});
127 }
128
TEST(GetExtensionsForIbmCompatibleSystem,testMultiMatchMultiCompat3)129 TEST(GetExtensionsForIbmCompatibleSystem, testMultiMatchMultiCompat3)
130 {
131 std::map<std::string, std::vector<std::string>> extensionMap{{
132 {"system-bar"s, {".BAR"s}},
133 {"system-foo"s, {".FOO"s}},
134 }};
135 std::vector<std::string> compatibleSystem{"system-bar", "system-foo"s},
136 extensions;
137 auto found =
138 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
139 extensionMap, compatibleSystem, extensions);
140 EXPECT_TRUE(found);
141 EXPECT_EQ(extensions, std::vector<std::string>{".BAR"s});
142 }
143
TEST(GetExtensionsForIbmCompatibleSystem,testMultiMatchMultiCompat4)144 TEST(GetExtensionsForIbmCompatibleSystem, testMultiMatchMultiCompat4)
145 {
146 std::map<std::string, std::vector<std::string>> extensionMap{{
147 {"system-foo"s, {".FOO"s}},
148 {"system-bar"s, {".BAR"s}},
149 }};
150 std::vector<std::string> compatibleSystem{"system-bar", "system-foo"s},
151 extensions;
152 auto found =
153 functions::process_hostfirmware::getExtensionsForIbmCompatibleSystem(
154 extensionMap, compatibleSystem, extensions);
155 EXPECT_TRUE(found);
156 EXPECT_EQ(extensions, std::vector<std::string>{".BAR"s});
157 }
158
TEST(MaybeCall,noMatch)159 TEST(MaybeCall, noMatch)
160 {
161 bool called = false;
162 auto callback = [&called](const auto&) { called = true; };
163 std::map<std::string,
164 std::map<std::string, std::variant<std::vector<std::string>>>>
165 interfaces{{
166 {"foo"s, {{"bar"s, std::vector<std::string>{"foo"s}}}},
167 }};
168 auto found = functions::process_hostfirmware::maybeCall(
169 interfaces, std::move(callback));
170 EXPECT_FALSE(found);
171 EXPECT_FALSE(called);
172 }
173
TEST(MaybeCall,match)174 TEST(MaybeCall, match)
175 {
176 bool called = false;
177 std::vector<std::string> sys;
178 auto callback = [&called, &sys](const auto& system) {
179 sys = system;
180 called = true;
181 };
182 std::map<std::string,
183 std::map<std::string, std::variant<std::vector<std::string>>>>
184 interfaces{{
185 {"xyz.openbmc_project.Inventory.Decorator.Compatible"s,
186 {{"Names"s, std::vector<std::string>{"foo"s}}}},
187 }};
188 auto found = functions::process_hostfirmware::maybeCall(
189 interfaces, std::move(callback));
190 EXPECT_TRUE(found);
191 EXPECT_TRUE(called);
192 EXPECT_EQ(sys, std::vector<std::string>{"foo"s});
193 }
194
TEST(MaybeCall,missingNames)195 TEST(MaybeCall, missingNames)
196 {
197 bool called = false;
198 auto callback = [&called](const auto&) { called = true; };
199 std::map<std::string,
200 std::map<std::string, std::variant<std::vector<std::string>>>>
201 interfaces{{
202 {"xyz.openbmc_project.Inventory.Decorator.Compatible"s, {}},
203 }};
204 auto found = functions::process_hostfirmware::maybeCall(
205 interfaces, std::move(callback));
206 EXPECT_TRUE(found);
207 EXPECT_FALSE(called);
208 }
209
TEST(MaybeCall,emptyCallbackFound)210 TEST(MaybeCall, emptyCallbackFound)
211 {
212 std::map<std::string,
213 std::map<std::string, std::variant<std::vector<std::string>>>>
214 interfaces{{
215 {"xyz.openbmc_project.Inventory.Decorator.Compatible"s,
216 {{"Names"s, std::vector<std::string>{"foo"s}}}},
217 }};
218 auto found = functions::process_hostfirmware::maybeCall(
219 interfaces, std::function<void(std::vector<std::string>)>());
220 EXPECT_TRUE(found);
221 }
222
TEST(MaybeCall,emptyCallbackNotFound)223 TEST(MaybeCall, emptyCallbackNotFound)
224 {
225 std::map<std::string,
226 std::map<std::string, std::variant<std::vector<std::string>>>>
227 interfaces{{
228 {"foo"s, {{"Names"s, std::vector<std::string>{"foo"s}}}},
229 }};
230 auto found = functions::process_hostfirmware::maybeCall(
231 interfaces, std::function<void(std::vector<std::string>)>());
232 EXPECT_FALSE(found);
233 }
234
TEST(MaybeCall,emptyInterfaces)235 TEST(MaybeCall, emptyInterfaces)
236 {
237 bool called = false;
238 auto callback = [&called](const auto&) { called = true; };
239 std::map<std::string,
240 std::map<std::string, std::variant<std::vector<std::string>>>>
241 interfaces;
242 auto found = functions::process_hostfirmware::maybeCall(
243 interfaces, std::move(callback));
244 EXPECT_FALSE(found);
245 EXPECT_FALSE(called);
246 }
247
TEST(MaybeCall,emptyInterfacesEmptyCallback)248 TEST(MaybeCall, emptyInterfacesEmptyCallback)
249 {
250 std::map<std::string,
251 std::map<std::string, std::variant<std::vector<std::string>>>>
252 interfaces;
253 auto found = functions::process_hostfirmware::maybeCall(
254 interfaces, std::function<void(std::vector<std::string>)>());
255 EXPECT_FALSE(found);
256 }
257
TEST(WriteLink,testLinkNoDelete)258 TEST(WriteLink, testLinkNoDelete)
259 {
260 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
261 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
262 bool called = false;
263 auto callback = [&called](const auto&, auto&) { called = true; };
264 std::filesystem::path linkPath = workdir / "link";
265 std::filesystem::path targetPath = workdir / "target";
266 std::ofstream link{linkPath};
267 functions::process_hostfirmware::writeLink(linkPath.filename(), targetPath,
268 callback);
269 std::filesystem::remove_all(workdir);
270 EXPECT_FALSE(called);
271 }
272
TEST(WriteLink,testLinkDelete)273 TEST(WriteLink, testLinkDelete)
274 {
275 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
276 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
277 bool called = false;
278 auto callback = [&called](const auto&, auto&) { called = true; };
279 auto linkPath = workdir / "link";
280 auto targetPath = workdir / "target";
281 std::ofstream link{linkPath}, target{targetPath};
282 functions::process_hostfirmware::writeLink(linkPath.filename(), targetPath,
283 callback);
284 std::filesystem::remove_all(workdir);
285 EXPECT_FALSE(called);
286 }
287
TEST(WriteLink,testLinkFailDeleteDir)288 TEST(WriteLink, testLinkFailDeleteDir)
289 {
290 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
291 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
292 std::error_code ec;
293 std::filesystem::path callbackPath;
294 auto callback = [&ec, &callbackPath](const auto& p, auto& _ec) {
295 ec = _ec;
296 callbackPath = p;
297 };
298 auto targetPath = workdir / "target";
299 std::filesystem::create_directory(targetPath);
300 auto linkPath = workdir / "link";
301 auto filePath = targetPath / "file";
302 std::ofstream link{linkPath}, file{filePath};
303 functions::process_hostfirmware::writeLink(linkPath.filename(), targetPath,
304 callback);
305 std::filesystem::remove_all(workdir);
306 EXPECT_EQ(ec.value(), ENOTEMPTY);
307 EXPECT_EQ(callbackPath, targetPath);
308 }
309
TEST(WriteLink,testLinkPathNotExist)310 TEST(WriteLink, testLinkPathNotExist)
311 {
312 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
313 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
314 std::error_code ec;
315 std::filesystem::path callbackPath;
316 auto callback = [&ec, &callbackPath](const auto& p, auto& _ec) {
317 ec = _ec;
318 callbackPath = p;
319 };
320 auto linkPath = workdir / "baz";
321 auto targetPath = workdir / "foo/bar/foo";
322 functions::process_hostfirmware::writeLink(linkPath.filename(), targetPath,
323 callback);
324 std::filesystem::remove_all(workdir);
325 EXPECT_EQ(ec.value(), ENOENT);
326 EXPECT_EQ(callbackPath, targetPath);
327 }
328
TEST(FindLinks,testNoLinks)329 TEST(FindLinks, testNoLinks)
330 {
331 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
332 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
333
334 bool callbackCalled = false, errorCallbackCalled = false;
335 auto callback = [&callbackCalled](const auto&, const auto&, const auto&) {
336 callbackCalled = true;
337 };
338 auto errorCallback = [&errorCallbackCalled](const auto&, auto&) {
339 errorCallbackCalled = true;
340 };
341
342 std::vector<std::string> extensions;
343 functions::process_hostfirmware::findLinks(workdir, extensions,
344 errorCallback, callback);
345 std::filesystem::remove_all(workdir);
346 EXPECT_FALSE(errorCallbackCalled);
347 EXPECT_FALSE(callbackCalled);
348 }
349
TEST(FindLinks,testOneFound)350 TEST(FindLinks, testOneFound)
351 {
352 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
353 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
354 std::filesystem::path callbackPath, callbackLink;
355
356 bool errorCallbackCalled = false;
357 auto callback = [&callbackPath, &callbackLink](
358 const auto& p1, const auto& p2, const auto&) {
359 callbackPath = p1;
360 callbackLink = p2;
361 };
362 auto errorCallback = [&errorCallbackCalled](const auto&, auto&) {
363 errorCallbackCalled = true;
364 };
365
366 auto filePath = workdir / "foo.foo";
367 std::ofstream file{filePath};
368 std::vector<std::string> extensions{".foo"s};
369 functions::process_hostfirmware::findLinks(workdir, extensions,
370 errorCallback, callback);
371 std::filesystem::remove_all(workdir);
372 EXPECT_FALSE(errorCallbackCalled);
373 EXPECT_EQ(callbackLink, workdir / "foo");
374 EXPECT_EQ(callbackPath, filePath.filename());
375 }
376
TEST(FindLinks,testNoExtensions)377 TEST(FindLinks, testNoExtensions)
378 {
379 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
380 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
381 std::filesystem::path callbackPath, callbackLink;
382
383 bool errorCallbackCalled = false, callbackCalled = false;
384 auto callback = [&callbackCalled](const auto&, const auto&, const auto&) {
385 callbackCalled = true;
386 };
387 auto errorCallback = [&errorCallbackCalled](const auto&, auto&) {
388 errorCallbackCalled = true;
389 };
390
391 auto filePath = workdir / "foo.foo";
392 std::ofstream file{filePath};
393 std::vector<std::string> extensions;
394 functions::process_hostfirmware::findLinks(workdir, extensions,
395 errorCallback, callback);
396 std::filesystem::remove_all(workdir);
397 EXPECT_FALSE(errorCallbackCalled);
398 EXPECT_FALSE(callbackCalled);
399 }
400
TEST(FindLinks,testEnoent)401 TEST(FindLinks, testEnoent)
402 {
403 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
404 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
405
406 std::error_code ec;
407 bool called = false;
408 std::filesystem::path callbackPath;
409 auto callback = [&called](const auto&, const auto&, const auto&) {
410 called = true;
411 };
412 auto errorCallback = [&ec, &callbackPath](const auto& p, auto& _ec) {
413 ec = _ec;
414 callbackPath = p;
415 };
416
417 std::vector<std::string> extensions;
418 auto dir = workdir / "baz";
419 functions::process_hostfirmware::findLinks(dir, extensions, errorCallback,
420 callback);
421 std::filesystem::remove_all(workdir);
422 EXPECT_EQ(ec.value(), ENOENT);
423 EXPECT_EQ(callbackPath, dir);
424 EXPECT_FALSE(called);
425 }
426
TEST(FindLinks,testEmptyCallback)427 TEST(FindLinks, testEmptyCallback)
428 {
429 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
430 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
431
432 bool called = false;
433 std::filesystem::path callbackPath;
434 auto errorCallback = [&called](const auto&, auto&) { called = true; };
435
436 auto filePath = workdir / "foo.foo";
437 std::ofstream file{filePath};
438
439 std::vector<std::string> extensions{".foo"s};
440 functions::process_hostfirmware::findLinks(
441 workdir, extensions, errorCallback,
442 functions::process_hostfirmware::LinkCallbackType());
443 std::filesystem::remove_all(workdir);
444 EXPECT_FALSE(called);
445 EXPECT_NO_THROW();
446 }
447
TEST(FindLinks,testEmptyErrorCallback)448 TEST(FindLinks, testEmptyErrorCallback)
449 {
450 std::array<char, 15> tmpl{"/tmp/tmpXXXXXX"};
451 std::filesystem::path workdir = mkdtemp(&tmpl[0]);
452
453 bool called = false;
454 auto callback = [&called](const auto&, const auto&, const auto&) {
455 called = true;
456 };
457
458 std::vector<std::string> extensions;
459 auto dir = workdir / "baz";
460 functions::process_hostfirmware::findLinks(
461 dir, extensions, functions::process_hostfirmware::ErrorCallbackType(),
462 callback);
463 std::filesystem::remove_all(workdir);
464 EXPECT_FALSE(called);
465 EXPECT_NO_THROW();
466 }
467