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