xref: /openbmc/phosphor-logging/test/openpower-pels/mocks.hpp (revision 784b02e7081099d8184df6fe46404937861c504e)
1 #include "extensions/openpower-pels/data_interface.hpp"
2 #include "extensions/openpower-pels/host_interface.hpp"
3 #include "extensions/openpower-pels/journal.hpp"
4 
5 #include <fcntl.h>
6 
7 #include <sdeventplus/source/io.hpp>
8 
9 #include <filesystem>
10 
11 #include <gmock/gmock.h>
12 
13 namespace openpower
14 {
15 namespace pels
16 {
17 
18 class MockDataInterface : public DataInterfaceBase
19 {
20   public:
21     MockDataInterface()
22     {
23         ON_CALL(*this, checkDumpStatus)
24             .WillByDefault(
25                 ::testing::Return(std::vector<bool>({false, false, false})));
26     }
27 
28     MOCK_METHOD(std::string, getMachineTypeModel, (), (const override));
29     MOCK_METHOD(std::string, getMachineSerialNumber, (), (const override));
30     MOCK_METHOD(std::string, getServerFWVersion, (), (const override));
31     MOCK_METHOD(std::string, getBMCFWVersion, (), (const override));
32     MOCK_METHOD(std::string, getBMCFWVersionID, (), (const override));
33     MOCK_METHOD(bool, getHostPELEnablement, (), (const override));
34     MOCK_METHOD(std::string, getBMCState, (), (const override));
35     MOCK_METHOD(std::string, getChassisState, (), (const override));
36     MOCK_METHOD(std::string, getHostState, (), (const override));
37     MOCK_METHOD(std::string, getMotherboardCCIN, (), (const override));
38     MOCK_METHOD(void, getHWCalloutFields,
39                 (const std::string&, std::string&, std::string&, std::string&),
40                 (const override));
41     MOCK_METHOD(std::string, getLocationCode, (const std::string&),
42                 (const override));
43     MOCK_METHOD(std::vector<std::string>, getSystemNames, (), (const override));
44     MOCK_METHOD(std::string, expandLocationCode, (const std::string&, uint16_t),
45                 (const override));
46     MOCK_METHOD(std::vector<std::string>, getInventoryFromLocCode,
47                 (const std::string&, uint16_t, bool), (const override));
48     MOCK_METHOD(void, assertLEDGroup, (const std::string&, bool),
49                 (const override));
50     MOCK_METHOD(void, setFunctional, (const std::string&, bool),
51                 (const override));
52     MOCK_METHOD(std::vector<uint8_t>, getSystemIMKeyword, (), (const override));
53     MOCK_METHOD(bool, getQuiesceOnError, (), (const override));
54     MOCK_METHOD(void, setCriticalAssociation, (const std::string&),
55                 (const override));
56     MOCK_METHOD(std::vector<bool>, checkDumpStatus,
57                 (const std::vector<std::string>&), (const override));
58     MOCK_METHOD(std::string, getBootState, (), (const override));
59     MOCK_METHOD(void, createGuardRecord,
60                 (const std::vector<uint8_t>&, const std::string&,
61                  const std::string&),
62                 (const override));
63     MOCK_METHOD(void, createProgressSRC,
64                 (const uint64_t&, const std::vector<uint8_t>&),
65                 (const override));
66     MOCK_METHOD(std::vector<uint32_t>, getLogIDWithHwIsolation, (),
67                 (const override));
68     MOCK_METHOD(std::vector<uint8_t>, getRawProgressSRC, (), (const override));
69 
70     void changeHostState(bool newState)
71     {
72         setHostUp(newState);
73     }
74 
75     void setHMCManaged(bool managed)
76     {
77         _hmcManaged = managed;
78     }
79 };
80 
81 /**
82  * @brief The mock HostInterface class
83  *
84  * This replaces the PLDM calls with a FIFO for the asynchronous
85  * responses.
86  */
87 class MockHostInterface : public HostInterface
88 {
89   public:
90     /**
91      * @brief Constructor
92      *
93      * @param[in] event - The sd_event object
94      * @param[in] dataIface - The DataInterface class
95      */
96     MockHostInterface(sd_event* event, DataInterfaceBase& dataIface) :
97         HostInterface(event, dataIface)
98     {
99         char templ[] = "/tmp/cmdfifoXXXXXX";
100         std::filesystem::path dir = mkdtemp(templ);
101         _fifo = dir / "fifo";
102     }
103 
104     /**
105      * @brief Destructor
106      */
107     virtual ~MockHostInterface()
108     {
109         std::filesystem::remove_all(_fifo.parent_path());
110     }
111 
112     MOCK_METHOD(CmdStatus, sendNewLogCmd, (uint32_t, uint32_t), (override));
113 
114     /**
115      * @brief Cancels waiting for a command response
116      */
117     virtual void cancelCmd() override
118     {
119         _inProgress = false;
120         _source = nullptr;
121     }
122 
123     /**
124      * @brief Returns the amount of time to wait before retrying after
125      *        a failed send command.
126      *
127      * @return milliseconds - The amount of time to wait
128      */
129     virtual std::chrono::milliseconds getSendRetryDelay() const override
130     {
131         return std::chrono::milliseconds(2);
132     }
133 
134     /**
135      * @brief Returns the amount of time to wait before retrying after
136      *        a command receive.
137      *
138      * @return milliseconds - The amount of time to wait
139      */
140     virtual std::chrono::milliseconds getReceiveRetryDelay() const override
141     {
142         return std::chrono::milliseconds(2);
143     }
144 
145     /**
146      * @brief Returns the amount of time to wait before retrying if the
147      *        host firmware's PEL storage was full and it can't store
148      *        any more logs until it is freed up somehow.
149      *
150      * @return milliseconds - The amount of time to wait
151      */
152     virtual std::chrono::milliseconds getHostFullRetryDelay() const override
153     {
154         return std::chrono::milliseconds(400);
155     }
156 
157     /**
158      * @brief Returns the amount of time to wait after the host is up
159      *        before sending commands.
160      *
161      * @return milliseconds - The amount of time to wait
162      */
163     virtual std::chrono::milliseconds getHostUpDelay() const override
164     {
165         return std::chrono::milliseconds(0);
166     }
167 
168     /**
169      * @brief Returns the number of commands processed
170      */
171     size_t numCmdsProcessed() const
172     {
173         return _cmdsProcessed;
174     }
175 
176     /**
177      * @brief Writes the data passed in to the FIFO
178      *
179      * @param[in] hostResponse - use a 0 to indicate success
180      *
181      * @return CmdStatus - success or failure
182      */
183     CmdStatus send(uint8_t hostResponse)
184     {
185         // Create a FIFO once.
186         if (!std::filesystem::exists(_fifo))
187         {
188             if (mkfifo(_fifo.c_str(), 0622))
189             {
190                 ADD_FAILURE() << "Failed mkfifo " << _fifo << strerror(errno);
191                 exit(-1);
192             }
193         }
194 
195         // Open it and register the reponse callback to
196         // be used on FD activity.
197         int fd = open(_fifo.c_str(), O_NONBLOCK | O_RDWR);
198         EXPECT_TRUE(fd >= 0) << "Unable to open FIFO";
199 
200         auto callback =
201             [this](sdeventplus::source::IO& source, int fd, uint32_t events) {
202             this->receive(source, fd, events);
203         };
204 
205         try
206         {
207             _source = std::make_unique<sdeventplus::source::IO>(
208                 _event, fd, EPOLLIN,
209                 std::bind(callback, std::placeholders::_1,
210                           std::placeholders::_2, std::placeholders::_3));
211         }
212         catch (const std::exception& e)
213         {
214             ADD_FAILURE() << "Event exception: " << e.what();
215             close(fd);
216             return CmdStatus::failure;
217         }
218 
219         // Write the fake host reponse to the FIFO
220         auto bytesWritten = write(fd, &hostResponse, sizeof(hostResponse));
221         EXPECT_EQ(bytesWritten, sizeof(hostResponse));
222 
223         _inProgress = true;
224 
225         return CmdStatus::success;
226     }
227 
228   protected:
229     /**
230      * @brief Reads the data written to the fifo and then calls
231      *        the subscriber's callback.
232      *
233      * Nonzero data indicates a command failure (for testing bad path).
234      *
235      * @param[in] source - The event source object
236      * @param[in] fd - The file descriptor used
237      * @param[in] events - The event bits
238      */
239     void receive(sdeventplus::source::IO& /*source*/, int /*fd*/,
240                  uint32_t events) override
241     {
242         if (!(events & EPOLLIN))
243         {
244             return;
245         }
246 
247         _inProgress = false;
248 
249         int newFD = open(_fifo.c_str(), O_NONBLOCK | O_RDONLY);
250         ASSERT_TRUE(newFD >= 0) << "Failed to open FIFO";
251 
252         // Read the host success/failure response from the FIFO.
253         uint8_t data;
254         auto bytesRead = read(newFD, &data, sizeof(data));
255         EXPECT_EQ(bytesRead, sizeof(data));
256 
257         close(newFD);
258 
259         ResponseStatus status = ResponseStatus::success;
260         if (data != 0)
261         {
262             status = ResponseStatus::failure;
263         }
264 
265         callResponseFunc(status);
266 
267         // Keep account of the number of commands responses for testing.
268         _cmdsProcessed++;
269     }
270 
271   private:
272     /**
273      * @brief The event source for the fifo
274      */
275     std::unique_ptr<sdeventplus::source::IO> _source;
276 
277     /**
278      * @brief the path to the fifo
279      */
280     std::filesystem::path _fifo;
281 
282     /**
283      * @brief The number of commands processed
284      */
285     size_t _cmdsProcessed = 0;
286 };
287 
288 class MockJournal : public JournalBase
289 {
290   public:
291     MockJournal() {}
292 
293     MOCK_METHOD(std::vector<std::string>, getMessages,
294                 (const std::string&, size_t), (const override));
295 
296     MOCK_METHOD(void, sync, (), (const override));
297 };
298 
299 } // namespace pels
300 } // namespace openpower
301