| Matt Spinler | 09d6400 | 2019-09-11 14:29:46 -0500 | [diff] [blame] | 1 | #include "extensions/openpower-pels/data_interface.hpp" | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 2 | #include "extensions/openpower-pels/host_interface.hpp" | 
| Matt Spinler | d96fa60 | 2022-12-15 11:11:26 -0600 | [diff] [blame] | 3 | #include "extensions/openpower-pels/journal.hpp" | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 4 |  | 
|  | 5 | #include <fcntl.h> | 
|  | 6 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 7 | #include <sdeventplus/source/io.hpp> | 
| Matt Spinler | 09d6400 | 2019-09-11 14:29:46 -0500 | [diff] [blame] | 8 |  | 
| Patrick Williams | 2544b41 | 2022-10-04 08:41:06 -0500 | [diff] [blame] | 9 | #include <filesystem> | 
|  | 10 |  | 
| Matt Spinler | 09d6400 | 2019-09-11 14:29:46 -0500 | [diff] [blame] | 11 | #include <gmock/gmock.h> | 
|  | 12 |  | 
|  | 13 | namespace openpower | 
|  | 14 | { | 
|  | 15 | namespace pels | 
|  | 16 | { | 
|  | 17 |  | 
|  | 18 | class MockDataInterface : public DataInterfaceBase | 
|  | 19 | { | 
|  | 20 | public: | 
| Matt Spinler | 784b02e | 2023-04-25 11:07:55 -0500 | [diff] [blame^] | 21 | MockDataInterface() | 
|  | 22 | { | 
|  | 23 | ON_CALL(*this, checkDumpStatus) | 
|  | 24 | .WillByDefault( | 
|  | 25 | ::testing::Return(std::vector<bool>({false, false, false}))); | 
|  | 26 | } | 
|  | 27 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 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)); | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 32 | MOCK_METHOD(std::string, getBMCFWVersionID, (), (const override)); | 
| Matt Spinler | 24a8558 | 2020-01-27 16:40:21 -0600 | [diff] [blame] | 33 | MOCK_METHOD(bool, getHostPELEnablement, (), (const override)); | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 34 | MOCK_METHOD(std::string, getBMCState, (), (const override)); | 
|  | 35 | MOCK_METHOD(std::string, getChassisState, (), (const override)); | 
|  | 36 | MOCK_METHOD(std::string, getHostState, (), (const override)); | 
| Matt Spinler | 075e5ba | 2020-02-21 15:46:00 -0600 | [diff] [blame] | 37 | MOCK_METHOD(std::string, getMotherboardCCIN, (), (const override)); | 
| Matt Spinler | 60c4e79 | 2020-03-13 13:45:36 -0500 | [diff] [blame] | 38 | MOCK_METHOD(void, getHWCalloutFields, | 
| Matt Spinler | 9b90e2a | 2020-04-14 10:59:04 -0500 | [diff] [blame] | 39 | (const std::string&, std::string&, std::string&, std::string&), | 
| Matt Spinler | 60c4e79 | 2020-03-13 13:45:36 -0500 | [diff] [blame] | 40 | (const override)); | 
| Matt Spinler | 9b90e2a | 2020-04-14 10:59:04 -0500 | [diff] [blame] | 41 | MOCK_METHOD(std::string, getLocationCode, (const std::string&), | 
|  | 42 | (const override)); | 
| Matt Spinler | 1ab6696 | 2020-10-29 13:21:44 -0500 | [diff] [blame] | 43 | MOCK_METHOD(std::vector<std::string>, getSystemNames, (), (const override)); | 
| Matt Spinler | 5fb24c1 | 2020-06-04 11:21:33 -0500 | [diff] [blame] | 44 | MOCK_METHOD(std::string, expandLocationCode, (const std::string&, uint16_t), | 
|  | 45 | (const override)); | 
| Matt Spinler | bad056b | 2023-01-25 14:16:57 -0600 | [diff] [blame] | 46 | MOCK_METHOD(std::vector<std::string>, getInventoryFromLocCode, | 
| Matt Spinler | 2f9225a | 2020-08-05 12:58:49 -0500 | [diff] [blame] | 47 | (const std::string&, uint16_t, bool), (const override)); | 
| Matt Spinler | 34a904c | 2020-08-05 14:53:28 -0500 | [diff] [blame] | 48 | MOCK_METHOD(void, assertLEDGroup, (const std::string&, bool), | 
|  | 49 | (const override)); | 
| Matt Spinler | 993168d | 2021-04-07 16:05:03 -0500 | [diff] [blame] | 50 | MOCK_METHOD(void, setFunctional, (const std::string&, bool), | 
|  | 51 | (const override)); | 
| Ben Tyner | e32b7e7 | 2021-05-18 12:38:40 -0500 | [diff] [blame] | 52 | MOCK_METHOD(std::vector<uint8_t>, getSystemIMKeyword, (), (const override)); | 
| Sumit Kumar | 3b8ed7f | 2021-05-18 12:38:35 -0500 | [diff] [blame] | 53 | MOCK_METHOD(bool, getQuiesceOnError, (), (const override)); | 
| Sumit Kumar | 76198a2 | 2021-07-15 05:59:57 -0500 | [diff] [blame] | 54 | MOCK_METHOD(void, setCriticalAssociation, (const std::string&), | 
|  | 55 | (const override)); | 
| Sumit Kumar | 9d43a72 | 2021-08-24 09:46:19 -0500 | [diff] [blame] | 56 | MOCK_METHOD(std::vector<bool>, checkDumpStatus, | 
|  | 57 | (const std::vector<std::string>&), (const override)); | 
| Sumit Kumar | 2c36fdd | 2021-09-21 03:12:11 -0500 | [diff] [blame] | 58 | MOCK_METHOD(std::string, getBootState, (), (const override)); | 
| Jayanth Othayoth | ecaa2fc | 2021-11-05 02:02:52 -0500 | [diff] [blame] | 59 | MOCK_METHOD(void, createGuardRecord, | 
|  | 60 | (const std::vector<uint8_t>&, const std::string&, | 
|  | 61 | const std::string&), | 
|  | 62 | (const override)); | 
| Sumit Kumar | 3e27443 | 2021-09-14 06:37:56 -0500 | [diff] [blame] | 63 | MOCK_METHOD(void, createProgressSRC, | 
|  | 64 | (const uint64_t&, const std::vector<uint8_t>&), | 
|  | 65 | (const override)); | 
| Sumit Kumar | 027bf28 | 2022-01-24 11:25:19 -0600 | [diff] [blame] | 66 | MOCK_METHOD(std::vector<uint32_t>, getLogIDWithHwIsolation, (), | 
|  | 67 | (const override)); | 
| Vijay Lobo | 875b6c7 | 2021-10-20 17:38:56 -0500 | [diff] [blame] | 68 | MOCK_METHOD(std::vector<uint8_t>, getRawProgressSRC, (), (const override)); | 
| Matt Spinler | 34a904c | 2020-08-05 14:53:28 -0500 | [diff] [blame] | 69 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 70 | void changeHostState(bool newState) | 
|  | 71 | { | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 72 | setHostUp(newState); | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 73 | } | 
|  | 74 |  | 
|  | 75 | void setHMCManaged(bool managed) | 
|  | 76 | { | 
|  | 77 | _hmcManaged = managed; | 
|  | 78 | } | 
|  | 79 | }; | 
|  | 80 |  | 
|  | 81 | /** | 
|  | 82 | * @brief The mock HostInterface class | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 83 | * | 
|  | 84 | * This replaces the PLDM calls with a FIFO for the asynchronous | 
|  | 85 | * responses. | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 86 | */ | 
|  | 87 | class MockHostInterface : public HostInterface | 
|  | 88 | { | 
|  | 89 | public: | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 90 | /** | 
|  | 91 | * @brief Constructor | 
|  | 92 | * | 
|  | 93 | * @param[in] event - The sd_event object | 
|  | 94 | * @param[in] dataIface - The DataInterface class | 
|  | 95 | */ | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 96 | MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) : | 
|  | 97 | HostInterface(event, dataIface) | 
|  | 98 | { | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 99 | char templ[] = "/tmp/cmdfifoXXXXXX"; | 
|  | 100 | std::filesystem::path dir = mkdtemp(templ); | 
|  | 101 | _fifo = dir / "fifo"; | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 102 | } | 
|  | 103 |  | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 104 | /** | 
|  | 105 | * @brief Destructor | 
|  | 106 | */ | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 107 | virtual ~MockHostInterface() | 
|  | 108 | { | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 109 | std::filesystem::remove_all(_fifo.parent_path()); | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 110 | } | 
|  | 111 |  | 
|  | 112 | MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override)); | 
|  | 113 |  | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 | /** | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 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 | { | 
| Matt Spinler | 6aae6a0 | 2020-02-07 12:46:07 -0600 | [diff] [blame] | 154 | return std::chrono::milliseconds(400); | 
| Matt Spinler | 41293cb | 2019-12-12 13:11:09 -0600 | [diff] [blame] | 155 | } | 
|  | 156 |  | 
|  | 157 | /** | 
| Matt Spinler | e5f7508 | 2022-01-24 16:09:51 -0600 | [diff] [blame] | 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 | /** | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 |  | 
| Patrick Williams | ac1ba3f | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 200 | auto callback = | 
|  | 201 | [this](sdeventplus::source::IO& source, int fd, uint32_t events) { | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 | } | 
| Patrick Williams | 66491c6 | 2021-10-06 12:23:37 -0500 | [diff] [blame] | 212 | catch (const std::exception& e) | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 228 | protected: | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 | */ | 
| Patrick Williams | d26fa3e | 2021-04-21 15:22:23 -0500 | [diff] [blame] | 239 | void receive(sdeventplus::source::IO& /*source*/, int /*fd*/, | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 240 | uint32_t events) override | 
|  | 241 | { | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 |  | 
| Matt Spinler | a44efe4 | 2020-03-03 10:30:16 -0600 | [diff] [blame] | 265 | callResponseFunc(status); | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 266 |  | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 267 | // Keep account of the number of commands responses for testing. | 
|  | 268 | _cmdsProcessed++; | 
|  | 269 | } | 
|  | 270 |  | 
|  | 271 | private: | 
| Matt Spinler | 5342d9a | 2019-12-12 11:03:39 -0600 | [diff] [blame] | 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 | */ | 
| Matt Spinler | f60ac27 | 2019-12-11 13:47:50 -0600 | [diff] [blame] | 285 | size_t _cmdsProcessed = 0; | 
| Matt Spinler | 09d6400 | 2019-09-11 14:29:46 -0500 | [diff] [blame] | 286 | }; | 
|  | 287 |  | 
| Matt Spinler | d96fa60 | 2022-12-15 11:11:26 -0600 | [diff] [blame] | 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)); | 
| Matt Spinler | 9d92109 | 2022-12-15 11:54:49 -0600 | [diff] [blame] | 295 |  | 
|  | 296 | MOCK_METHOD(void, sync, (), (const override)); | 
| Matt Spinler | d96fa60 | 2022-12-15 11:11:26 -0600 | [diff] [blame] | 297 | }; | 
|  | 298 |  | 
| Matt Spinler | 09d6400 | 2019-09-11 14:29:46 -0500 | [diff] [blame] | 299 | } // namespace pels | 
|  | 300 | } // namespace openpower |