| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 1 | // Copyright 2022 Google LLC | 
| Willy Tu | a2056e9 | 2021-10-10 13:36:16 -0700 | [diff] [blame] | 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 |  | 
| Patrick Venture | d2037c6 | 2019-03-15 10:29:47 -0700 | [diff] [blame] | 15 | #include "errors.hpp" | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 16 | #include "handler.hpp" | 
| Patrick Venture | c87de55 | 2020-05-20 20:25:39 -0700 | [diff] [blame] | 17 | #include "handler_impl.hpp" | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 18 |  | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 19 | #include <systemd/sd-bus.h> | 
 | 20 |  | 
| Patrick Williams | 444b5ea | 2023-05-19 13:56:42 -0500 | [diff] [blame] | 21 | #include <nlohmann/json.hpp> | 
 | 22 | #include <sdbusplus/message.hpp> | 
 | 23 | #include <sdbusplus/test/sdbus_mock.hpp> | 
| Michael Shen | 8d61853 | 2023-10-25 09:14:07 +0000 | [diff] [blame^] | 24 | #include <stdplus/print.hpp> | 
| Patrick Williams | 444b5ea | 2023-05-19 13:56:42 -0500 | [diff] [blame] | 25 |  | 
| Willy Tu | 6c71b0f | 2021-10-10 13:34:41 -0700 | [diff] [blame] | 26 | #include <charconv> | 
 | 27 | #include <filesystem> | 
| Patrick Venture | ab65000 | 2019-03-16 09:08:47 -0700 | [diff] [blame] | 28 | #include <fstream> | 
| Willy Tu | 6c71b0f | 2021-10-10 13:34:41 -0700 | [diff] [blame] | 29 | #include <functional> | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 30 | #include <string> | 
 | 31 | #include <tuple> | 
 | 32 |  | 
 | 33 | #include <gtest/gtest.h> | 
 | 34 |  | 
 | 35 | namespace google | 
 | 36 | { | 
 | 37 | namespace ipmi | 
 | 38 | { | 
 | 39 |  | 
| Willy Tu | 6c71b0f | 2021-10-10 13:34:41 -0700 | [diff] [blame] | 40 | using testing::_; | 
 | 41 | using testing::Return; | 
 | 42 |  | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 43 | TEST(HandlerTest, EthCheckValidHappy) | 
 | 44 | { | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 45 |     Handler h; | 
| William A. Kennington III | b69209b | 2021-07-13 13:22:24 -0700 | [diff] [blame] | 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()); | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 49 | } | 
 | 50 |  | 
| Patrick Venture | d2037c6 | 2019-03-15 10:29:47 -0700 | [diff] [blame] | 51 | TEST(HandlerTest, CableCheckIllegalPath) | 
 | 52 | { | 
 | 53 |     Handler h; | 
 | 54 |     EXPECT_THROW(h.getRxPackets("eth0/../../"), IpmiException); | 
 | 55 | } | 
 | 56 |  | 
| Patrick Venture | ab65000 | 2019-03-16 09:08:47 -0700 | [diff] [blame] | 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 |  | 
 | 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 |  | 
 | 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 |  | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 121 | using ::testing::_; | 
 | 122 | using ::testing::AnyNumber; | 
| Willy Tu | 6c71b0f | 2021-10-10 13:34:41 -0700 | [diff] [blame] | 123 | using ::testing::ContainerEq; | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 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: | 
 | 143 |     MockDbusHandler(sdbusplus::SdBusMock& mock, | 
 | 144 |                     const std::string& config = "") : | 
 | 145 |         Handler(config), | 
 | 146 |         mock_(&mock) | 
| Patrick Williams | 444b5ea | 2023-05-19 13:56:42 -0500 | [diff] [blame] | 147 |     {} | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 148 |  | 
 | 149 |   protected: | 
| Patrick Williams | 6537122 | 2023-05-19 02:31:40 -0500 | [diff] [blame] | 150 |     sdbusplus::bus_t getDbus() const override | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 151 |     { | 
 | 152 |         return sdbusplus::get_mocked_new( | 
 | 153 |             const_cast<sdbusplus::SdBusMock*>(mock_)); | 
 | 154 |     } | 
 | 155 |  | 
 | 156 |   private: | 
 | 157 |     sdbusplus::SdBusMock* mock_; | 
 | 158 | }; | 
 | 159 |  | 
 | 160 | ACTION_TEMPLATE(AssignReadVal, HAS_1_TEMPLATE_PARAMS(typename, T), | 
 | 161 |                 AND_1_VALUE_PARAMS(val)) | 
 | 162 | { | 
 | 163 |     *static_cast<T*>(arg2) = val; | 
 | 164 | } | 
 | 165 |  | 
 | 166 | ACTION_P(TraceDbus, msg) | 
 | 167 | { | 
| Michael Shen | 8d61853 | 2023-10-25 09:14:07 +0000 | [diff] [blame^] | 168 |     stdplus::print(stderr, "{}\n", msg); | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 169 | } | 
 | 170 |  | 
 | 171 | ACTION_P(TraceDbus2, msg) | 
 | 172 | { | 
| Michael Shen | 8d61853 | 2023-10-25 09:14:07 +0000 | [diff] [blame^] | 173 |     stdplus::print(stderr, "{}({:02x})\n", msg, | 
 | 174 |                    *static_cast<const uint8_t*>(arg2)); | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 175 | } | 
 | 176 |  | 
 | 177 | constexpr char object_path[] = "/com/google/customAccel/test/path"; | 
 | 178 | constexpr char property_grpc[] = "com.google.custom_accel.gRPC"; | 
 | 179 | constexpr char value_port[] = "Port"; | 
 | 180 | constexpr uint32_t port = 5000; | 
 | 181 |  | 
 | 182 | constexpr char SD_BUS_TYPE_BYTE_STR[] = {SD_BUS_TYPE_BYTE, '\0'}; | 
 | 183 |  | 
 | 184 | // Returns an object that looks like: | 
 | 185 | //     "/com/google/customAccel/test/path": { | 
 | 186 | //         "com.google.custom_accel.gRPC" : { | 
 | 187 | //             "Port" : { | 
 | 188 | //                 "type" : "u", | 
 | 189 | //                 "data" : 5000 | 
 | 190 | //             } | 
 | 191 | //         } | 
 | 192 | //     } | 
 | 193 | void ExpectGetManagedObjects(StrictMock<sdbusplus::SdBusMock>& mock, | 
 | 194 |                              const char* obj_path = object_path) | 
 | 195 | { | 
 | 196 |     ::testing::InSequence s; | 
 | 197 |  | 
 | 198 |     // These must be nullptr or sd_bus_message_unref will seg fault. | 
 | 199 |     constexpr sd_bus_message* method = nullptr; | 
 | 200 |     constexpr sd_bus_message* msg = nullptr; | 
 | 201 |  | 
 | 202 |     EXPECT_CALL(mock, sd_bus_message_new_method_call( | 
 | 203 |                           _,         // sd_bus *bus, | 
 | 204 |                           NotNull(), // sd_bus_message **m | 
 | 205 |                           StrEq("com.google.custom_accel"), StrEq("/"), | 
 | 206 |                           StrEq("org.freedesktop.DBus.ObjectManager"), | 
 | 207 |                           StrEq("GetManagedObjects"))) | 
 | 208 |         .WillOnce(DoAll(SetArgPointee<1>(method), Return(0))); | 
 | 209 |  | 
| Willy Tu | 1209ccc | 2023-05-19 00:49:51 -0700 | [diff] [blame] | 210 |     EXPECT_CALL(mock, sd_bus_call(_,           // sd_bus *bus, | 
 | 211 |                                   method,      // sd_bus_message *m | 
 | 212 |                                   _,           // uint64_t timeout | 
 | 213 |                                   NotNull(),   // sd_bus_error *ret_error | 
 | 214 |                                   NotNull()))  // sd_bus_message **reply | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 215 |         .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL), | 
 | 216 |                         SetArgPointee<4>(msg), // reply | 
 | 217 |                         Return(0))); | 
 | 218 |  | 
 | 219 |     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, | 
 | 220 |                                                      StrEq("{oa{sa{sv}}}"))) | 
 | 221 |         .WillOnce(Return(1)); | 
 | 222 |  | 
 | 223 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); | 
 | 224 |  | 
 | 225 |     EXPECT_CALL(mock, sd_bus_message_enter_container( | 
 | 226 |                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("oa{sa{sv}}"))) | 
 | 227 |         .WillOnce(Return(1)); | 
 | 228 |  | 
 | 229 |     EXPECT_CALL(mock, sd_bus_message_read_basic(msg, SD_BUS_TYPE_OBJECT_PATH, | 
 | 230 |                                                 NotNull())) | 
 | 231 |         .WillOnce(DoAll(AssignReadVal<const char*>(obj_path), Return(1))); | 
 | 232 |  | 
 | 233 |     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, | 
 | 234 |                                                      StrEq("{sa{sv}}"))) | 
 | 235 |         .WillOnce(Return(1)); | 
 | 236 |  | 
 | 237 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); | 
 | 238 |  | 
 | 239 |     EXPECT_CALL(mock, sd_bus_message_enter_container( | 
 | 240 |                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sa{sv}"))) | 
 | 241 |         .WillOnce(Return(1)); | 
 | 242 |  | 
 | 243 |     EXPECT_CALL(mock, | 
 | 244 |                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull())) | 
 | 245 |         .WillOnce(DoAll(AssignReadVal<const char*>(property_grpc), Return(1))); | 
 | 246 |  | 
 | 247 |     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, | 
 | 248 |                                                      StrEq("{sv}"))) | 
 | 249 |         .WillOnce(Return(1)); | 
 | 250 |  | 
 | 251 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(0)); | 
 | 252 |  | 
 | 253 |     EXPECT_CALL(mock, sd_bus_message_enter_container( | 
 | 254 |                           msg, SD_BUS_TYPE_DICT_ENTRY, StrEq("sv"))) | 
 | 255 |         .WillOnce(Return(1)); | 
 | 256 |  | 
 | 257 |     EXPECT_CALL(mock, | 
 | 258 |                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, NotNull())) | 
 | 259 |         .WillOnce(DoAll(AssignReadVal<const char*>(value_port), Return(1))); | 
 | 260 |  | 
 | 261 |     EXPECT_CALL( | 
 | 262 |         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u"))) | 
 | 263 |         .Times(AnyNumber()) | 
 | 264 |         .WillRepeatedly(Return(0)); | 
 | 265 |  | 
 | 266 |     EXPECT_CALL( | 
 | 267 |         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrEq("u"))) | 
 | 268 |         .WillOnce(Return(1)); | 
 | 269 |  | 
 | 270 |     EXPECT_CALL(mock, sd_bus_message_enter_container(msg, SD_BUS_TYPE_VARIANT, | 
 | 271 |                                                      StrEq("u"))) | 
 | 272 |         .WillOnce(Return(1)); | 
 | 273 |  | 
 | 274 |     EXPECT_CALL(mock, | 
 | 275 |                 sd_bus_message_read_basic(msg, SD_BUS_TYPE_UINT32, NotNull())) | 
 | 276 |         .WillOnce(DoAll(AssignReadVal<uint32_t>(port), Return(0))); | 
 | 277 |  | 
 | 278 |     EXPECT_CALL( | 
 | 279 |         mock, sd_bus_message_verify_type(msg, SD_BUS_TYPE_VARIANT, StrNe("u"))) | 
 | 280 |         .Times(AnyNumber()) | 
 | 281 |         .WillRepeatedly(Return(0)); | 
 | 282 |  | 
 | 283 |     EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) | 
 | 284 |         .WillOnce(Return(1)) | 
 | 285 |         .WillOnce(Return(1)); | 
 | 286 |  | 
 | 287 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); | 
 | 288 |  | 
 | 289 |     EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) | 
 | 290 |         .WillOnce(Return(1)) | 
 | 291 |         .WillOnce(Return(1)); | 
 | 292 |  | 
 | 293 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); | 
 | 294 |  | 
 | 295 |     EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) | 
 | 296 |         .WillOnce(Return(1)) | 
 | 297 |         .WillOnce(Return(1)); | 
 | 298 |  | 
 | 299 |     EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); | 
 | 300 |  | 
 | 301 |     EXPECT_CALL(mock, sd_bus_message_exit_container(msg)).WillOnce(Return(1)); | 
 | 302 | } | 
 | 303 |  | 
| Michael Shen | 0e928ac | 2022-06-20 05:21:52 +0000 | [diff] [blame] | 304 | void ExpectSdBusError(StrictMock<sdbusplus::SdBusMock>& mock, | 
 | 305 |                       const std::string& service, const std::string& objPath, | 
 | 306 |                       const std::string& interface, const std::string& function) | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 307 | { | 
| Michael Shen | 0e928ac | 2022-06-20 05:21:52 +0000 | [diff] [blame] | 308 |     EXPECT_CALL( | 
 | 309 |         mock, sd_bus_message_new_method_call(_,         // sd_bus *bus, | 
 | 310 |                                              NotNull(), // sd_bus_message **m | 
 | 311 |                                              StrEq(service), StrEq(objPath), | 
 | 312 |                                              StrEq(interface), StrEq(function))) | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 313 |         .WillOnce(Return(-ENOTCONN)); | 
 | 314 | } | 
 | 315 |  | 
 | 316 | TEST(HandlerTest, accelOobDeviceCount_Success) | 
 | 317 | { | 
 | 318 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 319 |     MockDbusHandler h(mock); | 
 | 320 |     ExpectGetManagedObjects(mock); | 
 | 321 |     EXPECT_EQ(1, h.accelOobDeviceCount()); | 
 | 322 | } | 
 | 323 |  | 
 | 324 | TEST(HandlerTest, accelOobDeviceCount_Fail) | 
 | 325 | { | 
 | 326 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 327 |     MockDbusHandler h(mock); | 
| Michael Shen | 0e928ac | 2022-06-20 05:21:52 +0000 | [diff] [blame] | 328 |     ExpectSdBusError(mock, "com.google.custom_accel", "/", | 
 | 329 |                      "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 330 |     EXPECT_THROW(h.accelOobDeviceCount(), IpmiException); | 
 | 331 | } | 
 | 332 |  | 
 | 333 | TEST(HandlerTest, accelOobDeviceName_Success) | 
 | 334 | { | 
 | 335 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 336 |     MockDbusHandler h(mock); | 
 | 337 |     ExpectGetManagedObjects(mock); | 
 | 338 |     EXPECT_EQ(std::string("test/path"), h.accelOobDeviceName(0)); | 
 | 339 | } | 
 | 340 |  | 
 | 341 | TEST(HandlerTest, accelOobDeviceName_Fail) | 
 | 342 | { | 
 | 343 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 344 |     MockDbusHandler h(mock); | 
| Michael Shen | 0e928ac | 2022-06-20 05:21:52 +0000 | [diff] [blame] | 345 |     ExpectSdBusError(mock, "com.google.custom_accel", "/", | 
 | 346 |                      "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 347 |     EXPECT_THROW(h.accelOobDeviceName(0), IpmiException); | 
 | 348 | } | 
 | 349 |  | 
 | 350 | TEST(HandlerTest, accelOobDeviceName_OutOfRange) | 
 | 351 | { | 
 | 352 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 353 |     MockDbusHandler h(mock); | 
 | 354 |     ExpectGetManagedObjects(mock); | 
 | 355 |     EXPECT_THROW(h.accelOobDeviceName(1), IpmiException); | 
 | 356 | } | 
 | 357 |  | 
 | 358 | TEST(HandlerTest, accelOobDeviceName_InvalidName) | 
 | 359 | { | 
 | 360 |     constexpr char bad_object_path[] = "/com/google/customAccel2/bad/path"; | 
 | 361 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 362 |     MockDbusHandler h(mock); | 
 | 363 |     ExpectGetManagedObjects(mock, bad_object_path); | 
 | 364 |     EXPECT_THROW(h.accelOobDeviceName(0), IpmiException); | 
 | 365 | } | 
 | 366 |  | 
 | 367 | constexpr uint8_t NUM_BYTES_RETURNED_EQ_NUM_BYTES = 0xff; | 
 | 368 | void ExpectRead(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address, | 
 | 369 |                 uint8_t num_bytes, uint64_t data, int sd_bus_call_return_value, | 
 | 370 |                 uint8_t num_bytes_returned = NUM_BYTES_RETURNED_EQ_NUM_BYTES) | 
 | 371 | { | 
 | 372 |     ::testing::InSequence s; | 
 | 373 |  | 
 | 374 |     // These must be nullptr or sd_bus_message_unref will seg fault. | 
 | 375 |     constexpr sd_bus_message* method = nullptr; | 
 | 376 |     constexpr sd_bus_message* msg = nullptr; | 
 | 377 |  | 
 | 378 |     EXPECT_CALL(mock, sd_bus_message_new_method_call( | 
 | 379 |                           _,         // sd_bus *bus, | 
 | 380 |                           NotNull(), // sd_bus_message **m | 
 | 381 |                           StrEq("com.google.custom_accel"), | 
 | 382 |                           StrEq("/com/google/customAccel/test/path"), | 
 | 383 |                           StrEq("com.google.custom_accel.BAR"), StrEq("Read"))) | 
 | 384 |         .WillOnce(DoAll(SetArgPointee<1>(method), Return(0))); | 
 | 385 |  | 
 | 386 |     EXPECT_CALL( | 
 | 387 |         mock, sd_bus_message_append_basic( | 
 | 388 |                   method, SD_BUS_TYPE_UINT64, | 
 | 389 |                   MatcherCast<const void*>( | 
 | 390 |                       SafeMatcherCast<const uint64_t*>(Pointee(Eq(address)))))) | 
 | 391 |         .WillOnce(Return(1)); | 
 | 392 |  | 
 | 393 |     EXPECT_CALL(mock, | 
 | 394 |                 sd_bus_message_append_basic( | 
 | 395 |                     method, SD_BUS_TYPE_UINT64, | 
 | 396 |                     MatcherCast<const void*>(SafeMatcherCast<const uint64_t*>( | 
 | 397 |                         Pointee(Eq<uint64_t>(num_bytes)))))) | 
 | 398 |         .WillOnce(Return(1)); | 
 | 399 |  | 
| Willy Tu | 1209ccc | 2023-05-19 00:49:51 -0700 | [diff] [blame] | 400 |     EXPECT_CALL(mock, sd_bus_call(_,           // sd_bus *bus, | 
 | 401 |                                   method,      // sd_bus_message *m | 
 | 402 |                                   _,           // uint64_t timeout | 
 | 403 |                                   NotNull(),   // sd_bus_error *ret_error | 
 | 404 |                                   NotNull()))  // sd_bus_message **reply | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 405 |         .WillOnce(DoAll(SetArgPointee<3>(SD_BUS_ERROR_NULL), | 
 | 406 |                         SetArgPointee<4>(msg), // reply | 
 | 407 |                         Return(sd_bus_call_return_value))); | 
 | 408 |  | 
 | 409 |     if (sd_bus_call_return_value >= 0) | 
 | 410 |     { | 
 | 411 |         EXPECT_CALL(mock, | 
 | 412 |                     sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, | 
 | 413 |                                                    StrEq(SD_BUS_TYPE_BYTE_STR))) | 
 | 414 |             .WillOnce(Return(1)); | 
 | 415 |  | 
 | 416 |         if (num_bytes_returned == NUM_BYTES_RETURNED_EQ_NUM_BYTES) | 
 | 417 |         { | 
 | 418 |             num_bytes_returned = num_bytes; | 
 | 419 |         } | 
 | 420 |         for (auto i = num_bytes_returned - 1; i >= 0; --i) | 
 | 421 |         { | 
 | 422 |             EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)) | 
 | 423 |                 .WillOnce(Return(0)); | 
 | 424 |  | 
| Willy Tu | 1209ccc | 2023-05-19 00:49:51 -0700 | [diff] [blame] | 425 |             const uint8_t byte = (i >= 8) ? 0 : (data >> (8 * i)) & 0xff; | 
| Steve Foreman | 4f0d1de | 2021-09-20 14:06:32 -0700 | [diff] [blame] | 426 |             EXPECT_CALL(mock, sd_bus_message_read_basic(msg, SD_BUS_TYPE_BYTE, | 
 | 427 |                                                         NotNull())) | 
 | 428 |                 .WillOnce(DoAll(AssignReadVal<uint8_t>(byte), Return(1))); | 
 | 429 |         } | 
 | 430 |  | 
 | 431 |         EXPECT_CALL(mock, sd_bus_message_at_end(msg, 0)).WillOnce(Return(1)); | 
 | 432 |  | 
 | 433 |         EXPECT_CALL(mock, sd_bus_message_exit_container(msg)) | 
 | 434 |             .WillOnce(Return(1)); | 
 | 435 |     } | 
 | 436 | } | 
 | 437 |  | 
 | 438 | TEST(HandlerTest, accelOobRead_Success) | 
 | 439 | { | 
 | 440 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 441 |     MockDbusHandler h(mock); | 
 | 442 |  | 
 | 443 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 444 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 445 |     constexpr int sd_bus_call_return_value = 1; | 
 | 446 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 447 |  | 
 | 448 |     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value); | 
 | 449 |     EXPECT_EQ(data, h.accelOobRead("test/path", address, num_bytes)); | 
 | 450 | } | 
 | 451 |  | 
 | 452 | TEST(HandlerTest, accelOobRead_Fail) | 
 | 453 | { | 
 | 454 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 455 |     MockDbusHandler h(mock); | 
 | 456 |  | 
 | 457 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 458 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 459 |     constexpr int sd_bus_call_return_value = -ENOTCONN; | 
 | 460 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 461 |  | 
 | 462 |     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value); | 
 | 463 |     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), | 
 | 464 |                  IpmiException); | 
 | 465 | } | 
 | 466 |  | 
 | 467 | TEST(HandlerTest, accelOobRead_TooFewBytesReturned) | 
 | 468 | { | 
 | 469 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 470 |     MockDbusHandler h(mock); | 
 | 471 |  | 
 | 472 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 473 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 474 |     constexpr int sd_bus_call_return_value = 1; | 
 | 475 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 476 |     constexpr uint8_t num_bytes_returned = num_bytes - 1; | 
 | 477 |  | 
 | 478 |     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value, | 
 | 479 |                num_bytes_returned); | 
 | 480 |     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), | 
 | 481 |                  IpmiException); | 
 | 482 | } | 
 | 483 |  | 
 | 484 | TEST(HandlerTest, accelOobRead_TooManyBytesReturned) | 
 | 485 | { | 
 | 486 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 487 |     MockDbusHandler h(mock); | 
 | 488 |  | 
 | 489 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 490 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 491 |     constexpr int sd_bus_call_return_value = 1; | 
 | 492 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 493 |     constexpr uint8_t num_bytes_returned = sizeof(uint64_t) + 1; | 
 | 494 |  | 
 | 495 |     ExpectRead(mock, address, num_bytes, data, sd_bus_call_return_value, | 
 | 496 |                num_bytes_returned); | 
 | 497 |     EXPECT_THROW(h.accelOobRead("test/path", address, num_bytes), | 
 | 498 |                  IpmiException); | 
 | 499 | } | 
 | 500 |  | 
 | 501 | void ExpectWrite(StrictMock<sdbusplus::SdBusMock>& mock, uint64_t address, | 
 | 502 |                  uint8_t num_bytes, uint64_t data, int sd_bus_call_return_value) | 
 | 503 | { | 
 | 504 |     ::testing::InSequence s; | 
 | 505 |  | 
 | 506 |     // These must be nullptr or sd_bus_message_unref will seg fault. | 
 | 507 |     constexpr sd_bus_message* method = nullptr; | 
 | 508 |  | 
 | 509 |     EXPECT_CALL(mock, sd_bus_message_new_method_call( | 
 | 510 |                           _,         // sd_bus *bus, | 
 | 511 |                           NotNull(), // sd_bus_message **m | 
 | 512 |                           StrEq("com.google.custom_accel"), | 
 | 513 |                           StrEq("/com/google/customAccel/test/path"), | 
 | 514 |                           StrEq("com.google.custom_accel.BAR"), StrEq("Write"))) | 
 | 515 |         .WillOnce(DoAll(TraceDbus("sd_bus_message_new_method_call"), | 
 | 516 |                         SetArgPointee<1>(method), Return(0))); | 
 | 517 |  | 
 | 518 |     EXPECT_CALL( | 
 | 519 |         mock, sd_bus_message_append_basic( | 
 | 520 |                   method, SD_BUS_TYPE_UINT64, | 
 | 521 |                   MatcherCast<const void*>( | 
 | 522 |                       SafeMatcherCast<const uint64_t*>(Pointee(Eq(address)))))) | 
 | 523 |         .WillOnce(DoAll(TraceDbus("sd_bus_message_append_basic(address) -> 1"), | 
 | 524 |                         Return(1))); | 
 | 525 |  | 
 | 526 |     EXPECT_CALL(mock, | 
 | 527 |                 sd_bus_message_open_container(method, SD_BUS_TYPE_ARRAY, | 
 | 528 |                                               StrEq(SD_BUS_TYPE_BYTE_STR))) | 
 | 529 |         .WillOnce(DoAll(TraceDbus("sd_bus_message_open_container(a, y) -> 0"), | 
 | 530 |                         Return(0))); | 
 | 531 |  | 
 | 532 |     for (auto i = 0; i < num_bytes; ++i) | 
 | 533 |     { | 
 | 534 |         const uint8_t byte = (data >> (8 * i)) & 0xff; | 
 | 535 |  | 
 | 536 |         EXPECT_CALL( | 
 | 537 |             mock, sd_bus_message_append_basic( | 
 | 538 |                       method, SD_BUS_TYPE_BYTE, | 
 | 539 |                       MatcherCast<const void*>( | 
 | 540 |                           SafeMatcherCast<const uint8_t*>(Pointee(Eq(byte)))))) | 
 | 541 |             .WillOnce( | 
 | 542 |                 DoAll(TraceDbus2("sd_bus_message_append_basic"), Return(1))); | 
 | 543 |     } | 
 | 544 |  | 
 | 545 |     EXPECT_CALL(mock, sd_bus_message_close_container(method)) | 
 | 546 |         .WillOnce(DoAll(TraceDbus("sd_bus_message_close_container() -> 0"), | 
 | 547 |                         Return(0))); | 
 | 548 |  | 
 | 549 |     EXPECT_CALL(mock, sd_bus_call(_,         // sd_bus *bus, | 
 | 550 |                                   method,    // sd_bus_message *m | 
 | 551 |                                   _,         // uint64_t timeout | 
 | 552 |                                   NotNull(), // sd_bus_error *ret_error | 
 | 553 |                                   IsNull())) // sd_bus_message **reply | 
 | 554 |         .WillOnce(DoAll(TraceDbus("sd_bus_call() -> ret_val"), | 
 | 555 |                         SetArgPointee<3>(SD_BUS_ERROR_NULL), | 
 | 556 |                         Return(sd_bus_call_return_value))); | 
 | 557 | } | 
 | 558 |  | 
 | 559 | TEST(HandlerTest, accelOobWrite_Success) | 
 | 560 | { | 
 | 561 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 562 |     MockDbusHandler h(mock); | 
 | 563 |  | 
 | 564 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 565 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 566 |     constexpr int sd_bus_call_return_value = 1; | 
 | 567 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 568 |  | 
 | 569 |     ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value); | 
 | 570 |     EXPECT_NO_THROW(h.accelOobWrite("test/path", address, num_bytes, data)); | 
 | 571 | } | 
 | 572 |  | 
 | 573 | TEST(HandlerTest, accelOobRead_TooManyBytesRequested) | 
 | 574 | { | 
 | 575 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 576 |     MockDbusHandler h(mock); | 
 | 577 |  | 
 | 578 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 579 |     constexpr uint8_t num_bytes = sizeof(uint64_t) + 1; | 
 | 580 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 581 |  | 
 | 582 |     EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data), | 
 | 583 |                  IpmiException); | 
 | 584 | } | 
 | 585 |  | 
 | 586 | TEST(HandlerTest, accelOobWrite_Fail) | 
 | 587 | { | 
 | 588 |     StrictMock<sdbusplus::SdBusMock> mock; | 
 | 589 |     MockDbusHandler h(mock); | 
 | 590 |  | 
 | 591 |     constexpr uint64_t address = 0x123456789abcdef; | 
 | 592 |     constexpr uint8_t num_bytes = sizeof(uint64_t); | 
 | 593 |     constexpr int sd_bus_call_return_value = -ENOTCONN; | 
 | 594 |     constexpr uint64_t data = 0x13579bdf02468ace; | 
 | 595 |  | 
 | 596 |     ExpectWrite(mock, address, num_bytes, data, sd_bus_call_return_value); | 
 | 597 |     EXPECT_THROW(h.accelOobWrite("test/path", address, num_bytes, data), | 
 | 598 |                  IpmiException); | 
 | 599 | } | 
 | 600 |  | 
| Willy Tu | 6c71b0f | 2021-10-10 13:34:41 -0700 | [diff] [blame] | 601 | TEST(HandlerTest, PcieBifurcation) | 
 | 602 | { | 
 | 603 |     const std::string& testJson = "/tmp/test-json"; | 
 | 604 |     auto j = R"( | 
 | 605 |         { | 
 | 606 |             "1": [ 1, 3 ], | 
 | 607 |             "3": [ 3, 6 ], | 
 | 608 |             "4": [ 3, 4, 1 ], | 
 | 609 |             "6": [ 8 ] | 
 | 610 |         } | 
 | 611 |     )"_json; | 
 | 612 |  | 
 | 613 |     std::ofstream bifurcationJson(testJson); | 
 | 614 |     bifurcationJson << j.dump(); | 
 | 615 |     bifurcationJson.flush(); | 
 | 616 |     bifurcationJson.close(); | 
 | 617 |  | 
 | 618 |     BifurcationStatic bifurcationHelper(testJson); | 
 | 619 |     Handler h(std::ref(bifurcationHelper)); | 
 | 620 |  | 
 | 621 |     std::unordered_map<uint8_t, std::vector<uint8_t>> expectedMapping = { | 
 | 622 |         {1, {1, 3}}, {3, {3, 6}}, {4, {3, 4, 1}}, {6, {8}}}; | 
 | 623 |     std::vector<uint8_t> invalidBus = {0, 2, 5, 7}; | 
 | 624 |  | 
 | 625 |     for (const auto& [bus, output] : expectedMapping) | 
 | 626 |     { | 
 | 627 |         EXPECT_THAT(h.pcieBifurcation(bus), ContainerEq(output)); | 
 | 628 |     } | 
 | 629 |  | 
 | 630 |     for (const auto& bus : invalidBus) | 
 | 631 |     { | 
 | 632 |         EXPECT_TRUE(h.pcieBifurcation(bus).empty()); | 
 | 633 |     } | 
 | 634 |  | 
 | 635 |     std::filesystem::remove(testJson.data()); | 
 | 636 |     bifurcationHelper = BifurcationStatic(testJson); | 
 | 637 |     Handler h2(std::ref(bifurcationHelper)); | 
 | 638 |     for (uint8_t i = 0; i < 8; ++i) | 
 | 639 |     { | 
 | 640 |         auto bifurcation = h2.pcieBifurcation(i); | 
 | 641 |         EXPECT_TRUE(bifurcation.empty()); | 
 | 642 |     } | 
 | 643 | } | 
 | 644 |  | 
| Patrick Venture | f085d91 | 2019-03-15 08:50:00 -0700 | [diff] [blame] | 645 | // TODO: Add checks for other functions of handler. | 
 | 646 |  | 
 | 647 | } // namespace ipmi | 
 | 648 | } // namespace google |