1 #include "libpldm/base.h" 2 3 #include "common/types.hpp" 4 #include "common/utils.hpp" 5 #include "mock_request.hpp" 6 #include "pldmd/dbus_impl_requester.hpp" 7 #include "requester/handler.hpp" 8 9 #include <gmock/gmock.h> 10 #include <gtest/gtest.h> 11 12 using namespace pldm::requester; 13 using namespace std::chrono; 14 15 using ::testing::AtLeast; 16 using ::testing::Between; 17 using ::testing::Exactly; 18 using ::testing::NiceMock; 19 using ::testing::Return; 20 21 class HandlerTest : public testing::Test 22 { 23 protected: 24 HandlerTest() : 25 event(sdeventplus::Event::get_default()), 26 dbusImplReq(pldm::utils::DBusHandler::getBus(), 27 "/xyz/openbmc_project/pldm") 28 {} 29 30 int fd = 0; 31 mctp_eid_t eid = 0; 32 sdeventplus::Event event; 33 pldm::dbus_api::Requester dbusImplReq; 34 35 /** @brief This function runs the sd_event_run in a loop till all the events 36 * in the testcase are dispatched and exits when there are no events 37 * for the timeout time. 38 * 39 * @param[in] timeout - maximum time to wait for an event 40 */ 41 void waitEventExpiry(milliseconds timeout) 42 { 43 while (1) 44 { 45 auto sleepTime = duration_cast<microseconds>(timeout); 46 // Returns 0 on timeout 47 if (!sd_event_run(event.get(), sleepTime.count())) 48 { 49 break; 50 } 51 } 52 } 53 54 public: 55 bool nullResponse = false; 56 bool validResponse = false; 57 int callbackCount = 0; 58 bool response2 = false; 59 60 void pldmResponseCallBack(mctp_eid_t /*eid*/, const pldm_msg* response, 61 size_t respMsgLen) 62 { 63 if (response == nullptr && respMsgLen == 0) 64 { 65 nullResponse = true; 66 } 67 else 68 { 69 validResponse = true; 70 } 71 callbackCount++; 72 } 73 }; 74 75 TEST_F(HandlerTest, singleRequestResponseScenario) 76 { 77 Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, 78 seconds(1), 2, milliseconds(100)); 79 pldm::Request request{}; 80 auto instanceId = dbusImplReq.getInstanceId(eid); 81 reqHandler.registerRequest( 82 eid, instanceId, 0, 0, std::move(request), 83 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 84 85 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); 86 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data()); 87 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr, 88 sizeof(response)); 89 90 // handleResponse() will free the instance ID after calling the response 91 // handler, so the same instance ID is granted next as well 92 ASSERT_EQ(validResponse, true); 93 ASSERT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 94 } 95 96 TEST_F(HandlerTest, singleRequestInstanceIdTimerExpired) 97 { 98 Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, 99 seconds(1), 2, milliseconds(100)); 100 pldm::Request request{}; 101 auto instanceId = dbusImplReq.getInstanceId(eid); 102 reqHandler.registerRequest( 103 eid, instanceId, 0, 0, std::move(request), 104 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 105 106 // Waiting for 500ms so that the instance ID expiry callback is invoked 107 waitEventExpiry(milliseconds(500)); 108 109 // cleanup() will free the instance ID after calling the response 110 // handler will no response, so the same instance ID is granted next 111 ASSERT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 112 ASSERT_EQ(nullResponse, true); 113 } 114 115 TEST_F(HandlerTest, multipleRequestResponseScenario) 116 { 117 Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, 118 seconds(2), 2, milliseconds(100)); 119 pldm::Request request{}; 120 auto instanceId = dbusImplReq.getInstanceId(eid); 121 reqHandler.registerRequest( 122 eid, instanceId, 0, 0, std::move(request), 123 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 124 125 pldm::Request requestNxt{}; 126 auto instanceIdNxt = dbusImplReq.getInstanceId(eid); 127 reqHandler.registerRequest( 128 eid, instanceIdNxt, 0, 0, std::move(requestNxt), 129 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 130 131 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); 132 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data()); 133 reqHandler.handleResponse(eid, instanceIdNxt, 0, 0, responsePtr, 134 sizeof(response)); 135 ASSERT_EQ(validResponse, true); 136 ASSERT_EQ(callbackCount, 1); 137 validResponse = false; 138 139 // Waiting for 500ms and handle the response for the first request, to 140 // simulate a delayed response for the first request 141 waitEventExpiry(milliseconds(500)); 142 143 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr, 144 sizeof(response)); 145 146 ASSERT_EQ(validResponse, true); 147 ASSERT_EQ(callbackCount, 2); 148 ASSERT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 149 }