11ed5f7a6SRashmica Gupta #include "common/transport.hpp" 274f27c73STom Joseph #include "mock_request.hpp" 374f27c73STom Joseph 4c453e164SGeorge Liu #include <libpldm/base.h> 5c453e164SGeorge Liu 674f27c73STom Joseph #include <sdbusplus/timer.hpp> 774f27c73STom Joseph #include <sdeventplus/event.hpp> 874f27c73STom Joseph 974f27c73STom Joseph #include <gmock/gmock.h> 1074f27c73STom Joseph #include <gtest/gtest.h> 1174f27c73STom Joseph 1274f27c73STom Joseph using namespace pldm::requester; 1374f27c73STom Joseph using namespace std::chrono; 1474f27c73STom Joseph using ::testing::AtLeast; 1574f27c73STom Joseph using ::testing::Between; 1674f27c73STom Joseph using ::testing::Exactly; 1774f27c73STom Joseph using ::testing::Return; 1874f27c73STom Joseph 1974f27c73STom Joseph class RequestIntfTest : public testing::Test 2074f27c73STom Joseph { 2174f27c73STom Joseph protected: RequestIntfTest()226da4f91bSPatrick Williams RequestIntfTest() : event(sdeventplus::Event::get_default()) {} 2374f27c73STom Joseph 2474f27c73STom Joseph /** @brief This function runs the sd_event_run in a loop till all the events 2574f27c73STom Joseph * in the testcase are dispatched and exits when there are no events 2674f27c73STom Joseph * for the timeout time. 2774f27c73STom Joseph * 2874f27c73STom Joseph * @param[in] timeout - maximum time to wait for an event 2974f27c73STom Joseph */ waitEventExpiry(milliseconds timeout)3074f27c73STom Joseph void waitEventExpiry(milliseconds timeout) 3174f27c73STom Joseph { 3274f27c73STom Joseph while (1) 3374f27c73STom Joseph { 3474f27c73STom Joseph auto sleepTime = duration_cast<microseconds>(timeout); 3574f27c73STom Joseph // Returns 0 on timeout 3674f27c73STom Joseph if (!sd_event_run(event.get(), sleepTime.count())) 3774f27c73STom Joseph { 3874f27c73STom Joseph break; 3974f27c73STom Joseph } 4074f27c73STom Joseph } 4174f27c73STom Joseph } 4274f27c73STom Joseph 4374f27c73STom Joseph int fd = 0; 4474f27c73STom Joseph mctp_eid_t eid = 0; 451ed5f7a6SRashmica Gupta PldmTransport* pldmTransport = nullptr; 4674f27c73STom Joseph sdeventplus::Event event; 4774f27c73STom Joseph }; 4874f27c73STom Joseph 4974f27c73STom Joseph TEST_F(RequestIntfTest, 0Retries100msTimeout) 5074f27c73STom Joseph { 511ed5f7a6SRashmica Gupta std::vector<uint8_t> requestMsg; 521ed5f7a6SRashmica Gupta MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 0, 531ed5f7a6SRashmica Gupta milliseconds(100), false); 5474f27c73STom Joseph EXPECT_CALL(request, send()) 5574f27c73STom Joseph .Times(Exactly(1)) 5674f27c73STom Joseph .WillOnce(Return(PLDM_SUCCESS)); 5774f27c73STom Joseph auto rc = request.start(); 58a5ed6585STom Joseph EXPECT_EQ(rc, PLDM_SUCCESS); 5974f27c73STom Joseph } 6074f27c73STom Joseph 6174f27c73STom Joseph TEST_F(RequestIntfTest, 2Retries100msTimeout) 6274f27c73STom Joseph { 631ed5f7a6SRashmica Gupta std::vector<uint8_t> requestMsg; 641ed5f7a6SRashmica Gupta MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2, 651ed5f7a6SRashmica Gupta milliseconds(100), false); 6674f27c73STom Joseph // send() is called a total of 3 times, the original plus two retries 6774f27c73STom Joseph EXPECT_CALL(request, send()).Times(3).WillRepeatedly(Return(PLDM_SUCCESS)); 6874f27c73STom Joseph auto rc = request.start(); 69a5ed6585STom Joseph EXPECT_EQ(rc, PLDM_SUCCESS); 7074f27c73STom Joseph waitEventExpiry(milliseconds(500)); 7174f27c73STom Joseph } 7274f27c73STom Joseph 7374f27c73STom Joseph TEST_F(RequestIntfTest, 9Retries100msTimeoutRequestStoppedAfter1sec) 7474f27c73STom Joseph { 751ed5f7a6SRashmica Gupta std::vector<uint8_t> requestMsg; 761ed5f7a6SRashmica Gupta MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 9, 771ed5f7a6SRashmica Gupta milliseconds(100), false); 7874f27c73STom Joseph // send() will be called a total of 10 times, the original plus 9 retries. 7974f27c73STom Joseph // In a ideal scenario send() would have been called 10 times in 1 sec (when 8074f27c73STom Joseph // the timer is stopped) with a timeout of 100ms. Because there are delays 8174f27c73STom Joseph // in dispatch, the range is kept between 5 and 10. This recreates the 8274f27c73STom Joseph // situation where the Instance ID expires before the all the retries have 8374f27c73STom Joseph // been completed and the timer is stopped. 8474f27c73STom Joseph EXPECT_CALL(request, send()) 8574f27c73STom Joseph .Times(Between(5, 10)) 8674f27c73STom Joseph .WillRepeatedly(Return(PLDM_SUCCESS)); 8774f27c73STom Joseph auto rc = request.start(); 88a5ed6585STom Joseph EXPECT_EQ(rc, PLDM_SUCCESS); 8974f27c73STom Joseph __anon6eeae7e50102(void) 9074f27c73STom Joseph auto requestStopCallback = [&](void) { request.stop(); }; 91*35535cf2SPatrick Williams sdbusplus::Timer timer(event.get(), requestStopCallback); 9274f27c73STom Joseph timer.start(duration_cast<microseconds>(seconds(1))); 9374f27c73STom Joseph 9474f27c73STom Joseph waitEventExpiry(milliseconds(500)); 9574f27c73STom Joseph } 9674f27c73STom Joseph 9774f27c73STom Joseph TEST_F(RequestIntfTest, 2Retries100msTimeoutsendReturnsError) 9874f27c73STom Joseph { 991ed5f7a6SRashmica Gupta std::vector<uint8_t> requestMsg; 1001ed5f7a6SRashmica Gupta MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2, 1011ed5f7a6SRashmica Gupta milliseconds(100), false); 10274f27c73STom Joseph EXPECT_CALL(request, send()).Times(Exactly(1)).WillOnce(Return(PLDM_ERROR)); 10374f27c73STom Joseph auto rc = request.start(); 104a5ed6585STom Joseph EXPECT_EQ(rc, PLDM_ERROR); 10574f27c73STom Joseph } 106