blob: 99e97832da0645cdbb22f0cc76d6897b744202db [file] [log] [blame]
Matt Spinler09d64002019-09-11 14:29:46 -05001#include "extensions/openpower-pels/data_interface.hpp"
Matt Spinlerf60ac272019-12-11 13:47:50 -06002#include "extensions/openpower-pels/host_interface.hpp"
3
4#include <fcntl.h>
5
6#include <filesystem>
7#include <sdeventplus/source/io.hpp>
Matt Spinler09d64002019-09-11 14:29:46 -05008
9#include <gmock/gmock.h>
10
11namespace openpower
12{
13namespace pels
14{
15
16class MockDataInterface : public DataInterfaceBase
17{
18 public:
19 MockDataInterface()
20 {
21 }
Matt Spinlerf60ac272019-12-11 13:47:50 -060022 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));
Matt Spinler677381b2020-01-23 10:04:29 -060026 MOCK_METHOD(std::string, getBMCFWVersionID, (), (const override));
Matt Spinler24a85582020-01-27 16:40:21 -060027 MOCK_METHOD(bool, getHostPELEnablement, (), (const override));
Matt Spinler4aa23a12020-02-03 15:05:09 -060028 MOCK_METHOD(std::string, getBMCState, (), (const override));
29 MOCK_METHOD(std::string, getChassisState, (), (const override));
30 MOCK_METHOD(std::string, getHostState, (), (const override));
Matt Spinler075e5ba2020-02-21 15:46:00 -060031 MOCK_METHOD(std::string, getMotherboardCCIN, (), (const override));
Matt Spinler60c4e792020-03-13 13:45:36 -050032 MOCK_METHOD(void, getHWCalloutFields,
Matt Spinler9b90e2a2020-04-14 10:59:04 -050033 (const std::string&, std::string&, std::string&, std::string&),
Matt Spinler60c4e792020-03-13 13:45:36 -050034 (const override));
Matt Spinler9b90e2a2020-04-14 10:59:04 -050035 MOCK_METHOD(std::string, getLocationCode, (const std::string&),
36 (const override));
Matt Spinler1ab66962020-10-29 13:21:44 -050037 MOCK_METHOD(std::vector<std::string>, getSystemNames, (), (const override));
Matt Spinler5fb24c12020-06-04 11:21:33 -050038 MOCK_METHOD(std::string, expandLocationCode, (const std::string&, uint16_t),
39 (const override));
40 MOCK_METHOD(std::string, getInventoryFromLocCode,
Matt Spinler2f9225a2020-08-05 12:58:49 -050041 (const std::string&, uint16_t, bool), (const override));
Matt Spinler34a904c2020-08-05 14:53:28 -050042 MOCK_METHOD(void, assertLEDGroup, (const std::string&, bool),
43 (const override));
Matt Spinler993168d2021-04-07 16:05:03 -050044 MOCK_METHOD(void, setFunctional, (const std::string&, bool),
45 (const override));
Ben Tynere32b7e72021-05-18 12:38:40 -050046 MOCK_METHOD(std::vector<uint8_t>, getSystemIMKeyword, (), (const override));
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050047 MOCK_METHOD(bool, getQuiesceOnError, (), (const override));
Sumit Kumar76198a22021-07-15 05:59:57 -050048 MOCK_METHOD(void, setCriticalAssociation, (const std::string&),
49 (const override));
Sumit Kumar9d43a722021-08-24 09:46:19 -050050 MOCK_METHOD(std::vector<bool>, checkDumpStatus,
51 (const std::vector<std::string>&), (const override));
Sumit Kumar2c36fdd2021-09-21 03:12:11 -050052 MOCK_METHOD(std::string, getBootState, (), (const override));
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050053 MOCK_METHOD(void, createGuardRecord,
54 (const std::vector<uint8_t>&, const std::string&,
55 const std::string&),
56 (const override));
Matt Spinler34a904c2020-08-05 14:53:28 -050057
Matt Spinlerf60ac272019-12-11 13:47:50 -060058 void changeHostState(bool newState)
59 {
Matt Spinler4aa23a12020-02-03 15:05:09 -060060 setHostUp(newState);
Matt Spinlerf60ac272019-12-11 13:47:50 -060061 }
62
63 void setHMCManaged(bool managed)
64 {
65 _hmcManaged = managed;
66 }
67};
68
69/**
70 * @brief The mock HostInterface class
Matt Spinler5342d9a2019-12-12 11:03:39 -060071 *
72 * This replaces the PLDM calls with a FIFO for the asynchronous
73 * responses.
Matt Spinlerf60ac272019-12-11 13:47:50 -060074 */
75class MockHostInterface : public HostInterface
76{
77 public:
Matt Spinler5342d9a2019-12-12 11:03:39 -060078 /**
79 * @brief Constructor
80 *
81 * @param[in] event - The sd_event object
82 * @param[in] dataIface - The DataInterface class
83 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060084 MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) :
85 HostInterface(event, dataIface)
86 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060087 char templ[] = "/tmp/cmdfifoXXXXXX";
88 std::filesystem::path dir = mkdtemp(templ);
89 _fifo = dir / "fifo";
Matt Spinlerf60ac272019-12-11 13:47:50 -060090 }
91
Matt Spinler5342d9a2019-12-12 11:03:39 -060092 /**
93 * @brief Destructor
94 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060095 virtual ~MockHostInterface()
96 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060097 std::filesystem::remove_all(_fifo.parent_path());
Matt Spinlerf60ac272019-12-11 13:47:50 -060098 }
99
100 MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override));
101
Matt Spinler5342d9a2019-12-12 11:03:39 -0600102 /**
103 * @brief Cancels waiting for a command response
104 */
105 virtual void cancelCmd() override
106 {
107 _inProgress = false;
108 _source = nullptr;
109 }
110
111 /**
112 * @brief Returns the amount of time to wait before retrying after
113 * a failed send command.
114 *
115 * @return milliseconds - The amount of time to wait
116 */
117 virtual std::chrono::milliseconds getSendRetryDelay() const override
118 {
119 return std::chrono::milliseconds(2);
120 }
121
122 /**
123 * @brief Returns the amount of time to wait before retrying after
124 * a command receive.
125 *
126 * @return milliseconds - The amount of time to wait
127 */
128 virtual std::chrono::milliseconds getReceiveRetryDelay() const override
129 {
130 return std::chrono::milliseconds(2);
131 }
132
133 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600134 * @brief Returns the amount of time to wait before retrying if the
135 * host firmware's PEL storage was full and it can't store
136 * any more logs until it is freed up somehow.
137 *
138 * @return milliseconds - The amount of time to wait
139 */
140 virtual std::chrono::milliseconds getHostFullRetryDelay() const override
141 {
Matt Spinler6aae6a02020-02-07 12:46:07 -0600142 return std::chrono::milliseconds(400);
Matt Spinler41293cb2019-12-12 13:11:09 -0600143 }
144
145 /**
Matt Spinler5342d9a2019-12-12 11:03:39 -0600146 * @brief Returns the number of commands processed
147 */
148 size_t numCmdsProcessed() const
149 {
150 return _cmdsProcessed;
151 }
152
153 /**
154 * @brief Writes the data passed in to the FIFO
155 *
156 * @param[in] hostResponse - use a 0 to indicate success
157 *
158 * @return CmdStatus - success or failure
159 */
160 CmdStatus send(uint8_t hostResponse)
161 {
162 // Create a FIFO once.
163 if (!std::filesystem::exists(_fifo))
164 {
165 if (mkfifo(_fifo.c_str(), 0622))
166 {
167 ADD_FAILURE() << "Failed mkfifo " << _fifo << strerror(errno);
168 exit(-1);
169 }
170 }
171
172 // Open it and register the reponse callback to
173 // be used on FD activity.
174 int fd = open(_fifo.c_str(), O_NONBLOCK | O_RDWR);
175 EXPECT_TRUE(fd >= 0) << "Unable to open FIFO";
176
177 auto callback = [this](sdeventplus::source::IO& source, int fd,
178 uint32_t events) {
179 this->receive(source, fd, events);
180 };
181
182 try
183 {
184 _source = std::make_unique<sdeventplus::source::IO>(
185 _event, fd, EPOLLIN,
186 std::bind(callback, std::placeholders::_1,
187 std::placeholders::_2, std::placeholders::_3));
188 }
Patrick Williams66491c62021-10-06 12:23:37 -0500189 catch (const std::exception& e)
Matt Spinler5342d9a2019-12-12 11:03:39 -0600190 {
191 ADD_FAILURE() << "Event exception: " << e.what();
192 close(fd);
193 return CmdStatus::failure;
194 }
195
196 // Write the fake host reponse to the FIFO
197 auto bytesWritten = write(fd, &hostResponse, sizeof(hostResponse));
198 EXPECT_EQ(bytesWritten, sizeof(hostResponse));
199
200 _inProgress = true;
201
202 return CmdStatus::success;
203 }
204
Matt Spinlerf60ac272019-12-11 13:47:50 -0600205 protected:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600206 /**
207 * @brief Reads the data written to the fifo and then calls
208 * the subscriber's callback.
209 *
210 * Nonzero data indicates a command failure (for testing bad path).
211 *
212 * @param[in] source - The event source object
213 * @param[in] fd - The file descriptor used
214 * @param[in] events - The event bits
215 */
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500216 void receive(sdeventplus::source::IO& /*source*/, int /*fd*/,
Matt Spinlerf60ac272019-12-11 13:47:50 -0600217 uint32_t events) override
218 {
Matt Spinler5342d9a2019-12-12 11:03:39 -0600219 if (!(events & EPOLLIN))
220 {
221 return;
222 }
223
224 _inProgress = false;
225
226 int newFD = open(_fifo.c_str(), O_NONBLOCK | O_RDONLY);
227 ASSERT_TRUE(newFD >= 0) << "Failed to open FIFO";
228
229 // Read the host success/failure response from the FIFO.
230 uint8_t data;
231 auto bytesRead = read(newFD, &data, sizeof(data));
232 EXPECT_EQ(bytesRead, sizeof(data));
233
234 close(newFD);
235
236 ResponseStatus status = ResponseStatus::success;
237 if (data != 0)
238 {
239 status = ResponseStatus::failure;
240 }
241
Matt Spinlera44efe42020-03-03 10:30:16 -0600242 callResponseFunc(status);
Matt Spinler5342d9a2019-12-12 11:03:39 -0600243
Matt Spinlerf60ac272019-12-11 13:47:50 -0600244 // Keep account of the number of commands responses for testing.
245 _cmdsProcessed++;
246 }
247
248 private:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600249 /**
250 * @brief The event source for the fifo
251 */
252 std::unique_ptr<sdeventplus::source::IO> _source;
253
254 /**
255 * @brief the path to the fifo
256 */
257 std::filesystem::path _fifo;
258
259 /**
260 * @brief The number of commands processed
261 */
Matt Spinlerf60ac272019-12-11 13:47:50 -0600262 size_t _cmdsProcessed = 0;
Matt Spinler09d64002019-09-11 14:29:46 -0500263};
264
265} // namespace pels
266} // namespace openpower