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