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