blob: 5bec57926f998e63e18c6b032370168301d00524 [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));
26
27 void changeHostState(bool newState)
28 {
29 setHostState(newState);
30 }
31
32 void setHMCManaged(bool managed)
33 {
34 _hmcManaged = managed;
35 }
36};
37
38/**
39 * @brief The mock HostInterface class
Matt Spinler5342d9a2019-12-12 11:03:39 -060040 *
41 * This replaces the PLDM calls with a FIFO for the asynchronous
42 * responses.
Matt Spinlerf60ac272019-12-11 13:47:50 -060043 */
44class MockHostInterface : public HostInterface
45{
46 public:
Matt Spinler5342d9a2019-12-12 11:03:39 -060047 /**
48 * @brief Constructor
49 *
50 * @param[in] event - The sd_event object
51 * @param[in] dataIface - The DataInterface class
52 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060053 MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) :
54 HostInterface(event, dataIface)
55 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060056 char templ[] = "/tmp/cmdfifoXXXXXX";
57 std::filesystem::path dir = mkdtemp(templ);
58 _fifo = dir / "fifo";
Matt Spinlerf60ac272019-12-11 13:47:50 -060059 }
60
Matt Spinler5342d9a2019-12-12 11:03:39 -060061 /**
62 * @brief Destructor
63 */
Matt Spinlerf60ac272019-12-11 13:47:50 -060064 virtual ~MockHostInterface()
65 {
Matt Spinler5342d9a2019-12-12 11:03:39 -060066 std::filesystem::remove_all(_fifo.parent_path());
Matt Spinlerf60ac272019-12-11 13:47:50 -060067 }
68
69 MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override));
70
Matt Spinler5342d9a2019-12-12 11:03:39 -060071 /**
72 * @brief Cancels waiting for a command response
73 */
74 virtual void cancelCmd() override
75 {
76 _inProgress = false;
77 _source = nullptr;
78 }
79
80 /**
81 * @brief Returns the amount of time to wait before retrying after
82 * a failed send command.
83 *
84 * @return milliseconds - The amount of time to wait
85 */
86 virtual std::chrono::milliseconds getSendRetryDelay() const override
87 {
88 return std::chrono::milliseconds(2);
89 }
90
91 /**
92 * @brief Returns the amount of time to wait before retrying after
93 * a command receive.
94 *
95 * @return milliseconds - The amount of time to wait
96 */
97 virtual std::chrono::milliseconds getReceiveRetryDelay() const override
98 {
99 return std::chrono::milliseconds(2);
100 }
101
102 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600103 * @brief Returns the amount of time to wait before retrying if the
104 * host firmware's PEL storage was full and it can't store
105 * any more logs until it is freed up somehow.
106 *
107 * @return milliseconds - The amount of time to wait
108 */
109 virtual std::chrono::milliseconds getHostFullRetryDelay() const override
110 {
111 return std::chrono::milliseconds(20);
112 }
113
114 /**
Matt Spinler5342d9a2019-12-12 11:03:39 -0600115 * @brief Returns the number of commands processed
116 */
117 size_t numCmdsProcessed() const
118 {
119 return _cmdsProcessed;
120 }
121
122 /**
123 * @brief Writes the data passed in to the FIFO
124 *
125 * @param[in] hostResponse - use a 0 to indicate success
126 *
127 * @return CmdStatus - success or failure
128 */
129 CmdStatus send(uint8_t hostResponse)
130 {
131 // Create a FIFO once.
132 if (!std::filesystem::exists(_fifo))
133 {
134 if (mkfifo(_fifo.c_str(), 0622))
135 {
136 ADD_FAILURE() << "Failed mkfifo " << _fifo << strerror(errno);
137 exit(-1);
138 }
139 }
140
141 // Open it and register the reponse callback to
142 // be used on FD activity.
143 int fd = open(_fifo.c_str(), O_NONBLOCK | O_RDWR);
144 EXPECT_TRUE(fd >= 0) << "Unable to open FIFO";
145
146 auto callback = [this](sdeventplus::source::IO& source, int fd,
147 uint32_t events) {
148 this->receive(source, fd, events);
149 };
150
151 try
152 {
153 _source = std::make_unique<sdeventplus::source::IO>(
154 _event, fd, EPOLLIN,
155 std::bind(callback, std::placeholders::_1,
156 std::placeholders::_2, std::placeholders::_3));
157 }
158 catch (std::exception& e)
159 {
160 ADD_FAILURE() << "Event exception: " << e.what();
161 close(fd);
162 return CmdStatus::failure;
163 }
164
165 // Write the fake host reponse to the FIFO
166 auto bytesWritten = write(fd, &hostResponse, sizeof(hostResponse));
167 EXPECT_EQ(bytesWritten, sizeof(hostResponse));
168
169 _inProgress = true;
170
171 return CmdStatus::success;
172 }
173
Matt Spinlerf60ac272019-12-11 13:47:50 -0600174 protected:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600175 /**
176 * @brief Reads the data written to the fifo and then calls
177 * the subscriber's callback.
178 *
179 * Nonzero data indicates a command failure (for testing bad path).
180 *
181 * @param[in] source - The event source object
182 * @param[in] fd - The file descriptor used
183 * @param[in] events - The event bits
184 */
Matt Spinlerf60ac272019-12-11 13:47:50 -0600185 void receive(sdeventplus::source::IO& source, int fd,
186 uint32_t events) override
187 {
Matt Spinler5342d9a2019-12-12 11:03:39 -0600188 if (!(events & EPOLLIN))
189 {
190 return;
191 }
192
193 _inProgress = false;
194
195 int newFD = open(_fifo.c_str(), O_NONBLOCK | O_RDONLY);
196 ASSERT_TRUE(newFD >= 0) << "Failed to open FIFO";
197
198 // Read the host success/failure response from the FIFO.
199 uint8_t data;
200 auto bytesRead = read(newFD, &data, sizeof(data));
201 EXPECT_EQ(bytesRead, sizeof(data));
202
203 close(newFD);
204
205 ResponseStatus status = ResponseStatus::success;
206 if (data != 0)
207 {
208 status = ResponseStatus::failure;
209 }
210
211 if (_responseFunc)
212 {
213 (*_responseFunc)(status);
214 }
215
Matt Spinlerf60ac272019-12-11 13:47:50 -0600216 // Keep account of the number of commands responses for testing.
217 _cmdsProcessed++;
218 }
219
220 private:
Matt Spinler5342d9a2019-12-12 11:03:39 -0600221 /**
222 * @brief The event source for the fifo
223 */
224 std::unique_ptr<sdeventplus::source::IO> _source;
225
226 /**
227 * @brief the path to the fifo
228 */
229 std::filesystem::path _fifo;
230
231 /**
232 * @brief The number of commands processed
233 */
Matt Spinlerf60ac272019-12-11 13:47:50 -0600234 size_t _cmdsProcessed = 0;
Matt Spinler09d64002019-09-11 14:29:46 -0500235};
236
237} // namespace pels
238} // namespace openpower