| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "commands.hpp" |
| #include "errors.hpp" |
| #include "google_accel_oob.hpp" |
| #include "handler_mock.hpp" |
| |
| #include <ipmid/api.h> |
| |
| #include <gtest/gtest.h> |
| |
| namespace google |
| { |
| namespace ipmi |
| { |
| |
| using ::testing::Return; |
| |
| TEST(GoogleAccelOobTest, DeviceCount_Success) |
| { |
| ::testing::StrictMock<HandlerMock> h; |
| |
| uint8_t reqBuf[1]; // Could be 0, but zero-length arrays are an extension |
| |
| struct Reply |
| { |
| uint32_t count; |
| } __attribute__((packed)); |
| |
| constexpr uint32_t kTestDeviceCount = 2; |
| |
| EXPECT_CALL(h, accelOobDeviceCount()).WillOnce(Return(kTestDeviceCount)); |
| |
| Resp r = accelOobDeviceCount(reqBuf, &h); |
| |
| const auto response = std::get<0>(r); |
| EXPECT_EQ(response, IPMI_CC_OK); |
| |
| const auto payload = std::get<1>(r); |
| ASSERT_EQ(payload.has_value(), true); |
| const auto payload_tuple = payload.value(); |
| const auto reply_cmd = std::get<0>(payload_tuple); |
| EXPECT_EQ(reply_cmd, SysAccelOobDeviceCount); |
| const auto reply_buff = std::get<1>(payload_tuple); |
| ASSERT_EQ(reply_buff.size(), sizeof(Reply)); |
| |
| auto* reply = reinterpret_cast<const Reply*>(reply_buff.data()); |
| EXPECT_EQ(reply->count, kTestDeviceCount); |
| } |
| |
| TEST(GoogleAccelOobTest, DeviceName_Success) |
| { |
| ::testing::StrictMock<HandlerMock> h; |
| |
| struct Request |
| { |
| uint32_t index; |
| } __attribute__((packed)); |
| |
| struct Reply |
| { |
| uint32_t index; |
| uint8_t length; |
| char name[1]; |
| } __attribute__((packed)); |
| |
| constexpr uint32_t kTestDeviceIndex = 0; |
| const std::string kTestDeviceName("testDeviceName"); |
| |
| EXPECT_CALL(h, accelOobDeviceName(kTestDeviceIndex)) |
| .WillOnce(Return(kTestDeviceName)); |
| |
| Request reqBuf{kTestDeviceIndex}; |
| Resp r = accelOobDeviceName( |
| std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)), |
| &h); |
| |
| const auto response = std::get<0>(r); |
| EXPECT_EQ(response, IPMI_CC_OK); |
| |
| const auto payload = std::get<1>(r); |
| ASSERT_EQ(payload.has_value(), true); |
| const auto payload_tuple = payload.value(); |
| const auto reply_cmd = std::get<0>(payload_tuple); |
| EXPECT_EQ(reply_cmd, SysAccelOobDeviceName); |
| const auto reply_buff = std::get<1>(payload_tuple); |
| ASSERT_GE(reply_buff.size(), sizeof(Reply)); |
| |
| auto* reply = reinterpret_cast<const Reply*>(reply_buff.data()); |
| EXPECT_EQ(reply->index, kTestDeviceIndex); |
| EXPECT_EQ(reply->length, kTestDeviceName.length()); |
| EXPECT_STREQ(reply->name, kTestDeviceName.c_str()); |
| } |
| |
| TEST(GoogleAccelOobTest, Read_Success) |
| { |
| ::testing::StrictMock<HandlerMock> h; |
| |
| constexpr char kTestDeviceName[] = "testDeviceName"; |
| constexpr uint8_t kTestDeviceNameLength = |
| (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1; |
| constexpr uint8_t kTestToken = 0xAB; |
| constexpr uint64_t kTestAddress = 0; |
| constexpr uint8_t kTestReadSize = 8; |
| constexpr uint64_t kTestData = 0x12345678; |
| |
| struct Request |
| { |
| uint8_t nameLength; |
| char name[kTestDeviceNameLength]; |
| uint8_t token; |
| uint64_t address; |
| uint8_t num_bytes; |
| } __attribute__((packed)); |
| |
| struct Reply |
| { |
| uint8_t nameLength; |
| char name[kTestDeviceNameLength]; |
| uint8_t token; |
| uint64_t address; |
| uint8_t num_bytes; |
| uint64_t data; |
| } __attribute__((packed)); |
| |
| const std::string_view kTestDeviceNameStr(kTestDeviceName, |
| kTestDeviceNameLength); |
| EXPECT_CALL(h, |
| accelOobRead(kTestDeviceNameStr, kTestAddress, kTestReadSize)) |
| .WillOnce(Return(kTestData)); |
| |
| Request reqBuf{kTestDeviceNameLength, "", kTestToken, kTestAddress, |
| kTestReadSize}; |
| memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength); |
| Resp r = accelOobRead( |
| std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)), |
| &h); |
| |
| const auto response = std::get<0>(r); |
| EXPECT_EQ(response, IPMI_CC_OK); |
| |
| const auto payload = std::get<1>(r); |
| ASSERT_EQ(payload.has_value(), true); |
| const auto payload_tuple = payload.value(); |
| const auto reply_cmd = std::get<0>(payload_tuple); |
| EXPECT_EQ(reply_cmd, SysAccelOobRead); |
| const auto reply_buff = std::get<1>(payload_tuple); |
| ASSERT_GE(reply_buff.size(), sizeof(Reply)); |
| |
| auto* reply = reinterpret_cast<const Reply*>(reply_buff.data()); |
| EXPECT_EQ(reply->nameLength, kTestDeviceNameLength); |
| EXPECT_EQ(std::string_view(reply->name, reply->nameLength), |
| kTestDeviceNameStr); |
| EXPECT_EQ(reply->token, kTestToken); |
| EXPECT_EQ(reply->address, kTestAddress); |
| EXPECT_EQ(reply->num_bytes, kTestReadSize); |
| EXPECT_EQ(reply->data, kTestData); |
| } |
| |
| TEST(GoogleAccelOobTest, Write_Success) |
| { |
| ::testing::StrictMock<HandlerMock> h; |
| |
| constexpr char kTestDeviceName[] = "testDeviceName"; |
| constexpr uint8_t kTestDeviceNameLength = |
| (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1; |
| constexpr uint8_t kTestToken = 0xAB; |
| constexpr uint64_t kTestAddress = 0; |
| constexpr uint8_t kTestWriteSize = 8; |
| constexpr uint64_t kTestData = 0x12345678; |
| |
| struct Request |
| { |
| uint8_t nameLength; |
| char name[kTestDeviceNameLength]; |
| uint8_t token; |
| uint64_t address; |
| uint8_t num_bytes; |
| uint64_t data; |
| } __attribute__((packed)); |
| |
| struct Reply |
| { |
| uint8_t nameLength; |
| char name[kTestDeviceNameLength]; |
| uint8_t token; |
| uint64_t address; |
| uint8_t num_bytes; |
| uint64_t data; |
| } __attribute__((packed)); |
| |
| const std::string_view kTestDeviceNameStr(kTestDeviceName, |
| kTestDeviceNameLength); |
| EXPECT_CALL(h, accelOobWrite(kTestDeviceNameStr, kTestAddress, |
| kTestWriteSize, kTestData)) |
| .WillOnce(Return()); |
| |
| Request reqBuf{kTestDeviceNameLength, "", kTestToken, kTestAddress, |
| kTestWriteSize, kTestData}; |
| memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength); |
| Resp r = accelOobWrite( |
| std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)), |
| &h); |
| |
| const auto response = std::get<0>(r); |
| EXPECT_EQ(response, IPMI_CC_OK); |
| |
| const auto payload = std::get<1>(r); |
| ASSERT_EQ(payload.has_value(), true); |
| const auto payload_tuple = payload.value(); |
| const auto reply_cmd = std::get<0>(payload_tuple); |
| EXPECT_EQ(reply_cmd, SysAccelOobWrite); |
| const auto reply_buff = std::get<1>(payload_tuple); |
| ASSERT_GE(reply_buff.size(), sizeof(Reply)); |
| |
| auto* reply = reinterpret_cast<const Reply*>(reply_buff.data()); |
| EXPECT_EQ(reply->nameLength, kTestDeviceNameLength); |
| EXPECT_EQ(std::string_view(reply->name, reply->nameLength), |
| kTestDeviceNameStr); |
| EXPECT_EQ(reply->token, kTestToken); |
| EXPECT_EQ(reply->address, kTestAddress); |
| EXPECT_EQ(reply->num_bytes, kTestWriteSize); |
| EXPECT_EQ(reply->data, kTestData); |
| } |
| |
| } // namespace ipmi |
| } // namespace google |