1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "errors.hpp" 16 #include "handler.hpp" 17 #include "handler_impl.hpp" 18 19 #include <systemd/sd-bus.h> 20 21 #include <charconv> 22 #include <filesystem> 23 #include <fstream> 24 #include <functional> 25 #include <nlohmann/json.hpp> 26 #include <sdbusplus/message.hpp> 27 #include <sdbusplus/test/sdbus_mock.hpp> 28 #include <string> 29 #include <tuple> 30 31 #include <gtest/gtest.h> 32 33 namespace google 34 { 35 namespace ipmi 36 { 37 38 using testing::_; 39 using testing::Return; 40 41 TEST(HandlerTest, EthCheckValidHappy) 42 { 43 Handler h; 44 std::tuple<std::uint8_t, std::string> result = h.getEthDetails("et"); 45 EXPECT_EQ(12, std::get<0>(result)); 46 EXPECT_STREQ("et", std::get<1>(result).c_str()); 47 } 48 49 TEST(HandlerTest, CableCheckIllegalPath) 50 { 51 Handler h; 52 EXPECT_THROW(h.getRxPackets("eth0/../../"), IpmiException); 53 } 54 55 TEST(HandlerTest, readNameFromConfigInstanceVariety) 56 { 57 // Make sure it handles the failures and successes as we expect. 58 struct testCase 59 { 60 std::string type; 61 std::uint8_t instance; 62 std::string expectedName; 63 }; 64 65 std::vector<testCase> tests = { 66 {"cpu", 5, ""}, 67 {"cpu", 3, "CPU2"}, 68 }; 69 70 auto j2 = R"( 71 { 72 "cpu": [ 73 {"instance": 1, "name": "CPU0"}, 74 {"instance": 2, "name": "CPU1"}, 75 {"instance": 3, "name": "CPU2"}, 76 {"instance": 4, "name": "CPU3"} 77 ] 78 } 79 )"_json; 80 81 for (const auto& test : tests) 82 { 83 EXPECT_STREQ(test.expectedName.c_str(), 84 readNameFromConfig(test.type, test.instance, j2).c_str()); 85 } 86 } 87 88 // TODO: If we can test with phosphor-logging in the future, there are more 89 // failure cases. 90 91 TEST(HandlerTest, getEntityNameWithNameNotFoundExcepts) 92 { 93 const char* testFilename = "test.json"; 94 std::string contents = R"({"cpu": [{"instance": 1, "name": "CPU0"}]})"; 95 std::ofstream outputJson(testFilename); 96 outputJson << contents; 97 outputJson.flush(); 98 outputJson.close(); 99 100 Handler h(testFilename); 101 EXPECT_THROW(h.getEntityName(0x03, 2), IpmiException); 102 (void)std::remove(testFilename); 103 } 104 105 TEST(HandlerTest, getEntityNameWithNameFoundReturnsIt) 106 { 107 const char* testFilename = "test.json"; 108 std::string contents = R"({"cpu": [{"instance": 1, "name": "CPU0"}]})"; 109 std::ofstream outputJson(testFilename); 110 outputJson << contents; 111 outputJson.flush(); 112 outputJson.close(); 113 114 Handler h(testFilename); 115 EXPECT_STREQ("CPU0", h.getEntityName(0x03, 1).c_str()); 116 (void)std::remove(testFilename); 117 } 118 119 using ::testing::_; 120 using ::testing::AnyNumber; 121 using ::testing::ContainerEq; 122 using ::testing::DoAll; 123 using ::testing::ElementsAre; 124 using ::testing::Eq; 125 using ::testing::IsNull; 126 using ::testing::MatcherCast; 127 using ::testing::NotNull; 128 using ::testing::Pointee; 129 using ::testing::Return; 130 using ::testing::ReturnNull; 131 using ::testing::SafeMatcherCast; 132 using ::testing::SetArgPointee; 133 using ::testing::StrEq; 134 using ::testing::StrictMock; 135 using ::testing::StrNe; 136 using ::testing::WithArg; 137 138 class MockDbusHandler : public Handler 139 { 140 public: 141 MockDbusHandler(sdbusplus::SdBusMock& mock, 142 const std::string& config = "") : 143 Handler(config), 144 mock_(&mock) 145 { 146 } 147 148 protected: 149 sdbusplus::bus::bus getDbus() const override 150 { 151 return sdbusplus::get_mocked_new( 152 const_cast<sdbusplus::SdBusMock*>(mock_)); 153 } 154 155 private: 156 sdbusplus::SdBusMock* mock_; 157 }; 158 159 ACTION_TEMPLATE(AssignReadVal, HAS_1_TEMPLATE_PARAMS(typename, T), 160 AND_1_VALUE_PARAMS(val)) 161 { 162 *static_cast<T*>(arg2) = val; 163 } 164 165 ACTION_P(TraceDbus, msg) 166 { 167 std::fprintf(stderr, "%s\n", msg); 168 } 169 170 ACTION_P(TraceDbus2, msg) 171 { 172 std::fprintf(stderr, "%s(%02x)\n", msg, *static_cast<const uint8_t*>(arg2)); 173 } 174 175 constexpr char object_path[] = "/com/google/customAccel/test/path"; 176 constexpr char property_grpc[] = "com.google.custom_accel.gRPC"; 177 constexpr char value_port[] = "Port"; 178 constexpr uint32_t port = 5000; 179 180 constexpr char SD_BUS_TYPE_BYTE_STR[] = {SD_BUS_TYPE_BYTE, '\0'}; 181 182 // Returns an object that looks like: 183 // "/com/google/customAccel/test/path": { 184 // "com.google.custom_accel.gRPC" : { 185 // "Port" : { 186 // "type" : "u", 187 // "data" : 5000 188 // } 189 // } 190 // } 191 void ExpectGetManagedObjects(StrictMock<sdbusplus::SdBusMock>& mock, 192 const char* obj_path = object_path) 193 { 194 ::testing::InSequence s; 195 196 // These must be nullptr or sd_bus_message_unref will seg fault. 197 constexpr sd_bus_message* method = nullptr; 198 constexpr sd_bus_message* msg = nullptr; 199 200 EXPECT_CALL(mock, sd_bus_message_new_method_call( 201 _, // sd_bus *bus, 202 NotNull(), // sd_bus_message **m 203 StrEq("com.google.custom_accel"), StrEq("/"), 204 StrEq("org.freedesktop.DBus.ObjectManager"), 205 StrEq("GetManagedObjects"))) 206 .WillOnce(DoAll(SetArgPointee<1>(method), Return(0))); 207 208 EXPECT_CALL(mock, sd_bus_call(_, // sd_bus *bus, 209 method, // sd_bus_message *m 210 _, // uint64_t timeout 211 NotNull(), // sd_bus_error *ret_error 212 NotNull())) // sd_bus_message **reply 213 .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL), 214 SetArgPointee<4>(msg), // reply 215 Return(0))); 216 217 EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, 218 StrEq("{oa{sa{sv}}}"))) 219 .WillOnce(Return(1)); 220 221 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); 222 223 EXPECT_CALL(mock, sd_bus_message_enter_container( 224 msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("oa{sa{sv}}"))) 225 .WillOnce(Return(1)); 226 227 EXPECT_CALL(mock, sd_bus_message_read_basic(msg, SD_BUS_TYPE_OBJECT_PATH, 228 NotNull())) 229 .WillOnce(DoAll(AssignReadVal<const char*>(obj_path), Return(1))); 230 231 EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, 232 StrEq("{sa{sv}}"))) 233 .WillOnce(Return(1)); 234 235 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); 236 237 EXPECT_CALL(mock, sd_bus_message_enter_container( 238 msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sa{sv}"))) 239 .WillOnce(Return(1)); 240 241 EXPECT_CALL(mock, 242 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull())) 243 .WillOnce(DoAll(AssignReadVal<const char*>(property_grpc), Return(1))); 244 245 EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, 246 StrEq("{sv}"))) 247 .WillOnce(Return(1)); 248 249 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); 250 251 EXPECT_CALL(mock, sd_bus_message_enter_container( 252 msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sv"))) 253 .WillOnce(Return(1)); 254 255 EXPECT_CALL(mock, 256 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull())) 257 .WillOnce(DoAll(AssignReadVal<const char*>(value_port), Return(1))); 258 259 EXPECT_CALL( 260 mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u"))) 261 .Times(AnyNumber()) 262 .WillRepeatedly(Return(0)); 263 264 EXPECT_CALL( 265 mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrEq("u"))) 266 .WillOnce(Return(1)); 267 268 EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_VARIANT, 269 StrEq("u"))) 270 .WillOnce(Return(1)); 271 272 EXPECT_CALL(mock, 273 sd_bus_message_read_basic(msg, SD_BUS_TYPE_UINT32, NotNull())) 274 .WillOnce(DoAll(AssignReadVal<uint32_t>(port), Return(0))); 275 276 EXPECT_CALL( 277 mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u"))) 278 .Times(AnyNumber()) 279 .WillRepeatedly(Return(0)); 280 281 EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) 282 .WillOnce(Return(1)) 283 .WillOnce(Return(1)); 284 285 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); 286 287 EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) 288 .WillOnce(Return(1)) 289 .WillOnce(Return(1)); 290 291 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); 292 293 EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) 294 .WillOnce(Return(1)) 295 .WillOnce(Return(1)); 296 297 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); 298 299 EXPECT_CALL(mock, sd_bus_message_exit_container(msg)).WillOnce(Return(1)); 300 } 301 302 void ExpectSdBusError(StrictMock<sdbusplus::SdBusMock>& mock, 303 const std::string& service, const std::string& objPath, 304 const std::string& interface, const std::string& function) 305 { 306 EXPECT_CALL( 307 mock, sd_bus_message_new_method_call(_, // sd_bus *bus, 308 NotNull(), // sd_bus_message **m 309 StrEq(service), StrEq(objPath), 310 StrEq(interface), StrEq(function))) 311 .WillOnce(Return(-ENOTCONN)); 312 } 313 314 TEST(HandlerTest, accelOobDeviceCount_Success) 315 { 316 StrictMock<sdbusplus::SdBusMock> mock; 317 MockDbusHandler h(mock); 318 ExpectGetManagedObjects(mock); 319 EXPECT_EQ(1, h.accelOobDeviceCount()); 320 } 321 322 TEST(HandlerTest, accelOobDeviceCount_Fail) 323 { 324 StrictMock<sdbusplus::SdBusMock> mock; 325 MockDbusHandler h(mock); 326 ExpectSdBusError(mock, "com.google.custom_accel", "/", 327 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 328 EXPECT_THROW(h.accelOobDeviceCount(), IpmiException); 329 } 330 331 TEST(HandlerTest, accelOobDeviceName_Success) 332 { 333 StrictMock<sdbusplus::SdBusMock> mock; 334 MockDbusHandler h(mock); 335 ExpectGetManagedObjects(mock); 336 EXPECT_EQ(std::string("test/path"), h.accelOobDeviceName(0)); 337 } 338 339 TEST(HandlerTest, accelOobDeviceName_Fail) 340 { 341 StrictMock<sdbusplus::SdBusMock> mock; 342 MockDbusHandler h(mock); 343 ExpectSdBusError(mock, "com.google.custom_accel", "/", 344 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 345 EXPECT_THROW(h.accelOobDeviceName(0), IpmiException); 346 } 347 348 TEST(HandlerTest, accelOobDeviceName_OutOfRange) 349 { 350 StrictMock<sdbusplus::SdBusMock> mock; 351 MockDbusHandler h(mock); 352 ExpectGetManagedObjects(mock); 353 EXPECT_THROW(h.accelOobDeviceName(1), IpmiException); 354 } 355 356 TEST(HandlerTest, accelOobDeviceName_InvalidName) 357 { 358 constexpr char bad_object_path[] = "/com/google/customAccel2/bad/path"; 359 StrictMock<sdbusplus::SdBusMock> mock; 360 MockDbusHandler h(mock); 361 ExpectGetManagedObjects(mock, bad_object_path); 362 EXPECT_THROW(h.accelOobDeviceName(0), IpmiException); 363 } 364 365 constexpr uint8_t NUM_BYTES_RETURNED_EQ_NUM_BYTES = 0xff; 366 void ExpectRead(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address, 367 uint8_t num_bytes, uint64_t data, int sd_bus_call_return_value, 368 uint8_t num_bytes_returned = NUM_BYTES_RETURNED_EQ_NUM_BYTES) 369 { 370 ::testing::InSequence s; 371 372 // These must be nullptr or sd_bus_message_unref will seg fault. 373 constexpr sd_bus_message* method = nullptr; 374 constexpr sd_bus_message* msg = nullptr; 375 376 EXPECT_CALL(mock, sd_bus_message_new_method_call( 377 _, // sd_bus *bus, 378 NotNull(), // sd_bus_message **m 379 StrEq("com.google.custom_accel"), 380 StrEq("/com/google/customAccel/test/path"), 381 StrEq("com.google.custom_accel.BAR"), StrEq("Read"))) 382 .WillOnce(DoAll(SetArgPointee<1>(method), Return(0))); 383 384 EXPECT_CALL( 385 mock, sd_bus_message_append_basic( 386 method, SD_BUS_TYPE_UINT64, 387 MatcherCast<const void*>( 388 SafeMatcherCast<const uint64_t*>(Pointee(Eq(address)))))) 389 .WillOnce(Return(1)); 390 391 EXPECT_CALL(mock, 392 sd_bus_message_append_basic( 393 method, SD_BUS_TYPE_UINT64, 394 MatcherCast<const void*>(SafeMatcherCast<const uint64_t*>( 395 Pointee(Eq<uint64_t>(num_bytes)))))) 396 .WillOnce(Return(1)); 397 398 EXPECT_CALL(mock, sd_bus_call(_, // sd_bus *bus, 399 method, // sd_bus_message *m 400 _, // uint64_t timeout 401 NotNull(), // sd_bus_error *ret_error 402 NotNull())) // sd_bus_message **reply 403 .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL), 404 SetArgPointee<4>(msg), // reply 405 Return(sd_bus_call_return_value))); 406 407 if (sd_bus_call_return_value >= 0) 408 { 409 EXPECT_CALL(mock, 410 sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, 411 StrEq(SD_BUS_TYPE_BYTE_STR))) 412 .WillOnce(Return(1)); 413 414 if (num_bytes_returned == NUM_BYTES_RETURNED_EQ_NUM_BYTES) 415 { 416 num_bytes_returned = num_bytes; 417 } 418 for (auto i = num_bytes_returned - 1; i >= 0; --i) 419 { 420 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)) 421 .WillOnce(Return(0)); 422 423 const uint8_t byte = (data >> (8 * i)) & 0xff; 424 EXPECT_CALL(mock, sd_bus_message_read_basic(msg, SD_BUS_TYPE_BYTE, 425 NotNull())) 426 .WillOnce(DoAll(AssignReadVal<uint8_t>(byte), Return(1))); 427 } 428 429 EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); 430 431 EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) 432 .WillOnce(Return(1)); 433 } 434 } 435 436 TEST(HandlerTest, accelOobRead_Success) 437 { 438 StrictMock<sdbusplus::SdBusMock> mock; 439 MockDbusHandler h(mock); 440 441 constexpr uint64_t address = 0x123456789abcdef; 442 constexpr uint8_t num_bytes = sizeof(uint64_t); 443 constexpr int sd_bus_call_return_value = 1; 444 constexpr uint64_t data = 0x13579bdf02468ace; 445 446 ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value); 447 EXPECT_EQ(data, h.accelOobRead("test/path", address, num_bytes)); 448 } 449 450 TEST(HandlerTest, accelOobRead_Fail) 451 { 452 StrictMock<sdbusplus::SdBusMock> mock; 453 MockDbusHandler h(mock); 454 455 constexpr uint64_t address = 0x123456789abcdef; 456 constexpr uint8_t num_bytes = sizeof(uint64_t); 457 constexpr int sd_bus_call_return_value = -ENOTCONN; 458 constexpr uint64_t data = 0x13579bdf02468ace; 459 460 ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value); 461 EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), 462 IpmiException); 463 } 464 465 TEST(HandlerTest, accelOobRead_TooFewBytesReturned) 466 { 467 StrictMock<sdbusplus::SdBusMock> mock; 468 MockDbusHandler h(mock); 469 470 constexpr uint64_t address = 0x123456789abcdef; 471 constexpr uint8_t num_bytes = sizeof(uint64_t); 472 constexpr int sd_bus_call_return_value = 1; 473 constexpr uint64_t data = 0x13579bdf02468ace; 474 constexpr uint8_t num_bytes_returned = num_bytes - 1; 475 476 ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value, 477 num_bytes_returned); 478 EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), 479 IpmiException); 480 } 481 482 TEST(HandlerTest, accelOobRead_TooManyBytesReturned) 483 { 484 StrictMock<sdbusplus::SdBusMock> mock; 485 MockDbusHandler h(mock); 486 487 constexpr uint64_t address = 0x123456789abcdef; 488 constexpr uint8_t num_bytes = sizeof(uint64_t); 489 constexpr int sd_bus_call_return_value = 1; 490 constexpr uint64_t data = 0x13579bdf02468ace; 491 constexpr uint8_t num_bytes_returned = sizeof(uint64_t) + 1; 492 493 ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value, 494 num_bytes_returned); 495 EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), 496 IpmiException); 497 } 498 499 void ExpectWrite(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address, 500 uint8_t num_bytes, uint64_t data, int sd_bus_call_return_value) 501 { 502 ::testing::InSequence s; 503 504 // These must be nullptr or sd_bus_message_unref will seg fault. 505 constexpr sd_bus_message* method = nullptr; 506 507 EXPECT_CALL(mock, sd_bus_message_new_method_call( 508 _, // sd_bus *bus, 509 NotNull(), // sd_bus_message **m 510 StrEq("com.google.custom_accel"), 511 StrEq("/com/google/customAccel/test/path"), 512 StrEq("com.google.custom_accel.BAR"), StrEq("Write"))) 513 .WillOnce(DoAll(TraceDbus("sd_bus_message_new_method_call"), 514 SetArgPointee<1>(method), Return(0))); 515 516 EXPECT_CALL( 517 mock, sd_bus_message_append_basic( 518 method, SD_BUS_TYPE_UINT64, 519 MatcherCast<const void*>( 520 SafeMatcherCast<const uint64_t*>(Pointee(Eq(address)))))) 521 .WillOnce(DoAll(TraceDbus("sd_bus_message_append_basic(address) -> 1"), 522 Return(1))); 523 524 EXPECT_CALL(mock, 525 sd_bus_message_open_container(method, SD_BUS_TYPE_ARRAY, 526 StrEq(SD_BUS_TYPE_BYTE_STR))) 527 .WillOnce(DoAll(TraceDbus("sd_bus_message_open_container(a, y) -> 0"), 528 Return(0))); 529 530 for (auto i = 0; i < num_bytes; ++i) 531 { 532 const uint8_t byte = (data >> (8 * i)) & 0xff; 533 534 EXPECT_CALL( 535 mock, sd_bus_message_append_basic( 536 method, SD_BUS_TYPE_BYTE, 537 MatcherCast<const void*>( 538 SafeMatcherCast<const uint8_t*>(Pointee(Eq(byte)))))) 539 .WillOnce( 540 DoAll(TraceDbus2("sd_bus_message_append_basic"), Return(1))); 541 } 542 543 EXPECT_CALL(mock, sd_bus_message_close_container(method)) 544 .WillOnce(DoAll(TraceDbus("sd_bus_message_close_container() -> 0"), 545 Return(0))); 546 547 EXPECT_CALL(mock, sd_bus_call(_, // sd_bus *bus, 548 method, // sd_bus_message *m 549 _, // uint64_t timeout 550 NotNull(), // sd_bus_error *ret_error 551 IsNull())) // sd_bus_message **reply 552 .WillOnce(DoAll(TraceDbus("sd_bus_call() -> ret_val"), 553 SetArgPointee<3>(SD_BUS_ERROR_NULL), 554 Return(sd_bus_call_return_value))); 555 } 556 557 TEST(HandlerTest, accelOobWrite_Success) 558 { 559 StrictMock<sdbusplus::SdBusMock> mock; 560 MockDbusHandler h(mock); 561 562 constexpr uint64_t address = 0x123456789abcdef; 563 constexpr uint8_t num_bytes = sizeof(uint64_t); 564 constexpr int sd_bus_call_return_value = 1; 565 constexpr uint64_t data = 0x13579bdf02468ace; 566 567 ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value); 568 EXPECT_NO_THROW(h.accelOobWrite("test/path", address, num_bytes, data)); 569 } 570 571 TEST(HandlerTest, accelOobRead_TooManyBytesRequested) 572 { 573 StrictMock<sdbusplus::SdBusMock> mock; 574 MockDbusHandler h(mock); 575 576 constexpr uint64_t address = 0x123456789abcdef; 577 constexpr uint8_t num_bytes = sizeof(uint64_t) + 1; 578 constexpr uint64_t data = 0x13579bdf02468ace; 579 580 EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data), 581 IpmiException); 582 } 583 584 TEST(HandlerTest, accelOobWrite_Fail) 585 { 586 StrictMock<sdbusplus::SdBusMock> mock; 587 MockDbusHandler h(mock); 588 589 constexpr uint64_t address = 0x123456789abcdef; 590 constexpr uint8_t num_bytes = sizeof(uint64_t); 591 constexpr int sd_bus_call_return_value = -ENOTCONN; 592 constexpr uint64_t data = 0x13579bdf02468ace; 593 594 ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value); 595 EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data), 596 IpmiException); 597 } 598 599 TEST(HandlerTest, PcieBifurcation) 600 { 601 const std::string& testJson = "/tmp/test-json"; 602 auto j = R"( 603 { 604 "1": [ 1, 3 ], 605 "3": [ 3, 6 ], 606 "4": [ 3, 4, 1 ], 607 "6": [ 8 ] 608 } 609 )"_json; 610 611 std::ofstream bifurcationJson(testJson); 612 bifurcationJson << j.dump(); 613 bifurcationJson.flush(); 614 bifurcationJson.close(); 615 616 BifurcationStatic bifurcationHelper(testJson); 617 Handler h(std::ref(bifurcationHelper)); 618 619 std::unordered_map<uint8_t, std::vector<uint8_t>> expectedMapping = { 620 {1, {1, 3}}, {3, {3, 6}}, {4, {3, 4, 1}}, {6, {8}}}; 621 std::vector<uint8_t> invalidBus = {0, 2, 5, 7}; 622 623 for (const auto& [bus, output] : expectedMapping) 624 { 625 EXPECT_THAT(h.pcieBifurcation(bus), ContainerEq(output)); 626 } 627 628 for (const auto& bus : invalidBus) 629 { 630 EXPECT_TRUE(h.pcieBifurcation(bus).empty()); 631 } 632 633 std::filesystem::remove(testJson.data()); 634 bifurcationHelper = BifurcationStatic(testJson); 635 Handler h2(std::ref(bifurcationHelper)); 636 for (uint8_t i = 0; i < 8; ++i) 637 { 638 auto bifurcation = h2.pcieBifurcation(i); 639 EXPECT_TRUE(bifurcation.empty()); 640 } 641 } 642 643 // TODO: Add checks for other functions of handler. 644 645 } // namespace ipmi 646 } // namespace google 647