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 "commands.hpp"
16 #include "errors.hpp"
17 #include "google_accel_oob.hpp"
18 #include "handler_mock.hpp"
19 
20 #include <ipmid/api.h>
21 
22 #include <gtest/gtest.h>
23 
24 namespace google
25 {
26 namespace ipmi
27 {
28 
29 using ::testing::Return;
30 
31 TEST(GoogleAccelOobTest, DeviceCount_Success)
32 {
33     ::testing::StrictMock<HandlerMock> h;
34 
35     uint8_t reqBuf[1]; // Could be 0, but zero-length arrays are an extension
36 
37     struct Reply
38     {
39         uint32_t count;
40     } __attribute__((packed));
41 
42     constexpr uint32_t kTestDeviceCount = 2;
43 
44     EXPECT_CALL(h, accelOobDeviceCount()).WillOnce(Return(kTestDeviceCount));
45 
46     Resp r = accelOobDeviceCount(reqBuf, &h);
47 
48     const auto response = std::get<0>(r);
49     EXPECT_EQ(response, IPMI_CC_OK);
50 
51     const auto payload = std::get<1>(r);
52     ASSERT_EQ(payload.has_value(), true);
53     const auto payload_tuple = payload.value();
54     const auto reply_cmd = std::get<0>(payload_tuple);
55     EXPECT_EQ(reply_cmd, SysAccelOobDeviceCount);
56     const auto reply_buff = std::get<1>(payload_tuple);
57     ASSERT_EQ(reply_buff.size(), sizeof(Reply));
58 
59     auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
60     EXPECT_EQ(reply->count, kTestDeviceCount);
61 }
62 
63 TEST(GoogleAccelOobTest, DeviceName_Success)
64 {
65     ::testing::StrictMock<HandlerMock> h;
66 
67     struct Request
68     {
69         uint32_t index;
70     } __attribute__((packed));
71 
72     struct Reply
73     {
74         uint32_t index;
75         uint8_t length;
76         char name[1];
77     } __attribute__((packed));
78 
79     constexpr uint32_t kTestDeviceIndex = 0;
80     const std::string kTestDeviceName("testDeviceName");
81 
82     EXPECT_CALL(h, accelOobDeviceName(kTestDeviceIndex))
83         .WillOnce(Return(kTestDeviceName));
84 
85     Request reqBuf{kTestDeviceIndex};
86     Resp r = accelOobDeviceName(
87         std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
88         &h);
89 
90     const auto response = std::get<0>(r);
91     EXPECT_EQ(response, IPMI_CC_OK);
92 
93     const auto payload = std::get<1>(r);
94     ASSERT_EQ(payload.has_value(), true);
95     const auto payload_tuple = payload.value();
96     const auto reply_cmd = std::get<0>(payload_tuple);
97     EXPECT_EQ(reply_cmd, SysAccelOobDeviceName);
98     const auto reply_buff = std::get<1>(payload_tuple);
99     ASSERT_GE(reply_buff.size(), sizeof(Reply));
100 
101     auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
102     EXPECT_EQ(reply->index, kTestDeviceIndex);
103     EXPECT_EQ(reply->length, kTestDeviceName.length());
104     EXPECT_STREQ(reply->name, kTestDeviceName.c_str());
105 }
106 
107 TEST(GoogleAccelOobTest, Read_Success)
108 {
109     ::testing::StrictMock<HandlerMock> h;
110 
111     constexpr char kTestDeviceName[] = "testDeviceName";
112     constexpr uint8_t kTestDeviceNameLength =
113         (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1;
114     constexpr uint8_t kTestToken = 0xAB;
115     constexpr uint64_t kTestAddress = 0;
116     constexpr uint8_t kTestReadSize = 8;
117     constexpr uint64_t kTestData = 0x12345678;
118 
119     struct Request
120     {
121         uint8_t nameLength;
122         char name[kTestDeviceNameLength];
123         uint8_t token;
124         uint64_t address;
125         uint8_t num_bytes;
126     } __attribute__((packed));
127 
128     struct Reply
129     {
130         uint8_t nameLength;
131         char name[kTestDeviceNameLength];
132         uint8_t token;
133         uint64_t address;
134         uint8_t num_bytes;
135         uint64_t data;
136     } __attribute__((packed));
137 
138     const std::string_view kTestDeviceNameStr(kTestDeviceName,
139                                               kTestDeviceNameLength);
140     EXPECT_CALL(h,
141                 accelOobRead(kTestDeviceNameStr, kTestAddress, kTestReadSize))
142         .WillOnce(Return(kTestData));
143 
144     Request reqBuf{kTestDeviceNameLength, "", kTestToken, kTestAddress,
145                    kTestReadSize};
146     memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength);
147     Resp r = accelOobRead(
148         std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
149         &h);
150 
151     const auto response = std::get<0>(r);
152     EXPECT_EQ(response, IPMI_CC_OK);
153 
154     const auto payload = std::get<1>(r);
155     ASSERT_EQ(payload.has_value(), true);
156     const auto payload_tuple = payload.value();
157     const auto reply_cmd = std::get<0>(payload_tuple);
158     EXPECT_EQ(reply_cmd, SysAccelOobRead);
159     const auto reply_buff = std::get<1>(payload_tuple);
160     ASSERT_GE(reply_buff.size(), sizeof(Reply));
161 
162     auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
163     EXPECT_EQ(reply->nameLength, kTestDeviceNameLength);
164     EXPECT_EQ(std::string_view(reply->name, reply->nameLength),
165               kTestDeviceNameStr);
166     EXPECT_EQ(reply->token, kTestToken);
167     EXPECT_EQ(reply->address, kTestAddress);
168     EXPECT_EQ(reply->num_bytes, kTestReadSize);
169     EXPECT_EQ(reply->data, kTestData);
170 }
171 
172 TEST(GoogleAccelOobTest, Write_Success)
173 {
174     ::testing::StrictMock<HandlerMock> h;
175 
176     constexpr char kTestDeviceName[] = "testDeviceName";
177     constexpr uint8_t kTestDeviceNameLength =
178         (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1;
179     constexpr uint8_t kTestToken = 0xAB;
180     constexpr uint64_t kTestAddress = 0;
181     constexpr uint8_t kTestWriteSize = 8;
182     constexpr uint64_t kTestData = 0x12345678;
183 
184     struct Request
185     {
186         uint8_t nameLength;
187         char name[kTestDeviceNameLength];
188         uint8_t token;
189         uint64_t address;
190         uint8_t num_bytes;
191         uint64_t data;
192     } __attribute__((packed));
193 
194     struct Reply
195     {
196         uint8_t nameLength;
197         char name[kTestDeviceNameLength];
198         uint8_t token;
199         uint64_t address;
200         uint8_t num_bytes;
201         uint64_t data;
202     } __attribute__((packed));
203 
204     const std::string_view kTestDeviceNameStr(kTestDeviceName,
205                                               kTestDeviceNameLength);
206     EXPECT_CALL(h, accelOobWrite(kTestDeviceNameStr, kTestAddress,
207                                  kTestWriteSize, kTestData))
208         .WillOnce(Return());
209 
210     Request reqBuf{kTestDeviceNameLength, "",       kTestToken, kTestAddress,
211                    kTestWriteSize,        kTestData};
212     memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength);
213     Resp r = accelOobWrite(
214         std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
215         &h);
216 
217     const auto response = std::get<0>(r);
218     EXPECT_EQ(response, IPMI_CC_OK);
219 
220     const auto payload = std::get<1>(r);
221     ASSERT_EQ(payload.has_value(), true);
222     const auto payload_tuple = payload.value();
223     const auto reply_cmd = std::get<0>(payload_tuple);
224     EXPECT_EQ(reply_cmd, SysAccelOobWrite);
225     const auto reply_buff = std::get<1>(payload_tuple);
226     ASSERT_GE(reply_buff.size(), sizeof(Reply));
227 
228     auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
229     EXPECT_EQ(reply->nameLength, kTestDeviceNameLength);
230     EXPECT_EQ(std::string_view(reply->name, reply->nameLength),
231               kTestDeviceNameStr);
232     EXPECT_EQ(reply->token, kTestToken);
233     EXPECT_EQ(reply->address, kTestAddress);
234     EXPECT_EQ(reply->num_bytes, kTestWriteSize);
235     EXPECT_EQ(reply->data, kTestData);
236 }
237 
238 } // namespace ipmi
239 } // namespace google
240