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