blob: ebccdf789522a39e29633c1aadef9545a6142ce0 [file] [log] [blame]
Andrew Jeffery2abbce72023-10-18 10:17:35 +10301#include "common/instance_id.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07002#include "common/types.hpp"
3#include "common/utils.hpp"
4#include "mock_request.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07005#include "requester/handler.hpp"
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +09306#include "test/test_instance_id.hpp"
Tom Joseph74f27c72021-05-16 07:58:53 -07007
George Liuc453e162022-12-21 17:16:23 +08008#include <libpldm/base.h>
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +10009#include <libpldm/transport.h>
George Liuc453e162022-12-21 17:16:23 +080010
Gilbert Chena85c69d2024-01-09 21:25:26 +070011#include <sdbusplus/async.hpp>
12
Tom Joseph74f27c72021-05-16 07:58:53 -070013#include <gmock/gmock.h>
14#include <gtest/gtest.h>
15
16using namespace pldm::requester;
17using namespace std::chrono;
18
19using ::testing::AtLeast;
20using ::testing::Between;
21using ::testing::Exactly;
22using ::testing::NiceMock;
23using ::testing::Return;
24
25class HandlerTest : public testing::Test
26{
27 protected:
Andrew Jefferya330b2f2023-05-04 14:55:37 +093028 HandlerTest() : event(sdeventplus::Event::get_default()), instanceIdDb() {}
Tom Joseph74f27c72021-05-16 07:58:53 -070029
30 int fd = 0;
31 mctp_eid_t eid = 0;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +100032 PldmTransport* pldmTransport = nullptr;
Tom Joseph74f27c72021-05-16 07:58:53 -070033 sdeventplus::Event event;
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +093034 TestInstanceIdDb instanceIdDb;
Tom Joseph74f27c72021-05-16 07:58:53 -070035
36 /** @brief This function runs the sd_event_run in a loop till all the events
37 * in the testcase are dispatched and exits when there are no events
38 * for the timeout time.
39 *
40 * @param[in] timeout - maximum time to wait for an event
41 */
42 void waitEventExpiry(milliseconds timeout)
43 {
44 while (1)
45 {
46 auto sleepTime = duration_cast<microseconds>(timeout);
47 // Returns 0 on timeout
48 if (!sd_event_run(event.get(), sleepTime.count()))
49 {
50 break;
51 }
52 }
53 }
54
55 public:
56 bool nullResponse = false;
57 bool validResponse = false;
58 int callbackCount = 0;
59 bool response2 = false;
60
61 void pldmResponseCallBack(mctp_eid_t /*eid*/, const pldm_msg* response,
62 size_t respMsgLen)
63 {
64 if (response == nullptr && respMsgLen == 0)
65 {
66 nullResponse = true;
67 }
68 else
69 {
70 validResponse = true;
71 }
72 callbackCount++;
73 }
74};
75
76TEST_F(HandlerTest, singleRequestResponseScenario)
77{
Patrick Williams16c2a0a2024-08-16 15:20:59 -040078 Handler<NiceMock<MockRequest>> reqHandler(
79 pldmTransport, event, instanceIdDb, false, seconds(1), 2,
80 milliseconds(100));
Tom Joseph74f27c72021-05-16 07:58:53 -070081 pldm::Request request{};
Eric Yang70262ed2025-07-02 06:35:03 +000082 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
83 ASSERT_TRUE(instanceIdResult);
84 auto instanceId = instanceIdResult.value();
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +093085 EXPECT_EQ(instanceId, 0);
Tom Josepha5ed6582021-06-17 22:08:47 -070086 auto rc = reqHandler.registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -070087 eid, instanceId, 0, 0, std::move(request),
Eric Yang70eca962025-05-11 01:48:15 +080088 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
89 this->pldmResponseCallBack(eid, response, respMsgLen);
90 });
Tom Josepha5ed6582021-06-17 22:08:47 -070091 EXPECT_EQ(rc, PLDM_SUCCESS);
Tom Joseph74f27c72021-05-16 07:58:53 -070092
93 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
94 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data());
95 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr,
Pavithra Barithaya93f1e002023-07-11 10:14:13 -050096 response.size());
Tom Joseph74f27c72021-05-16 07:58:53 -070097
Tom Josepha5ed6582021-06-17 22:08:47 -070098 EXPECT_EQ(validResponse, true);
Tom Joseph74f27c72021-05-16 07:58:53 -070099}
100
101TEST_F(HandlerTest, singleRequestInstanceIdTimerExpired)
102{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400103 Handler<NiceMock<MockRequest>> reqHandler(
104 pldmTransport, event, instanceIdDb, false, seconds(1), 2,
105 milliseconds(100));
Tom Joseph74f27c72021-05-16 07:58:53 -0700106 pldm::Request request{};
Eric Yang70262ed2025-07-02 06:35:03 +0000107 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
108 ASSERT_TRUE(instanceIdResult);
109 auto instanceId = instanceIdResult.value();
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930110 EXPECT_EQ(instanceId, 0);
Tom Josepha5ed6582021-06-17 22:08:47 -0700111 auto rc = reqHandler.registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -0700112 eid, instanceId, 0, 0, std::move(request),
Eric Yang70eca962025-05-11 01:48:15 +0800113 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
114 this->pldmResponseCallBack(eid, response, respMsgLen);
115 });
Tom Josepha5ed6582021-06-17 22:08:47 -0700116 EXPECT_EQ(rc, PLDM_SUCCESS);
Tom Joseph74f27c72021-05-16 07:58:53 -0700117
118 // Waiting for 500ms so that the instance ID expiry callback is invoked
119 waitEventExpiry(milliseconds(500));
120
Tom Josepha5ed6582021-06-17 22:08:47 -0700121 EXPECT_EQ(nullResponse, true);
Tom Joseph74f27c72021-05-16 07:58:53 -0700122}
123
124TEST_F(HandlerTest, multipleRequestResponseScenario)
125{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400126 Handler<NiceMock<MockRequest>> reqHandler(
127 pldmTransport, event, instanceIdDb, false, seconds(2), 2,
128 milliseconds(100));
Tom Joseph74f27c72021-05-16 07:58:53 -0700129 pldm::Request request{};
Eric Yang70262ed2025-07-02 06:35:03 +0000130 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
131 ASSERT_TRUE(instanceIdResult);
132 auto instanceId = instanceIdResult.value();
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930133 EXPECT_EQ(instanceId, 0);
Tom Josepha5ed6582021-06-17 22:08:47 -0700134 auto rc = reqHandler.registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -0700135 eid, instanceId, 0, 0, std::move(request),
Eric Yang70eca962025-05-11 01:48:15 +0800136 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
137 this->pldmResponseCallBack(eid, response, respMsgLen);
138 });
Tom Josepha5ed6582021-06-17 22:08:47 -0700139 EXPECT_EQ(rc, PLDM_SUCCESS);
Tom Joseph74f27c72021-05-16 07:58:53 -0700140
141 pldm::Request requestNxt{};
Eric Yang70262ed2025-07-02 06:35:03 +0000142 auto instanceIdNxtResult =
143 pldm::utils::getInstanceId(instanceIdDb.next(eid));
144 ASSERT_TRUE(instanceIdNxtResult);
145 auto instanceIdNxt = instanceIdNxtResult.value();
Andrew Jeffery7c1dc7e2023-04-28 14:52:16 +0930146 EXPECT_EQ(instanceIdNxt, 1);
Tom Josepha5ed6582021-06-17 22:08:47 -0700147 rc = reqHandler.registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -0700148 eid, instanceIdNxt, 0, 0, std::move(requestNxt),
Eric Yang70eca962025-05-11 01:48:15 +0800149 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
150 this->pldmResponseCallBack(eid, response, respMsgLen);
151 });
Tom Josepha5ed6582021-06-17 22:08:47 -0700152 EXPECT_EQ(rc, PLDM_SUCCESS);
Tom Joseph74f27c72021-05-16 07:58:53 -0700153
154 pldm::Response response(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
155 auto responsePtr = reinterpret_cast<const pldm_msg*>(response.data());
Thu Nguyen4ddee3a2023-08-03 08:20:03 +0700156 reqHandler.handleResponse(eid, instanceId, 0, 0, responsePtr,
Pavithra Barithaya93f1e002023-07-11 10:14:13 -0500157 response.size());
Tom Josepha5ed6582021-06-17 22:08:47 -0700158 EXPECT_EQ(validResponse, true);
159 EXPECT_EQ(callbackCount, 1);
Tom Joseph74f27c72021-05-16 07:58:53 -0700160 validResponse = false;
161
162 // Waiting for 500ms and handle the response for the first request, to
163 // simulate a delayed response for the first request
164 waitEventExpiry(milliseconds(500));
165
Thu Nguyen4ddee3a2023-08-03 08:20:03 +0700166 reqHandler.handleResponse(eid, instanceIdNxt, 0, 0, responsePtr,
Pavithra Barithaya93f1e002023-07-11 10:14:13 -0500167 response.size());
Tom Joseph74f27c72021-05-16 07:58:53 -0700168
Tom Josepha5ed6582021-06-17 22:08:47 -0700169 EXPECT_EQ(validResponse, true);
170 EXPECT_EQ(callbackCount, 2);
Manojkiran Eda9fffea22021-10-27 16:03:27 +0530171}
Gilbert Chena85c69d2024-01-09 21:25:26 +0700172
173TEST_F(HandlerTest, singleRequestResponseScenarioUsingCoroutine)
174{
175 exec::async_scope scope;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400176 Handler<NiceMock<MockRequest>> reqHandler(
177 pldmTransport, event, instanceIdDb, false, seconds(1), 2,
178 milliseconds(100));
Gilbert Chena85c69d2024-01-09 21:25:26 +0700179
Eric Yang70262ed2025-07-02 06:35:03 +0000180 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
181 ASSERT_TRUE(instanceIdResult);
182 auto instanceId = instanceIdResult.value();
Gilbert Chena85c69d2024-01-09 21:25:26 +0700183 EXPECT_EQ(instanceId, 0);
184
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400185 scope.spawn(
186 stdexec::just() | stdexec::let_value([&] -> exec::task<void> {
187 pldm::Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t), 0);
188 const pldm_msg* responseMsg;
189 size_t responseLen;
190 int rc = PLDM_SUCCESS;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700191
Pavithra Barithaya5ea72372025-02-04 18:09:57 +0530192 auto requestPtr = new (request.data()) pldm_msg;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400193 requestPtr->hdr.instance_id = instanceId;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700194
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400195 try
196 {
197 std::tie(rc, responseMsg, responseLen) =
198 co_await reqHandler.sendRecvMsg(eid, std::move(request));
199 }
200 catch (...)
201 {
202 std::rethrow_exception(std::current_exception());
203 }
Gilbert Chena85c69d2024-01-09 21:25:26 +0700204
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400205 EXPECT_NE(responseLen, 0);
Gilbert Chena85c69d2024-01-09 21:25:26 +0700206
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400207 this->pldmResponseCallBack(eid, responseMsg, responseLen);
Gilbert Chena85c69d2024-01-09 21:25:26 +0700208
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400209 EXPECT_EQ(validResponse, true);
210 }),
211 exec::default_task_context<void>(exec::inline_scheduler{}));
Gilbert Chena85c69d2024-01-09 21:25:26 +0700212
213 pldm::Response mockResponse(sizeof(pldm_msg_hdr) + sizeof(uint8_t), 0);
214 auto mockResponsePtr =
215 reinterpret_cast<const pldm_msg*>(mockResponse.data());
216 reqHandler.handleResponse(eid, instanceId, 0, 0, mockResponsePtr,
217 mockResponse.size() - sizeof(pldm_msg_hdr));
218
219 stdexec::sync_wait(scope.on_empty());
220}
221
222TEST_F(HandlerTest, singleRequestCancellationScenarioUsingCoroutine)
223{
224 exec::async_scope scope;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400225 Handler<NiceMock<MockRequest>> reqHandler(
226 pldmTransport, event, instanceIdDb, false, seconds(1), 2,
227 milliseconds(100));
Eric Yang70262ed2025-07-02 06:35:03 +0000228 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
229 ASSERT_TRUE(instanceIdResult);
230 auto instanceId = instanceIdResult.value();
Gilbert Chena85c69d2024-01-09 21:25:26 +0700231 EXPECT_EQ(instanceId, 0);
232
233 bool stopped = false;
234
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400235 scope.spawn(
236 stdexec::just() | stdexec::let_value([&] -> exec::task<void> {
237 pldm::Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t), 0);
238 pldm::Response response;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700239
Pavithra Barithaya5ea72372025-02-04 18:09:57 +0530240 auto requestPtr = new (request.data()) pldm_msg;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400241 requestPtr->hdr.instance_id = instanceId;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700242
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400243 co_await reqHandler.sendRecvMsg(eid, std::move(request));
Gilbert Chena85c69d2024-01-09 21:25:26 +0700244
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400245 EXPECT_TRUE(false); // unreachable
246 }) | stdexec::upon_stopped([&] { stopped = true; }),
247 exec::default_task_context<void>(exec::inline_scheduler{}));
Gilbert Chena85c69d2024-01-09 21:25:26 +0700248
249 scope.request_stop();
250
251 EXPECT_TRUE(stopped);
252
253 stdexec::sync_wait(scope.on_empty());
254}
255
256TEST_F(HandlerTest, asyncRequestResponseByCoroutine)
257{
258 struct _
259 {
Patrick Williams366507c2025-02-03 14:28:01 -0500260 static exec::task<uint8_t> getTIDTask(Handler<MockRequest>& handler,
261 mctp_eid_t eid,
262 uint8_t instanceId, uint8_t& tid)
Gilbert Chena85c69d2024-01-09 21:25:26 +0700263 {
264 pldm::Request request(sizeof(pldm_msg_hdr), 0);
Pavithra Barithaya5ea72372025-02-04 18:09:57 +0530265 auto requestMsg = new (request.data()) pldm_msg;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700266 const pldm_msg* responseMsg;
267 size_t responseLen;
268
269 auto rc = encode_get_tid_req(instanceId, requestMsg);
270 EXPECT_EQ(rc, PLDM_SUCCESS);
271
Thu Nguyen6b901e42024-07-10 15:21:10 +0700272 std::tie(rc, responseMsg, responseLen) =
Gilbert Chena85c69d2024-01-09 21:25:26 +0700273 co_await handler.sendRecvMsg(eid, std::move(request));
274 EXPECT_NE(responseLen, 0);
275
276 uint8_t cc = 0;
277 rc = decode_get_tid_resp(responseMsg, responseLen, &cc, &tid);
278 EXPECT_EQ(rc, PLDM_SUCCESS);
279
280 co_return cc;
281 }
282 };
283
284 exec::async_scope scope;
285 Handler<MockRequest> reqHandler(pldmTransport, event, instanceIdDb, false,
286 seconds(1), 2, milliseconds(100));
Eric Yang70262ed2025-07-02 06:35:03 +0000287 auto instanceIdResult = pldm::utils::getInstanceId(instanceIdDb.next(eid));
288 ASSERT_TRUE(instanceIdResult);
289 auto instanceId = instanceIdResult.value();
Gilbert Chena85c69d2024-01-09 21:25:26 +0700290
291 uint8_t expectedTid = 1;
292
293 // Execute a coroutine to send getTID command. The coroutine is suspended
294 // until reqHandler.handleResponse() is received.
295 scope.spawn(stdexec::just() | stdexec::let_value([&] -> exec::task<void> {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400296 uint8_t respTid = 0;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700297
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400298 co_await _::getTIDTask(reqHandler, eid, instanceId,
299 respTid);
Gilbert Chena85c69d2024-01-09 21:25:26 +0700300
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400301 EXPECT_EQ(expectedTid, respTid);
302 }),
Patrick Williams61be7342024-07-30 16:55:33 -0500303 exec::default_task_context<void>(exec::inline_scheduler{}));
Gilbert Chena85c69d2024-01-09 21:25:26 +0700304
305 pldm::Response mockResponse(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES,
306 0);
Pavithra Barithaya5ea72372025-02-04 18:09:57 +0530307 auto mockResponseMsg = new (mockResponse.data()) pldm_msg;
Gilbert Chena85c69d2024-01-09 21:25:26 +0700308
309 // Compose response message of getTID command
310 encode_get_tid_resp(instanceId, PLDM_SUCCESS, expectedTid, mockResponseMsg);
311
312 // Send response back to resume getTID coroutine to update respTid by
313 // calling reqHandler.handleResponse() manually
314 reqHandler.handleResponse(eid, instanceId, PLDM_BASE, PLDM_GET_TID,
315 mockResponseMsg,
316 mockResponse.size() - sizeof(pldm_msg_hdr));
317
318 stdexec::sync_wait(scope.on_empty());
319}