blob: 1fd679ff168878f9c864282bbe69eedee02fe9fa [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 Spinler03984582020-04-09 13:17:58 -050035 MOCK_METHOD(std::string, getSystemType, (), (const override));
Matt Spinler9b90e2a2020-04-14 10:59:04 -050036 MOCK_METHOD(std::string, getLocationCode, (const std::string&),
37 (const override));
Matt Spinlerf60ac272019-12-11 13:47:50 -060038
39 void changeHostState(bool newState)
40 {
Matt Spinler4aa23a12020-02-03 15:05:09 -060041 setHostUp(newState);
Matt Spinlerf60ac272019-12-11 13:47:50 -060042 }
43
44 void setHMCManaged(bool managed)
45 {
46 _hmcManaged = managed;
47 }
48};
49
50/**
51 * @brief The mock HostInterface class
Matt Spinler5342d9a2019-12-12 11:03:39 -060052 *
53 * This replaces the PLDM calls with a FIFO for the asynchronous
54 * responses.
Matt Spinlerf60ac272019-12-11 13:47:50 -060055 */
56class MockHostInterface : public HostInterface
57{
58 public:
Matt Spinler5342d9a2019-12-12 11:03:39 -060059 /**
60 * @brief Constructor
61 *
62 * @param[in] event - The sd_event object
63 * @param[in] dataIface - The DataInterface class
64 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060065 MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) :
66 HostInterface(event, dataIface)
67 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060068 char templ[] = "/tmp/cmdfifoXXXXXX";
69 std::filesystem::path dir = mkdtemp(templ);
70 _fifo = dir / "fifo";
Matt Spinlerf60ac272019-12-11 13:47:50 -060071 }
72
Matt Spinler5342d9a2019-12-12 11:03:39 -060073 /**
74 * @brief Destructor
75 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060076 virtual ~MockHostInterface()
77 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060078 std::filesystem::remove_all(_fifo.parent_path());
Matt Spinlerf60ac272019-12-11 13:47:50 -060079 }
80
81 MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override));
82
Matt Spinler5342d9a2019-12-12 11:03:39 -060083 /**
84 * @brief Cancels waiting for a command response
85 */
86 virtual void cancelCmd() override
87 {
88 _inProgress = false;
89 _source = nullptr;
90 }
91
92 /**
93 * @brief Returns the amount of time to wait before retrying after
94 * a failed send command.
95 *
96 * @return milliseconds - The amount of time to wait
97 */
98 virtual std::chrono::milliseconds getSendRetryDelay() const override
99 {
100 return std::chrono::milliseconds(2);
101 }
102
103 /**
104 * @brief Returns the amount of time to wait before retrying after
105 * a command receive.
106 *
107 * @return milliseconds - The amount of time to wait
108 */
109 virtual std::chrono::milliseconds getReceiveRetryDelay() const override
110 {
111 return std::chrono::milliseconds(2);
112 }
113
114 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600115 * @brief Returns the amount of time to wait before retrying if the
116 * host firmware's PEL storage was full and it can't store
117 * any more logs until it is freed up somehow.
118 *
119 * @return milliseconds - The amount of time to wait
120 */
121 virtual std::chrono::milliseconds getHostFullRetryDelay() const override
122 {
Matt Spinler6aae6a02020-02-07 12:46:07 -0600123 return std::chrono::milliseconds(400);
Matt Spinler41293cb2019-12-12 13:11:09 -0600124 }
125
126 /**
Matt Spinler5342d9a2019-12-12 11:03:39 -0600127 * @brief Returns the number of commands processed
128 */
129 size_t numCmdsProcessed() const
130 {
131 return _cmdsProcessed;
132 }
133
134 /**
135 * @brief Writes the data passed in to the FIFO
136 *
137 * @param[in] hostResponse - use a 0 to indicate success
138 *
139 * @return CmdStatus - success or failure
140 */
141 CmdStatus send(uint8_t hostResponse)
142 {
143 // Create a FIFO once.
144 if (!std::filesystem::exists(_fifo))
145 {
146 if (mkfifo(_fifo.c_str(), 0622))
147 {
148 ADD_FAILURE() << "Failed mkfifo " << _fifo << strerror(errno);
149 exit(-1);
150 }
151 }
152
153 // Open it and register the reponse callback to
154 // be used on FD activity.
155 int fd = open(_fifo.c_str(), O_NONBLOCK | O_RDWR);
156 EXPECT_TRUE(fd >= 0) << "Unable to open FIFO";
157
158 auto callback = [this](sdeventplus::source::IO& source, int fd,
159 uint32_t events) {
160 this->receive(source, fd, events);
161 };
162
163 try
164 {
165 _source = std::make_unique<sdeventplus::source::IO>(
166 _event, fd, EPOLLIN,
167 std::bind(callback, std::placeholders::_1,
168 std::placeholders::_2, std::placeholders::_3));
169 }
170 catch (std::exception& e)
171 {
172 ADD_FAILURE() << "Event exception: " << e.what();
173 close(fd);
174 return CmdStatus::failure;
175 }
176
177 // Write the fake host reponse to the FIFO
178 auto bytesWritten = write(fd, &hostResponse, sizeof(hostResponse));
179 EXPECT_EQ(bytesWritten, sizeof(hostResponse));
180
181 _inProgress = true;
182
183 return CmdStatus::success;
184 }
185
Matt Spinlerf60ac272019-12-11 13:47:50 -0600186 protected:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600187 /**
188 * @brief Reads the data written to the fifo and then calls
189 * the subscriber's callback.
190 *
191 * Nonzero data indicates a command failure (for testing bad path).
192 *
193 * @param[in] source - The event source object
194 * @param[in] fd - The file descriptor used
195 * @param[in] events - The event bits
196 */
Matt Spinlerf60ac272019-12-11 13:47:50 -0600197 void receive(sdeventplus::source::IO& source, int fd,
198 uint32_t events) override
199 {
Matt Spinler5342d9a2019-12-12 11:03:39 -0600200 if (!(events & EPOLLIN))
201 {
202 return;
203 }
204
205 _inProgress = false;
206
207 int newFD = open(_fifo.c_str(), O_NONBLOCK | O_RDONLY);
208 ASSERT_TRUE(newFD >= 0) << "Failed to open FIFO";
209
210 // Read the host success/failure response from the FIFO.
211 uint8_t data;
212 auto bytesRead = read(newFD, &data, sizeof(data));
213 EXPECT_EQ(bytesRead, sizeof(data));
214
215 close(newFD);
216
217 ResponseStatus status = ResponseStatus::success;
218 if (data != 0)
219 {
220 status = ResponseStatus::failure;
221 }
222
Matt Spinlera44efe42020-03-03 10:30:16 -0600223 callResponseFunc(status);
Matt Spinler5342d9a2019-12-12 11:03:39 -0600224
Matt Spinlerf60ac272019-12-11 13:47:50 -0600225 // Keep account of the number of commands responses for testing.
226 _cmdsProcessed++;
227 }
228
229 private:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600230 /**
231 * @brief The event source for the fifo
232 */
233 std::unique_ptr<sdeventplus::source::IO> _source;
234
235 /**
236 * @brief the path to the fifo
237 */
238 std::filesystem::path _fifo;
239
240 /**
241 * @brief The number of commands processed
242 */
Matt Spinlerf60ac272019-12-11 13:47:50 -0600243 size_t _cmdsProcessed = 0;
Matt Spinler09d64002019-09-11 14:29:46 -0500244};
245
246} // namespace pels
247} // namespace openpower