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