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