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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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