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( 78 fd, event, dbusImplReq, false, 90000, seconds(1), 2, milliseconds(100)); 79 pldm::Request request{}; 80 auto instanceId = dbusImplReq.getInstanceId(eid); 81 auto rc = reqHandler.registerRequest( 82 eid, instanceId, 0, 0, std::move(request), 83 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 84 EXPECT_EQ(rc, PLDM_SUCCESS); 85 86 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); 87 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data()); 88 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr, 89 sizeof(response)); 90 91 // handleResponse() will free the instance ID after calling the response 92 // handler, so the same instance ID is granted next as well 93 EXPECT_EQ(validResponse, true); 94 EXPECT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 95 } 96 97 TEST_F(HandlerTest, singleRequestInstanceIdTimerExpired) 98 { 99 Handler<NiceMock<MockRequest>> reqHandler( 100 fd, event, dbusImplReq, false, 90000, seconds(1), 2, milliseconds(100)); 101 pldm::Request request{}; 102 auto instanceId = dbusImplReq.getInstanceId(eid); 103 auto rc = reqHandler.registerRequest( 104 eid, instanceId, 0, 0, std::move(request), 105 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 106 EXPECT_EQ(rc, PLDM_SUCCESS); 107 108 // Waiting for 500ms so that the instance ID expiry callback is invoked 109 waitEventExpiry(milliseconds(500)); 110 111 // cleanup() will free the instance ID after calling the response 112 // handler will no response, so the same instance ID is granted next 113 EXPECT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 114 EXPECT_EQ(nullResponse, true); 115 } 116 117 TEST_F(HandlerTest, multipleRequestResponseScenario) 118 { 119 Handler<NiceMock<MockRequest>> reqHandler( 120 fd, event, dbusImplReq, false, 90000, seconds(2), 2, milliseconds(100)); 121 pldm::Request request{}; 122 auto instanceId = dbusImplReq.getInstanceId(eid); 123 auto rc = reqHandler.registerRequest( 124 eid, instanceId, 0, 0, std::move(request), 125 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 126 EXPECT_EQ(rc, PLDM_SUCCESS); 127 128 pldm::Request requestNxt{}; 129 auto instanceIdNxt = dbusImplReq.getInstanceId(eid); 130 rc = reqHandler.registerRequest( 131 eid, instanceIdNxt, 0, 0, std::move(requestNxt), 132 std::move(std::bind_front(&HandlerTest::pldmResponseCallBack, this))); 133 EXPECT_EQ(rc, PLDM_SUCCESS); 134 135 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); 136 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data()); 137 reqHandler.handleResponse(eid, instanceIdNxt, 0, 0, responsePtr, 138 sizeof(response)); 139 EXPECT_EQ(validResponse, true); 140 EXPECT_EQ(callbackCount, 1); 141 validResponse = false; 142 143 // Waiting for 500ms and handle the response for the first request, to 144 // simulate a delayed response for the first request 145 waitEventExpiry(milliseconds(500)); 146 147 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr, 148 sizeof(response)); 149 150 EXPECT_EQ(validResponse, true); 151 EXPECT_EQ(callbackCount, 2); 152 EXPECT_EQ(instanceId, dbusImplReq.getInstanceId(eid)); 153 } 154