1 #include "extensions/openpower-pels/data_interface.hpp" 2 #include "extensions/openpower-pels/host_interface.hpp" 3 4 #include <fcntl.h> 5 6 #include <filesystem> 7 #include <sdeventplus/source/io.hpp> 8 9 #include <gmock/gmock.h> 10 11 namespace openpower 12 { 13 namespace pels 14 { 15 16 class MockDataInterface : public DataInterfaceBase 17 { 18 public: 19 MockDataInterface() 20 { 21 } 22 MOCK_METHOD(std::string, getMachineTypeModel, (), (const override)); 23 MOCK_METHOD(std::string, getMachineSerialNumber, (), (const override)); 24 MOCK_METHOD(std::string, getServerFWVersion, (), (const override)); 25 MOCK_METHOD(std::string, getBMCFWVersion, (), (const override)); 26 MOCK_METHOD(std::string, getBMCFWVersionID, (), (const override)); 27 MOCK_METHOD(bool, getHostPELEnablement, (), (const override)); 28 MOCK_METHOD(std::string, getBMCState, (), (const override)); 29 MOCK_METHOD(std::string, getChassisState, (), (const override)); 30 MOCK_METHOD(std::string, getHostState, (), (const override)); 31 MOCK_METHOD(std::string, getMotherboardCCIN, (), (const override)); 32 33 void changeHostState(bool newState) 34 { 35 setHostUp(newState); 36 } 37 38 void setHMCManaged(bool managed) 39 { 40 _hmcManaged = managed; 41 } 42 }; 43 44 /** 45 * @brief The mock HostInterface class 46 * 47 * This replaces the PLDM calls with a FIFO for the asynchronous 48 * responses. 49 */ 50 class MockHostInterface : public HostInterface 51 { 52 public: 53 /** 54 * @brief Constructor 55 * 56 * @param[in] event - The sd_event object 57 * @param[in] dataIface - The DataInterface class 58 */ 59 MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) : 60 HostInterface(event, dataIface) 61 { 62 char templ[] = "/tmp/cmdfifoXXXXXX"; 63 std::filesystem::path dir = mkdtemp(templ); 64 _fifo = dir / "fifo"; 65 } 66 67 /** 68 * @brief Destructor 69 */ 70 virtual ~MockHostInterface() 71 { 72 std::filesystem::remove_all(_fifo.parent_path()); 73 } 74 75 MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override)); 76 77 /** 78 * @brief Cancels waiting for a command response 79 */ 80 virtual void cancelCmd() override 81 { 82 _inProgress = false; 83 _source = nullptr; 84 } 85 86 /** 87 * @brief Returns the amount of time to wait before retrying after 88 * a failed send command. 89 * 90 * @return milliseconds - The amount of time to wait 91 */ 92 virtual std::chrono::milliseconds getSendRetryDelay() const override 93 { 94 return std::chrono::milliseconds(2); 95 } 96 97 /** 98 * @brief Returns the amount of time to wait before retrying after 99 * a command receive. 100 * 101 * @return milliseconds - The amount of time to wait 102 */ 103 virtual std::chrono::milliseconds getReceiveRetryDelay() const override 104 { 105 return std::chrono::milliseconds(2); 106 } 107 108 /** 109 * @brief Returns the amount of time to wait before retrying if the 110 * host firmware's PEL storage was full and it can't store 111 * any more logs until it is freed up somehow. 112 * 113 * @return milliseconds - The amount of time to wait 114 */ 115 virtual std::chrono::milliseconds getHostFullRetryDelay() const override 116 { 117 return std::chrono::milliseconds(400); 118 } 119 120 /** 121 * @brief Returns the number of commands processed 122 */ 123 size_t numCmdsProcessed() const 124 { 125 return _cmdsProcessed; 126 } 127 128 /** 129 * @brief Writes the data passed in to the FIFO 130 * 131 * @param[in] hostResponse - use a 0 to indicate success 132 * 133 * @return CmdStatus - success or failure 134 */ 135 CmdStatus send(uint8_t hostResponse) 136 { 137 // Create a FIFO once. 138 if (!std::filesystem::exists(_fifo)) 139 { 140 if (mkfifo(_fifo.c_str(), 0622)) 141 { 142 ADD_FAILURE() << "Failed mkfifo " << _fifo << strerror(errno); 143 exit(-1); 144 } 145 } 146 147 // Open it and register the reponse callback to 148 // be used on FD activity. 149 int fd = open(_fifo.c_str(), O_NONBLOCK | O_RDWR); 150 EXPECT_TRUE(fd >= 0) << "Unable to open FIFO"; 151 152 auto callback = [this](sdeventplus::source::IO& source, int fd, 153 uint32_t events) { 154 this->receive(source, fd, events); 155 }; 156 157 try 158 { 159 _source = std::make_unique<sdeventplus::source::IO>( 160 _event, fd, EPOLLIN, 161 std::bind(callback, std::placeholders::_1, 162 std::placeholders::_2, std::placeholders::_3)); 163 } 164 catch (std::exception& e) 165 { 166 ADD_FAILURE() << "Event exception: " << e.what(); 167 close(fd); 168 return CmdStatus::failure; 169 } 170 171 // Write the fake host reponse to the FIFO 172 auto bytesWritten = write(fd, &hostResponse, sizeof(hostResponse)); 173 EXPECT_EQ(bytesWritten, sizeof(hostResponse)); 174 175 _inProgress = true; 176 177 return CmdStatus::success; 178 } 179 180 protected: 181 /** 182 * @brief Reads the data written to the fifo and then calls 183 * the subscriber's callback. 184 * 185 * Nonzero data indicates a command failure (for testing bad path). 186 * 187 * @param[in] source - The event source object 188 * @param[in] fd - The file descriptor used 189 * @param[in] events - The event bits 190 */ 191 void receive(sdeventplus::source::IO& source, int fd, 192 uint32_t events) override 193 { 194 if (!(events & EPOLLIN)) 195 { 196 return; 197 } 198 199 _inProgress = false; 200 201 int newFD = open(_fifo.c_str(), O_NONBLOCK | O_RDONLY); 202 ASSERT_TRUE(newFD >= 0) << "Failed to open FIFO"; 203 204 // Read the host success/failure response from the FIFO. 205 uint8_t data; 206 auto bytesRead = read(newFD, &data, sizeof(data)); 207 EXPECT_EQ(bytesRead, sizeof(data)); 208 209 close(newFD); 210 211 ResponseStatus status = ResponseStatus::success; 212 if (data != 0) 213 { 214 status = ResponseStatus::failure; 215 } 216 217 callResponseFunc(status); 218 219 // Keep account of the number of commands responses for testing. 220 _cmdsProcessed++; 221 } 222 223 private: 224 /** 225 * @brief The event source for the fifo 226 */ 227 std::unique_ptr<sdeventplus::source::IO> _source; 228 229 /** 230 * @brief the path to the fifo 231 */ 232 std::filesystem::path _fifo; 233 234 /** 235 * @brief The number of commands processed 236 */ 237 size_t _cmdsProcessed = 0; 238 }; 239 240 } // namespace pels 241 } // namespace openpower 242