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