xref: /openbmc/google-ipmi-sys/test/handler_unittest.cpp (revision 0aec7a3490c8d6b45344776c2a969fffdc101046)
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "errors.hpp"
16 #include "handler.hpp"
17 #include "handler_impl.hpp"
18 
19 #include <systemd/sd-bus.h>
20 
21 #include <nlohmann/json.hpp>
22 #include <sdbusplus/message.hpp>
23 #include <sdbusplus/test/sdbus_mock.hpp>
24 #include <stdplus/print.hpp>
25 
26 #include <charconv>
27 #include <filesystem>
28 #include <fstream>
29 #include <functional>
30 #include <string>
31 #include <tuple>
32 
33 #include <gtest/gtest.h>
34 
35 namespace google
36 {
37 namespace ipmi
38 {
39 
40 using testing::_;
41 using testing::Return;
42 
TEST(HandlerTest,EthCheckValidHappy)43 TEST(HandlerTest, EthCheckValidHappy)
44 {
45     Handler h;
46     std::tuple<std::uint8_t, std::string> result = h.getEthDetails("et");
47     EXPECT_EQ(12, std::get<0>(result));
48     EXPECT_STREQ("et", std::get<1>(result).c_str());
49 }
50 
TEST(HandlerTest,CableCheckIllegalPath)51 TEST(HandlerTest, CableCheckIllegalPath)
52 {
53     Handler h;
54     EXPECT_THROW(h.getRxPackets("eth0/../../"), IpmiException);
55 }
56 
TEST(HandlerTest,readNameFromConfigInstanceVariety)57 TEST(HandlerTest, readNameFromConfigInstanceVariety)
58 {
59     // Make sure it handles the failures and successes as we expect.
60     struct testCase
61     {
62         std::string type;
63         std::uint8_t instance;
64         std::string expectedName;
65     };
66 
67     std::vector<testCase> tests = {
68         {"cpu", 5, ""},
69         {"cpu", 3, "CPU2"},
70     };
71 
72     auto j2 = R"(
73       {
74         "cpu": [
75           {"instance": 1, "name": "CPU0"},
76           {"instance": 2, "name": "CPU1"},
77           {"instance": 3, "name": "CPU2"},
78           {"instance": 4, "name": "CPU3"}
79         ]
80       }
81     )"_json;
82 
83     for (const auto& test : tests)
84     {
85         EXPECT_STREQ(test.expectedName.c_str(),
86                      readNameFromConfig(test.type, test.instance, j2).c_str());
87     }
88 }
89 
90 // TODO: If we can test with phosphor-logging in the future, there are more
91 // failure cases.
92 
TEST(HandlerTest,getEntityNameWithNameNotFoundExcepts)93 TEST(HandlerTest, getEntityNameWithNameNotFoundExcepts)
94 {
95     const char* testFilename = "test.json";
96     std::string contents = R"({"cpu": [{"instance": 1, "name": "CPU0"}]})";
97     std::ofstream outputJson(testFilename);
98     outputJson << contents;
99     outputJson.flush();
100     outputJson.close();
101 
102     Handler h(testFilename);
103     EXPECT_THROW(h.getEntityName(0x03, 2), IpmiException);
104     (void)std::remove(testFilename);
105 }
106 
TEST(HandlerTest,getEntityNameWithNameFoundReturnsIt)107 TEST(HandlerTest, getEntityNameWithNameFoundReturnsIt)
108 {
109     const char* testFilename = "test.json";
110     std::string contents = R"({"cpu": [{"instance": 1, "name": "CPU0"}]})";
111     std::ofstream outputJson(testFilename);
112     outputJson << contents;
113     outputJson.flush();
114     outputJson.close();
115 
116     Handler h(testFilename);
117     EXPECT_STREQ("CPU0", h.getEntityName(0x03, 1).c_str());
118     (void)std::remove(testFilename);
119 }
120 
121 using ::testing::_;
122 using ::testing::AnyNumber;
123 using ::testing::ContainerEq;
124 using ::testing::DoAll;
125 using ::testing::ElementsAre;
126 using ::testing::Eq;
127 using ::testing::IsNull;
128 using ::testing::MatcherCast;
129 using ::testing::NotNull;
130 using ::testing::Pointee;
131 using ::testing::Return;
132 using ::testing::ReturnNull;
133 using ::testing::SafeMatcherCast;
134 using ::testing::SetArgPointee;
135 using ::testing::StrEq;
136 using ::testing::StrictMock;
137 using ::testing::StrNe;
138 using ::testing::WithArg;
139 
140 class MockDbusHandler : public Handler
141 {
142   public:
MockDbusHandler(sdbusplus::SdBusMock & mock,const std::string & config="")143     MockDbusHandler(sdbusplus::SdBusMock& mock,
144                     const std::string& config = "") :
145         Handler(config), mock_(&mock)
146     {}
147 
148   protected:
getDbus() const149     sdbusplus::bus_t getDbus() const override
150     {
151         return sdbusplus::get_mocked_new(
152             const_cast<sdbusplus::SdBusMock*>(mock_));
153     }
154 
155   private:
156     sdbusplus::SdBusMock* mock_;
157 };
158 
ACTION_TEMPLATE(AssignReadVal,HAS_1_TEMPLATE_PARAMS (typename,T),AND_1_VALUE_PARAMS (val))159 ACTION_TEMPLATE(AssignReadVal, HAS_1_TEMPLATE_PARAMS(typename, T),
160                 AND_1_VALUE_PARAMS(val))
161 {
162     *static_cast<T*>(arg2) = val;
163 }
164 
ACTION_P(TraceDbus,msg)165 ACTION_P(TraceDbus, msg)
166 {
167     stdplus::print(stderr, "{}\n", msg);
168 }
169 
ACTION_P(TraceDbus2,msg)170 ACTION_P(TraceDbus2, msg)
171 {
172     stdplus::print(stderr, "{}({:02x})\n", msg,
173                    *static_cast<const uint8_t*>(arg2));
174 }
175 
176 constexpr char object_path[] = "/com/google/customAccel/test/path";
177 constexpr char property_grpc[] = "com.google.custom_accel.gRPC";
178 constexpr char value_port[] = "Port";
179 constexpr uint32_t port = 5000;
180 
181 constexpr char SD_BUS_TYPE_BYTE_STR[] = {SD_BUS_TYPE_BYTE, '\0'};
182 
183 // Returns an object that looks like:
184 //     "/com/google/customAccel/test/path": {
185 //         "com.google.custom_accel.gRPC" : {
186 //             "Port" : {
187 //                 "type" : "u",
188 //                 "data" : 5000
189 //             }
190 //         }
191 //     }
ExpectGetManagedObjects(StrictMock<sdbusplus::SdBusMock> & mock,const char * obj_path=object_path)192 void ExpectGetManagedObjects(StrictMock<sdbusplus::SdBusMock>& mock,
193                              const char* obj_path = object_path)
194 {
195     ::testing::InSequence s;
196 
197     // These must be nullptr or sd_bus_message_unref will seg fault.
198     constexpr sd_bus_message* method = nullptr;
199     constexpr sd_bus_message* msg = nullptr;
200 
201     EXPECT_CALL(mock, sd_bus_message_new_method_call(
202                           _,         // sd_bus *bus,
203                           NotNull(), // sd_bus_message **m
204                           StrEq("com.google.custom_accel"), StrEq("/"),
205                           StrEq("org.freedesktop.DBus.ObjectManager"),
206                           StrEq("GetManagedObjects")))
207         .WillOnce(DoAll(SetArgPointee<1>(method), Return(0)));
208 
209     EXPECT_CALL(mock, sd_bus_call(_,           // sd_bus *bus,
210                                   method,      // sd_bus_message *m
211                                   _,           // uint64_t timeout
212                                   NotNull(),   // sd_bus_error *ret_error
213                                   NotNull()))  // sd_bus_message **reply
214         .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL),
215                         SetArgPointee<4>(msg), // reply
216                         Return(0)));
217 
218     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY,
219                                                      StrEq("{oa{sa{sv}}}")))
220         .WillOnce(Return(1));
221 
222     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0));
223 
224     EXPECT_CALL(mock, sd_bus_message_enter_container(
225                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("oa{sa{sv}}")))
226         .WillOnce(Return(1));
227 
228     EXPECT_CALL(mock, sd_bus_message_read_basic(msg, SD_BUS_TYPE_OBJECT_PATH,
229                                                 NotNull()))
230         .WillOnce(DoAll(AssignReadVal<const char*>(obj_path), Return(1)));
231 
232     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY,
233                                                      StrEq("{sa{sv}}")))
234         .WillOnce(Return(1));
235 
236     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0));
237 
238     EXPECT_CALL(mock, sd_bus_message_enter_container(
239                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sa{sv}")))
240         .WillOnce(Return(1));
241 
242     EXPECT_CALL(mock,
243                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull()))
244         .WillOnce(DoAll(AssignReadVal<const char*>(property_grpc), Return(1)));
245 
246     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY,
247                                                      StrEq("{sv}")))
248         .WillOnce(Return(1));
249 
250     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0));
251 
252     EXPECT_CALL(mock, sd_bus_message_enter_container(
253                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sv")))
254         .WillOnce(Return(1));
255 
256     EXPECT_CALL(mock,
257                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull()))
258         .WillOnce(DoAll(AssignReadVal<const char*>(value_port), Return(1)));
259 
260     EXPECT_CALL(
261         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u")))
262         .Times(AnyNumber())
263         .WillRepeatedly(Return(0));
264 
265     EXPECT_CALL(
266         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrEq("u")))
267         .WillOnce(Return(1));
268 
269     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_VARIANT,
270                                                      StrEq("u")))
271         .WillOnce(Return(1));
272 
273     EXPECT_CALL(mock,
274                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_UINT32, NotNull()))
275         .WillOnce(DoAll(AssignReadVal<uint32_t>(port), Return(0)));
276 
277     EXPECT_CALL(
278         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u")))
279         .Times(AnyNumber())
280         .WillRepeatedly(Return(0));
281 
282     EXPECT_CALL(mock, sd_bus_message_exit_container(msg))
283         .WillOnce(Return(1))
284         .WillOnce(Return(1));
285 
286     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1));
287 
288     EXPECT_CALL(mock, sd_bus_message_exit_container(msg))
289         .WillOnce(Return(1))
290         .WillOnce(Return(1));
291 
292     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1));
293 
294     EXPECT_CALL(mock, sd_bus_message_exit_container(msg))
295         .WillOnce(Return(1))
296         .WillOnce(Return(1));
297 
298     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1));
299 
300     EXPECT_CALL(mock, sd_bus_message_exit_container(msg)).WillOnce(Return(1));
301 }
302 
ExpectSdBusError(StrictMock<sdbusplus::SdBusMock> & mock,const std::string & service,const std::string & objPath,const std::string & interface,const std::string & function)303 void ExpectSdBusError(StrictMock<sdbusplus::SdBusMock>& mock,
304                       const std::string& service, const std::string& objPath,
305                       const std::string& interface, const std::string& function)
306 {
307     EXPECT_CALL(mock, sd_bus_message_new_method_call(
308                           _,         // sd_bus *bus,
309                           NotNull(), // sd_bus_message **m
310                           StrEq(service), StrEq(objPath), StrEq(interface),
311                           StrEq(function)))
312         .WillOnce(Return(-ENOTCONN));
313 }
314 
TEST(HandlerTest,accelOobDeviceCount_Success)315 TEST(HandlerTest, accelOobDeviceCount_Success)
316 {
317     StrictMock<sdbusplus::SdBusMock> mock;
318     MockDbusHandler h(mock);
319     ExpectGetManagedObjects(mock);
320     EXPECT_EQ(1, h.accelOobDeviceCount());
321 }
322 
TEST(HandlerTest,accelOobDeviceCount_Fail)323 TEST(HandlerTest, accelOobDeviceCount_Fail)
324 {
325     StrictMock<sdbusplus::SdBusMock> mock;
326     MockDbusHandler h(mock);
327     ExpectSdBusError(mock, "com.google.custom_accel", "/",
328                      "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
329     EXPECT_THROW(h.accelOobDeviceCount(), IpmiException);
330 }
331 
TEST(HandlerTest,accelOobDeviceName_Success)332 TEST(HandlerTest, accelOobDeviceName_Success)
333 {
334     StrictMock<sdbusplus::SdBusMock> mock;
335     MockDbusHandler h(mock);
336     ExpectGetManagedObjects(mock);
337     EXPECT_EQ(std::string("test/path"), h.accelOobDeviceName(0));
338 }
339 
TEST(HandlerTest,accelOobDeviceName_Fail)340 TEST(HandlerTest, accelOobDeviceName_Fail)
341 {
342     StrictMock<sdbusplus::SdBusMock> mock;
343     MockDbusHandler h(mock);
344     ExpectSdBusError(mock, "com.google.custom_accel", "/",
345                      "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
346     EXPECT_THROW(h.accelOobDeviceName(0), IpmiException);
347 }
348 
TEST(HandlerTest,accelOobDeviceName_OutOfRange)349 TEST(HandlerTest, accelOobDeviceName_OutOfRange)
350 {
351     StrictMock<sdbusplus::SdBusMock> mock;
352     MockDbusHandler h(mock);
353     ExpectGetManagedObjects(mock);
354     EXPECT_THROW(h.accelOobDeviceName(1), IpmiException);
355 }
356 
TEST(HandlerTest,accelOobDeviceName_InvalidName)357 TEST(HandlerTest, accelOobDeviceName_InvalidName)
358 {
359     constexpr char bad_object_path[] = "/com/google/customAccel2/bad/path";
360     StrictMock<sdbusplus::SdBusMock> mock;
361     MockDbusHandler h(mock);
362     ExpectGetManagedObjects(mock, bad_object_path);
363     EXPECT_THROW(h.accelOobDeviceName(0), IpmiException);
364 }
365 
366 constexpr uint8_t NUM_BYTES_RETURNED_EQ_NUM_BYTES = 0xff;
ExpectRead(StrictMock<sdbusplus::SdBusMock> & mock,uint64_t address,uint8_t num_bytes,uint64_t data,int sd_bus_call_return_value,uint8_t num_bytes_returned=NUM_BYTES_RETURNED_EQ_NUM_BYTES)367 void ExpectRead(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address,
368                 uint8_t num_bytes, uint64_t data, int sd_bus_call_return_value,
369                 uint8_t num_bytes_returned = NUM_BYTES_RETURNED_EQ_NUM_BYTES)
370 {
371     ::testing::InSequence s;
372 
373     // These must be nullptr or sd_bus_message_unref will seg fault.
374     constexpr sd_bus_message* method = nullptr;
375     constexpr sd_bus_message* msg = nullptr;
376 
377     EXPECT_CALL(mock, sd_bus_message_new_method_call(
378                           _,         // sd_bus *bus,
379                           NotNull(), // sd_bus_message **m
380                           StrEq("com.google.custom_accel"),
381                           StrEq("/com/google/customAccel/test/path"),
382                           StrEq("com.google.custom_accel.BAR"), StrEq("Read")))
383         .WillOnce(DoAll(SetArgPointee<1>(method), Return(0)));
384 
385     EXPECT_CALL(mock,
386                 sd_bus_message_append_basic(
387                     method, SD_BUS_TYPE_UINT64,
388                     MatcherCast<const void*>(SafeMatcherCast<const uint64_t*>(
389                         Pointee(Eq(address))))))
390         .WillOnce(Return(1));
391 
392     EXPECT_CALL(mock,
393                 sd_bus_message_append_basic(
394                     method, SD_BUS_TYPE_UINT64,
395                     MatcherCast<const void*>(SafeMatcherCast<const uint64_t*>(
396                         Pointee(Eq<uint64_t>(num_bytes))))))
397         .WillOnce(Return(1));
398 
399     EXPECT_CALL(mock, sd_bus_call(_,           // sd_bus *bus,
400                                   method,      // sd_bus_message *m
401                                   _,           // uint64_t timeout
402                                   NotNull(),   // sd_bus_error *ret_error
403                                   NotNull()))  // sd_bus_message **reply
404         .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL),
405                         SetArgPointee<4>(msg), // reply
406                         Return(sd_bus_call_return_value)));
407 
408     if (sd_bus_call_return_value >= 0)
409     {
410         if (num_bytes_returned == NUM_BYTES_RETURNED_EQ_NUM_BYTES)
411         {
412             num_bytes_returned = num_bytes;
413         }
414 
415         uint64_t updatedData = 0;
416         for (size_t i = 0; i < num_bytes_returned; ++i)
417         {
418             updatedData <<= 8;
419             updatedData += (i >= 8) ? 0 : (data >> (i * 8)) & 0xff;
420         }
421 
422         auto read_array_callback =
423             [updatedData, num_bytes_returned](sd_bus_message*, char,
424                                               const void** p, size_t* sz) {
425                 *p = &updatedData;
426                 *sz = num_bytes_returned;
427             };
428 
429         EXPECT_CALL(mock, sd_bus_message_read_array(nullptr, SD_BUS_TYPE_BYTE,
430                                                     testing::_, testing::_))
431             .WillOnce(DoAll(testing::Invoke(read_array_callback), Return(0)));
432     }
433 }
434 
TEST(HandlerTest,accelOobRead_Success)435 TEST(HandlerTest, accelOobRead_Success)
436 {
437     StrictMock<sdbusplus::SdBusMock> mock;
438     MockDbusHandler h(mock);
439 
440     constexpr uint64_t address = 0x123456789abcdef;
441     constexpr uint8_t num_bytes = sizeof(uint64_t);
442     constexpr int sd_bus_call_return_value = 1;
443     constexpr uint64_t data = 0x13579bdf02468ace;
444 
445     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value);
446     EXPECT_EQ(data, h.accelOobRead("test/path", address, num_bytes));
447 }
448 
TEST(HandlerTest,accelOobRead_Fail)449 TEST(HandlerTest, accelOobRead_Fail)
450 {
451     StrictMock<sdbusplus::SdBusMock> mock;
452     MockDbusHandler h(mock);
453 
454     constexpr uint64_t address = 0x123456789abcdef;
455     constexpr uint8_t num_bytes = sizeof(uint64_t);
456     constexpr int sd_bus_call_return_value = -ENOTCONN;
457     constexpr uint64_t data = 0x13579bdf02468ace;
458 
459     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value);
460     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes),
461                  IpmiException);
462 }
463 
TEST(HandlerTest,accelOobRead_TooFewBytesReturned)464 TEST(HandlerTest, accelOobRead_TooFewBytesReturned)
465 {
466     StrictMock<sdbusplus::SdBusMock> mock;
467     MockDbusHandler h(mock);
468 
469     constexpr uint64_t address = 0x123456789abcdef;
470     constexpr uint8_t num_bytes = sizeof(uint64_t);
471     constexpr int sd_bus_call_return_value = 1;
472     constexpr uint64_t data = 0x13579bdf02468ace;
473     constexpr uint8_t num_bytes_returned = num_bytes - 1;
474 
475     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value,
476                num_bytes_returned);
477     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes),
478                  IpmiException);
479 }
480 
TEST(HandlerTest,accelOobRead_TooManyBytesReturned)481 TEST(HandlerTest, accelOobRead_TooManyBytesReturned)
482 {
483     StrictMock<sdbusplus::SdBusMock> mock;
484     MockDbusHandler h(mock);
485 
486     constexpr uint64_t address = 0x123456789abcdef;
487     constexpr uint8_t num_bytes = sizeof(uint64_t);
488     constexpr int sd_bus_call_return_value = 1;
489     constexpr uint64_t data = 0x13579bdf02468ace;
490     constexpr uint8_t num_bytes_returned = sizeof(uint64_t) + 1;
491 
492     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value,
493                num_bytes_returned);
494     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes),
495                  IpmiException);
496 }
497 
on_array_append(sd_bus_message *,char,const void *,size_t)498 static int on_array_append(sd_bus_message*, char, const void*, size_t)
499 {
500     return 0;
501 }
502 
ExpectWrite(StrictMock<sdbusplus::SdBusMock> & mock,uint64_t address,uint8_t num_bytes,uint64_t,int sd_bus_call_return_value)503 void ExpectWrite(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address,
504                  uint8_t num_bytes, uint64_t, int sd_bus_call_return_value)
505 {
506     ::testing::InSequence s;
507 
508     // These must be nullptr or sd_bus_message_unref will seg fault.
509     constexpr sd_bus_message* method = nullptr;
510 
511     EXPECT_CALL(mock, sd_bus_message_new_method_call(
512                           _,         // sd_bus *bus,
513                           NotNull(), // sd_bus_message **m
514                           StrEq("com.google.custom_accel"),
515                           StrEq("/com/google/customAccel/test/path"),
516                           StrEq("com.google.custom_accel.BAR"), StrEq("Write")))
517         .WillOnce(DoAll(TraceDbus("sd_bus_message_new_method_call"),
518                         SetArgPointee<1>(method), Return(0)));
519 
520     EXPECT_CALL(mock,
521                 sd_bus_message_append_basic(
522                     method, SD_BUS_TYPE_UINT64,
523                     MatcherCast<const void*>(SafeMatcherCast<const uint64_t*>(
524                         Pointee(Eq(address))))))
525         .WillOnce(DoAll(TraceDbus("sd_bus_message_append_basic(address) -> 1"),
526                         Return(1)));
527 
528     EXPECT_CALL(
529         mock, sd_bus_message_append_array(nullptr, SD_BUS_TYPE_BYTE, testing::_,
530                                           num_bytes * sizeof(std::byte)))
531         .WillOnce(testing::Invoke(on_array_append));
532 
533     EXPECT_CALL(mock, sd_bus_call(_,         // sd_bus *bus,
534                                   method,    // sd_bus_message *m
535                                   _,         // uint64_t timeout
536                                   NotNull(), // sd_bus_error *ret_error
537                                   IsNull())) // sd_bus_message **reply
538         .WillOnce(DoAll(TraceDbus("sd_bus_call() -> ret_val"),
539                         SetArgPointee<3>(SD_BUS_ERROR_NULL),
540                         Return(sd_bus_call_return_value)));
541 }
542 
TEST(HandlerTest,accelOobWrite_Success)543 TEST(HandlerTest, accelOobWrite_Success)
544 {
545     StrictMock<sdbusplus::SdBusMock> mock;
546     MockDbusHandler h(mock);
547 
548     constexpr uint64_t address = 0x123456789abcdef;
549     constexpr uint8_t num_bytes = sizeof(uint64_t);
550     constexpr int sd_bus_call_return_value = 1;
551     constexpr uint64_t data = 0x13579bdf02468ace;
552 
553     ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value);
554     EXPECT_NO_THROW(h.accelOobWrite("test/path", address, num_bytes, data));
555 }
556 
TEST(HandlerTest,accelOobRead_TooManyBytesRequested)557 TEST(HandlerTest, accelOobRead_TooManyBytesRequested)
558 {
559     StrictMock<sdbusplus::SdBusMock> mock;
560     MockDbusHandler h(mock);
561 
562     constexpr uint64_t address = 0x123456789abcdef;
563     constexpr uint8_t num_bytes = sizeof(uint64_t) + 1;
564     constexpr uint64_t data = 0x13579bdf02468ace;
565 
566     EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data),
567                  IpmiException);
568 }
569 
TEST(HandlerTest,accelOobWrite_Fail)570 TEST(HandlerTest, accelOobWrite_Fail)
571 {
572     StrictMock<sdbusplus::SdBusMock> mock;
573     MockDbusHandler h(mock);
574 
575     constexpr uint64_t address = 0x123456789abcdef;
576     constexpr uint8_t num_bytes = sizeof(uint64_t);
577     constexpr int sd_bus_call_return_value = -ENOTCONN;
578     constexpr uint64_t data = 0x13579bdf02468ace;
579 
580     ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value);
581     EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data),
582                  IpmiException);
583 }
584 
TEST(HandlerTest,PcieBifurcation)585 TEST(HandlerTest, PcieBifurcation)
586 {
587     const std::string& testJson = "/tmp/test-json";
588     auto j = R"(
589         {
590             "1": [ 1, 3 ],
591             "3": [ 3, 6 ],
592             "4": [ 3, 4, 1 ],
593             "6": [ 8 ]
594         }
595     )"_json;
596 
597     std::ofstream bifurcationJson(testJson);
598     bifurcationJson << j.dump();
599     bifurcationJson.flush();
600     bifurcationJson.close();
601 
602     BifurcationStatic bifurcationHelper(testJson);
603     Handler h(std::ref(bifurcationHelper));
604 
605     std::unordered_map<uint8_t, std::vector<uint8_t>> expectedMapping = {
606         {1, {1, 3}}, {3, {3, 6}}, {4, {3, 4, 1}}, {6, {8}}};
607     std::vector<uint8_t> invalidBus = {0, 2, 5, 7};
608 
609     for (const auto& [bus, output] : expectedMapping)
610     {
611         EXPECT_THAT(h.pcieBifurcation(bus), ContainerEq(output));
612     }
613 
614     for (const auto& bus : invalidBus)
615     {
616         EXPECT_TRUE(h.pcieBifurcation(bus).empty());
617     }
618 
619     std::filesystem::remove(testJson.data());
620     bifurcationHelper = BifurcationStatic(testJson);
621     Handler h2(std::ref(bifurcationHelper));
622     for (uint8_t i = 0; i < 8; ++i)
623     {
624         auto bifurcation = h2.pcieBifurcation(i);
625         EXPECT_TRUE(bifurcation.empty());
626     }
627 }
628 
TEST(HandlerTest,BmInstanceFailCase)629 TEST(HandlerTest, BmInstanceFailCase)
630 {
631     StrictMock<sdbusplus::SdBusMock> mock;
632     MockDbusHandler h(mock);
633 
634     // Invalid enum
635     EXPECT_THROW(h.getBMInstanceProperty(0x07), IpmiException);
636 
637     // Valid enum but no path exists
638     EXPECT_THROW(h.getBMInstanceProperty(0x00), IpmiException);
639 }
640 
641 // TODO: Add checks for other functions of handler.
642 
643 } // namespace ipmi
644 } // namespace google
645