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::_;
30 using ::testing::Return;
31
TEST(GoogleAccelOobTest,DeviceCount_Success)32 TEST(GoogleAccelOobTest, DeviceCount_Success)
33 {
34 ::testing::StrictMock<HandlerMock> h;
35
36 uint8_t reqBuf[1]; // Could be 0, but zero-length arrays are an extension
37
38 struct Reply
39 {
40 uint32_t count;
41 } __attribute__((packed));
42
43 constexpr uint32_t kTestDeviceCount = 2;
44
45 EXPECT_CALL(h, accelOobDeviceCount()).WillOnce(Return(kTestDeviceCount));
46
47 Resp r = accelOobDeviceCount(reqBuf, &h);
48
49 const auto response = std::get<0>(r);
50 EXPECT_EQ(response, IPMI_CC_OK);
51
52 const auto payload = std::get<1>(r);
53 ASSERT_EQ(payload.has_value(), true);
54 const auto payload_tuple = payload.value();
55 const auto reply_cmd = std::get<0>(payload_tuple);
56 EXPECT_EQ(reply_cmd, SysAccelOobDeviceCount);
57 const auto reply_buff = std::get<1>(payload_tuple);
58 ASSERT_EQ(reply_buff.size(), sizeof(Reply));
59
60 auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
61 EXPECT_EQ(reply->count, kTestDeviceCount);
62 }
63
TEST(GoogleAccelOobTest,DeviceName_Success)64 TEST(GoogleAccelOobTest, DeviceName_Success)
65 {
66 ::testing::StrictMock<HandlerMock> h;
67
68 struct Request
69 {
70 uint32_t index;
71 } __attribute__((packed));
72
73 struct Reply
74 {
75 uint32_t index;
76 uint8_t length;
77 char name[1];
78 } __attribute__((packed));
79
80 constexpr uint32_t kTestDeviceIndex = 0;
81 const std::string kTestDeviceName("testDeviceName");
82
83 EXPECT_CALL(h, accelOobDeviceName(kTestDeviceIndex))
84 .WillOnce(Return(kTestDeviceName));
85
86 Request reqBuf{kTestDeviceIndex};
87 Resp r = accelOobDeviceName(
88 std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
89 &h);
90
91 const auto response = std::get<0>(r);
92 EXPECT_EQ(response, IPMI_CC_OK);
93
94 const auto payload = std::get<1>(r);
95 ASSERT_EQ(payload.has_value(), true);
96 const auto payload_tuple = payload.value();
97 const auto reply_cmd = std::get<0>(payload_tuple);
98 EXPECT_EQ(reply_cmd, SysAccelOobDeviceName);
99 const auto reply_buff = std::get<1>(payload_tuple);
100 ASSERT_GE(reply_buff.size(), sizeof(Reply));
101
102 auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
103 EXPECT_EQ(reply->index, kTestDeviceIndex);
104 EXPECT_EQ(reply->length, kTestDeviceName.length());
105 EXPECT_STREQ(reply->name, kTestDeviceName.c_str());
106 }
107
TEST(GoogleAccelOobTest,Read_Success)108 TEST(GoogleAccelOobTest, Read_Success)
109 {
110 ::testing::StrictMock<HandlerMock> h;
111
112 constexpr char kTestDeviceName[] = "testDeviceName";
113 constexpr uint8_t kTestDeviceNameLength =
114 (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1;
115 constexpr uint8_t kTestToken = 0xAB;
116 constexpr uint64_t kTestAddress = 0;
117 constexpr uint8_t kTestReadSize = 8;
118 constexpr uint64_t kTestData = 0x12345678;
119
120 struct Request
121 {
122 uint8_t nameLength;
123 char name[kTestDeviceNameLength];
124 uint8_t token;
125 uint64_t address;
126 uint8_t num_bytes;
127 } __attribute__((packed));
128
129 struct Reply
130 {
131 uint8_t nameLength;
132 char name[kTestDeviceNameLength];
133 uint8_t token;
134 uint64_t address;
135 uint8_t num_bytes;
136 uint64_t data;
137 } __attribute__((packed));
138
139 const std::string_view kTestDeviceNameStr(kTestDeviceName,
140 kTestDeviceNameLength);
141 EXPECT_CALL(h,
142 accelOobRead(kTestDeviceNameStr, kTestAddress, kTestReadSize))
143 .WillOnce(Return(kTestData));
144
145 Request reqBuf{kTestDeviceNameLength, "", kTestToken, kTestAddress,
146 kTestReadSize};
147 memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength);
148 Resp r = accelOobRead(
149 std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
150 &h);
151
152 const auto response = std::get<0>(r);
153 EXPECT_EQ(response, IPMI_CC_OK);
154
155 const auto payload = std::get<1>(r);
156 ASSERT_EQ(payload.has_value(), true);
157 const auto payload_tuple = payload.value();
158 const auto reply_cmd = std::get<0>(payload_tuple);
159 EXPECT_EQ(reply_cmd, SysAccelOobRead);
160 const auto reply_buff = std::get<1>(payload_tuple);
161 ASSERT_GE(reply_buff.size(), sizeof(Reply));
162
163 auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
164 EXPECT_EQ(reply->nameLength, kTestDeviceNameLength);
165 EXPECT_EQ(std::string_view(reply->name, reply->nameLength),
166 kTestDeviceNameStr);
167 EXPECT_EQ(reply->token, kTestToken);
168 EXPECT_EQ(reply->address, kTestAddress);
169 EXPECT_EQ(reply->num_bytes, kTestReadSize);
170 EXPECT_EQ(reply->data, kTestData);
171 }
172
TEST(GoogleAccelOobTest,Write_Success)173 TEST(GoogleAccelOobTest, Write_Success)
174 {
175 ::testing::StrictMock<HandlerMock> h;
176
177 constexpr char kTestDeviceName[] = "testDeviceName";
178 constexpr uint8_t kTestDeviceNameLength =
179 (sizeof(kTestDeviceName) / sizeof(*kTestDeviceName)) - 1;
180 constexpr uint8_t kTestToken = 0xAB;
181 constexpr uint64_t kTestAddress = 0;
182 constexpr uint8_t kTestWriteSize = 8;
183 constexpr uint64_t kTestData = 0x12345678;
184
185 struct Request
186 {
187 uint8_t nameLength;
188 char name[kTestDeviceNameLength];
189 uint8_t token;
190 uint64_t address;
191 uint8_t num_bytes;
192 uint64_t data;
193 } __attribute__((packed));
194
195 struct Reply
196 {
197 uint8_t nameLength;
198 char name[kTestDeviceNameLength];
199 uint8_t token;
200 uint64_t address;
201 uint8_t num_bytes;
202 uint64_t data;
203 } __attribute__((packed));
204
205 const std::string_view kTestDeviceNameStr(kTestDeviceName,
206 kTestDeviceNameLength);
207 EXPECT_CALL(h, accelOobWrite(kTestDeviceNameStr, kTestAddress,
208 kTestWriteSize, kTestData))
209 .WillOnce(Return());
210
211 Request reqBuf{kTestDeviceNameLength, "", kTestToken, kTestAddress,
212 kTestWriteSize, kTestData};
213 memcpy(reqBuf.name, kTestDeviceName, kTestDeviceNameLength);
214 Resp r = accelOobWrite(
215 std::span(reinterpret_cast<const uint8_t*>(&reqBuf), sizeof(Request)),
216 &h);
217
218 const auto response = std::get<0>(r);
219 EXPECT_EQ(response, IPMI_CC_OK);
220
221 const auto payload = std::get<1>(r);
222 ASSERT_EQ(payload.has_value(), true);
223 const auto payload_tuple = payload.value();
224 const auto reply_cmd = std::get<0>(payload_tuple);
225 EXPECT_EQ(reply_cmd, SysAccelOobWrite);
226 const auto reply_buff = std::get<1>(payload_tuple);
227 ASSERT_GE(reply_buff.size(), sizeof(Reply));
228
229 auto* reply = reinterpret_cast<const Reply*>(reply_buff.data());
230 EXPECT_EQ(reply->nameLength, kTestDeviceNameLength);
231 EXPECT_EQ(std::string_view(reply->name, reply->nameLength),
232 kTestDeviceNameStr);
233 EXPECT_EQ(reply->token, kTestToken);
234 EXPECT_EQ(reply->address, kTestAddress);
235 EXPECT_EQ(reply->num_bytes, kTestWriteSize);
236 EXPECT_EQ(reply->data, kTestData);
237 }
238
TEST(GoogleAccelOobTest,SetVrSettings_Success)239 TEST(GoogleAccelOobTest, SetVrSettings_Success)
240 {
241 ::testing::StrictMock<HandlerMock> h;
242 constexpr uint8_t kChipId = 2;
243 constexpr uint8_t kSettingsId = 1;
244 constexpr uint16_t kTestValue = 0xAABB;
245
246 std::vector<uint8_t> testData = {kChipId, kSettingsId, 0xBB, 0xAA};
247
248 EXPECT_CALL(h, accelSetVrSettings(_, kChipId, kSettingsId, kTestValue))
249 .WillOnce(Return());
250
251 Resp r = accelSetVrSettings(nullptr, testData, &h);
252
253 const auto response = std::get<0>(r);
254 EXPECT_EQ(response, IPMI_CC_OK);
255
256 const auto payload = std::get<1>(r);
257 ASSERT_EQ(payload.has_value(), true);
258 const auto payload_tuple = payload.value();
259 const auto reply_cmd = std::get<0>(payload_tuple);
260 EXPECT_EQ(reply_cmd, SysSetAccelVrSettings);
261 const auto reply_buff = std::get<1>(payload_tuple);
262 ASSERT_EQ(reply_buff.size(), 0);
263 }
264
TEST(GoogleAccelOobTest,SetVrSettings_HandleIncorrectDataSize)265 TEST(GoogleAccelOobTest, SetVrSettings_HandleIncorrectDataSize)
266 {
267 ::testing::StrictMock<HandlerMock> h;
268 constexpr uint8_t kChipId = 2;
269 uint8_t kSettingsId = 1;
270
271 std::vector<uint8_t> testData = {kChipId, kSettingsId};
272
273 EXPECT_CALL(h, accelSetVrSettings(_, _, _, _)).Times(0);
274
275 Resp r = accelSetVrSettings(nullptr, testData, &h);
276
277 const auto response = std::get<0>(r);
278 EXPECT_EQ(response, IPMI_CC_REQ_DATA_LEN_INVALID);
279
280 const auto payload = std::get<1>(r);
281 ASSERT_EQ(payload.has_value(), false);
282 }
283
TEST(GoogleAccelOobTest,GetVrSettings_Success)284 TEST(GoogleAccelOobTest, GetVrSettings_Success)
285 {
286 ::testing::StrictMock<HandlerMock> h;
287 constexpr uint8_t kChipId = 3;
288 constexpr uint8_t kSettingsId = 2;
289
290 std::vector<uint8_t> testData = {kChipId, kSettingsId};
291
292 EXPECT_CALL(h, accelGetVrSettings(_, kChipId, kSettingsId))
293 .WillOnce(Return(0xAABB));
294
295 Resp r = accelGetVrSettings(nullptr, testData, &h);
296
297 const auto response = std::get<0>(r);
298 EXPECT_EQ(response, IPMI_CC_OK);
299
300 const auto payload = std::get<1>(r);
301 ASSERT_EQ(payload.has_value(), true);
302 const auto payload_tuple = payload.value();
303 const auto reply_cmd = std::get<0>(payload_tuple);
304 EXPECT_EQ(reply_cmd, SysGetAccelVrSettings);
305 const auto reply_buff = std::get<1>(payload_tuple);
306 ASSERT_EQ(reply_buff.size(), 2);
307
308 EXPECT_EQ(reply_buff.at(0), 0xBB);
309 EXPECT_EQ(reply_buff.at(1), 0xAA);
310 }
311
TEST(GoogleAccelOobTest,GetVrSettings_HandleIncorrectDataSize)312 TEST(GoogleAccelOobTest, GetVrSettings_HandleIncorrectDataSize)
313 {
314 ::testing::StrictMock<HandlerMock> h;
315 constexpr uint8_t kChipId = 2;
316 uint8_t kSettingsId = 1;
317
318 std::vector<uint8_t> testData = {kChipId, kSettingsId, 0xCC};
319
320 EXPECT_CALL(h, accelGetVrSettings(_, _, _)).Times(0);
321
322 Resp r = accelGetVrSettings(nullptr, testData, &h);
323
324 const auto response = std::get<0>(r);
325 EXPECT_EQ(response, IPMI_CC_REQ_DATA_LEN_INVALID);
326
327 const auto payload = std::get<1>(r);
328 ASSERT_EQ(payload.has_value(), false);
329 }
330 } // namespace ipmi
331 } // namespace google
332