xref: /openbmc/pldm/requester/test/handler_test.cpp (revision b3dbb6e8eb5a05a77c572bedce89b8ce331726b2)
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 }