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