1 #include "common/transport.hpp"
2 #include "mock_request.hpp"
3 
4 #include <libpldm/base.h>
5 
6 #include <sdbusplus/timer.hpp>
7 #include <sdeventplus/event.hpp>
8 
9 #include <gmock/gmock.h>
10 #include <gtest/gtest.h>
11 
12 using namespace pldm::requester;
13 using namespace std::chrono;
14 using ::testing::AtLeast;
15 using ::testing::Between;
16 using ::testing::Exactly;
17 using ::testing::Return;
18 
19 class RequestIntfTest : public testing::Test
20 {
21   protected:
22     RequestIntfTest() : event(sdeventplus::Event::get_default()) {}
23 
24     /** @brief This function runs the sd_event_run in a loop till all the events
25      *         in the testcase are dispatched and exits when there are no events
26      *         for the timeout time.
27      *
28      *  @param[in] timeout - maximum time to wait for an event
29      */
30     void waitEventExpiry(milliseconds timeout)
31     {
32         while (1)
33         {
34             auto sleepTime = duration_cast<microseconds>(timeout);
35             // Returns 0 on timeout
36             if (!sd_event_run(event.get(), sleepTime.count()))
37             {
38                 break;
39             }
40         }
41     }
42 
43     int fd = 0;
44     mctp_eid_t eid = 0;
45     PldmTransport* pldmTransport = nullptr;
46     sdeventplus::Event event;
47 };
48 
49 TEST_F(RequestIntfTest, 0Retries100msTimeout)
50 {
51     std::vector<uint8_t> requestMsg;
52     MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 0,
53                         milliseconds(100), false);
54     EXPECT_CALL(request, send())
55         .Times(Exactly(1))
56         .WillOnce(Return(PLDM_SUCCESS));
57     auto rc = request.start();
58     EXPECT_EQ(rc, PLDM_SUCCESS);
59 }
60 
61 TEST_F(RequestIntfTest, 2Retries100msTimeout)
62 {
63     std::vector<uint8_t> requestMsg;
64     MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2,
65                         milliseconds(100), false);
66     // send() is called a total of 3 times, the original plus two retries
67     EXPECT_CALL(request, send()).Times(3).WillRepeatedly(Return(PLDM_SUCCESS));
68     auto rc = request.start();
69     EXPECT_EQ(rc, PLDM_SUCCESS);
70     waitEventExpiry(milliseconds(500));
71 }
72 
73 TEST_F(RequestIntfTest, 9Retries100msTimeoutRequestStoppedAfter1sec)
74 {
75     std::vector<uint8_t> requestMsg;
76     MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 9,
77                         milliseconds(100), false);
78     // send() will be called a total of 10 times, the original plus 9 retries.
79     // In a ideal scenario send() would have been called 10 times in 1 sec (when
80     // the timer is stopped) with a timeout of 100ms. Because there are delays
81     // in dispatch, the range is kept between 5 and 10. This recreates the
82     // situation where the Instance ID expires before the all the retries have
83     // been completed and the timer is stopped.
84     EXPECT_CALL(request, send())
85         .Times(Between(5, 10))
86         .WillRepeatedly(Return(PLDM_SUCCESS));
87     auto rc = request.start();
88     EXPECT_EQ(rc, PLDM_SUCCESS);
89 
90     auto requestStopCallback = [&](void) { request.stop(); };
91     phosphor::Timer timer(event.get(), requestStopCallback);
92     timer.start(duration_cast<microseconds>(seconds(1)));
93 
94     waitEventExpiry(milliseconds(500));
95 }
96 
97 TEST_F(RequestIntfTest, 2Retries100msTimeoutsendReturnsError)
98 {
99     std::vector<uint8_t> requestMsg;
100     MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2,
101                         milliseconds(100), false);
102     EXPECT_CALL(request, send()).Times(Exactly(1)).WillOnce(Return(PLDM_ERROR));
103     auto rc = request.start();
104     EXPECT_EQ(rc, PLDM_ERROR);
105 }
106