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