blob: 9207c2d7c28d6e875e35223c8f963edd855f2681 [file] [log] [blame]
Brandon Kimfcbc3db2022-06-06 21:26:18 -07001#include "buffer.hpp"
2#include "data_interface_mock.hpp"
3
Brandon Kim17ee1a92022-06-07 21:04:08 -07004#include <boost/endian/arithmetic.hpp>
5#include <boost/endian/conversion.hpp>
6
7#include <algorithm>
Brandon Kimfcbc3db2022-06-06 21:26:18 -07008#include <array>
9#include <cstdint>
10#include <memory>
11
12#include <gmock/gmock.h>
13#include <gtest/gtest.h>
14
15namespace bios_bmc_smm_error_logger
16{
17namespace
18{
19
20using ::testing::_;
21using ::testing::ElementsAreArray;
22using ::testing::InSequence;
23using ::testing::Return;
24
25class BufferTest : public ::testing::Test
26{
27 protected:
28 BufferTest() :
29 dataInterfaceMock(std::make_unique<DataInterfaceMock>()),
30 dataInterfaceMockPtr(dataInterfaceMock.get())
31 {
32 bufferImpl = std::make_unique<BufferImpl>(std::move(dataInterfaceMock));
33 testInitializationHeader.bmcInterfaceVersion = testBmcInterfaceVersion;
34 testInitializationHeader.queueSize = testQueueSize;
35 testInitializationHeader.ueRegionSize = testUeRegionSize;
Brandon Kim17ee1a92022-06-07 21:04:08 -070036 std::transform(testMagicNumber.begin(), testMagicNumber.end(),
37 testInitializationHeader.magicNumber.begin(),
38 [](uint32_t number) -> little_uint32_t {
Patrick Williams1a643562024-08-16 15:22:05 -040039 return boost::endian::native_to_little(number);
40 });
Brandon Kimfcbc3db2022-06-06 21:26:18 -070041 }
42 ~BufferTest() override = default;
43
44 // CircularBufferHeader size is 0x30, ensure the test region is bigger
45 static constexpr size_t testRegionSize = 0x200;
46 static constexpr uint32_t testBmcInterfaceVersion = 123;
Brandon Kim3def3c82022-09-13 05:29:20 +000047 static constexpr uint32_t testQueueSize = 0x200;
Brandon Kimfcbc3db2022-06-06 21:26:18 -070048 static constexpr uint16_t testUeRegionSize = 0x50;
49 static constexpr std::array<uint32_t, 4> testMagicNumber = {
50 0x12345678, 0x22345678, 0x32345678, 0x42345678};
Brandon Kim17ee1a92022-06-07 21:04:08 -070051 static constexpr size_t bufferHeaderSize =
52 sizeof(struct CircularBufferHeader);
53
Patrick Williamsc20d1212024-12-18 11:22:36 -050054 struct CircularBufferHeader testInitializationHeader{};
Brandon Kimfcbc3db2022-06-06 21:26:18 -070055
56 std::unique_ptr<DataInterfaceMock> dataInterfaceMock;
57 DataInterfaceMock* dataInterfaceMockPtr;
Brandon Kimfcbc3db2022-06-06 21:26:18 -070058 std::unique_ptr<BufferImpl> bufferImpl;
59};
60
61TEST_F(BufferTest, BufferInitializeEraseFail)
62{
63 InSequence s;
Brandon Kim26660e92022-06-15 16:58:44 -070064 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
65 .WillOnce(Return(testRegionSize));
66 EXPECT_THROW(
67 try {
68 // Test too big of a proposed buffer compared to the memori size
Brandon Kim3def3c82022-09-13 05:29:20 +000069 uint16_t bigQueueSize = 0x201;
Brandon Kim26660e92022-06-15 16:58:44 -070070 uint16_t bigUeRegionSize = 0x50;
71 bufferImpl->initialize(testBmcInterfaceVersion, bigQueueSize,
72 bigUeRegionSize, testMagicNumber);
73 } catch (const std::runtime_error& e) {
74 EXPECT_STREQ(
75 e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +000076 "[initialize] Proposed queue size '513' is bigger than the BMC's allocated MMIO region of '512'");
Brandon Kim26660e92022-06-15 16:58:44 -070077 throw;
78 },
79 std::runtime_error);
80 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070081
82 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
83 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +000084 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070085 // Return a smaller write than the intended testRegionSize to test the error
86 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +000087 .WillOnce(Return(testQueueSize - 1));
Brandon Kimfcbc3db2022-06-06 21:26:18 -070088 EXPECT_THROW(
89 try {
90 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
91 testUeRegionSize, testMagicNumber);
92 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +000093 EXPECT_STREQ(e.what(), "[initialize] Only erased '511'");
Brandon Kimfcbc3db2022-06-06 21:26:18 -070094 throw;
95 },
96 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -070097 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070098
99 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
100 .WillOnce(Return(testRegionSize));
101 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000102 .WillOnce(Return(testQueueSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700103 // Return a smaller write than the intended initializationHeader to test the
104 // error
105 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0));
106 EXPECT_THROW(
107 try {
108 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
109 testUeRegionSize, testMagicNumber);
110 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700111 EXPECT_STREQ(e.what(),
112 "[initialize] Only wrote '0' bytes of the header");
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700113 throw;
114 },
115 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -0700116 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700117}
118
119TEST_F(BufferTest, BufferInitializePass)
120{
121 InSequence s;
122 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
123 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +0000124 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700125 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000126 .WillOnce(Return(testQueueSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700127
128 uint8_t* testInitializationHeaderPtr =
129 reinterpret_cast<uint8_t*>(&testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700130 EXPECT_CALL(*dataInterfaceMockPtr,
131 write(0, ElementsAreArray(testInitializationHeaderPtr,
Brandon Kim17ee1a92022-06-07 21:04:08 -0700132 bufferHeaderSize)))
133 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400134 EXPECT_NO_THROW(
135 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
136 testUeRegionSize, testMagicNumber));
Brandon Kim60cab572022-06-15 14:20:05 -0700137 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700138}
139
Brandon Kim17ee1a92022-06-07 21:04:08 -0700140TEST_F(BufferTest, BufferHeaderReadFail)
141{
142 std::vector<std::uint8_t> testBytesRead{};
143 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
144 .WillOnce(Return(testBytesRead));
145 EXPECT_THROW(
146 try {
147 bufferImpl->readBufferHeader();
148 } catch (const std::runtime_error& e) {
149 EXPECT_STREQ(e.what(),
150 "Buffer header read only read '0', expected '48'");
151 throw;
152 },
153 std::runtime_error);
154}
155
156TEST_F(BufferTest, BufferHeaderReadPass)
157{
158 uint8_t* testInitializationHeaderPtr =
159 reinterpret_cast<uint8_t*>(&testInitializationHeader);
160 std::vector<uint8_t> testInitializationHeaderVector(
161 testInitializationHeaderPtr,
162 testInitializationHeaderPtr + bufferHeaderSize);
163
164 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
165 .WillOnce(Return(testInitializationHeaderVector));
166 EXPECT_NO_THROW(bufferImpl->readBufferHeader());
167 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
168}
169
Brandon Kimcf0b9752022-06-15 10:32:21 -0700170TEST_F(BufferTest, BufferUpdateReadPtrFail)
171{
172 // Return write size that is not 2 which is sizeof(little_uint16_t)
173 constexpr size_t wrongWriteSize = 1;
174 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
175 .WillOnce(Return(wrongWriteSize));
176 EXPECT_THROW(
177 try {
178 bufferImpl->updateReadPtr(0);
179 } catch (const std::runtime_error& e) {
180 EXPECT_STREQ(
181 e.what(),
Brandon Kim271d2312022-09-02 16:34:55 +0000182 "[updateReadPtr] Wrote '1' bytes, instead of expected '3'");
Brandon Kimcf0b9752022-06-15 10:32:21 -0700183 throw;
184 },
185 std::runtime_error);
186}
187
188TEST_F(BufferTest, BufferUpdateReadPtrPass)
189{
Brandon Kim271d2312022-09-02 16:34:55 +0000190 constexpr size_t expectedWriteSize = 3;
191 constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
192 // Check that we truncate the highest 24bits
Brandon Kimcf0b9752022-06-15 10:32:21 -0700193 const uint32_t testNewReadPtr = 0x99881234;
Brandon Kim271d2312022-09-02 16:34:55 +0000194 const std::vector<uint8_t> expectedReadPtr{0x34, 0x12, 0x88};
Brandon Kimcf0b9752022-06-15 10:32:21 -0700195
196 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
197 ElementsAreArray(expectedReadPtr)))
198 .WillOnce(Return(expectedWriteSize));
199 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr));
Brandon Kimc49284b2022-06-17 09:55:26 -0700200
201 auto cachedHeader = bufferImpl->getCachedBufferHeader();
Brandon Kim271d2312022-09-02 16:34:55 +0000202 EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcReadPtr),
203 0x881234);
Brandon Kimc49284b2022-06-17 09:55:26 -0700204}
205
206TEST_F(BufferTest, BufferUpdateBmcFlagsFail)
207{
208 // Return write size that is not 4 which is sizeof(little_uint32_t)
209 constexpr size_t wrongWriteSize = 1;
210 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
211 .WillOnce(Return(wrongWriteSize));
212 EXPECT_THROW(
213 try {
214 bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready));
215 } catch (const std::runtime_error& e) {
216 EXPECT_STREQ(
217 e.what(),
218 "[updateBmcFlags] Wrote '1' bytes, instead of expected '4'");
219 throw;
220 },
221 std::runtime_error);
222}
223
224TEST_F(BufferTest, BufferUpdateBmcFlagsPass)
225{
226 constexpr size_t expectedWriteSize = 4;
Brandon Kim271d2312022-09-02 16:34:55 +0000227 constexpr uint8_t expectedBmcReadPtrOffset = 0x1d;
Brandon Kimc49284b2022-06-17 09:55:26 -0700228 const std::vector<uint8_t> expectedNewBmcFlagsVector{0x04, 0x0, 0x0, 0x00};
229
230 EXPECT_CALL(*dataInterfaceMockPtr,
231 write(expectedBmcReadPtrOffset,
232 ElementsAreArray(expectedNewBmcFlagsVector)))
233 .WillOnce(Return(expectedWriteSize));
234 EXPECT_NO_THROW(
235 bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready)));
236
237 auto cachedHeader = bufferImpl->getCachedBufferHeader();
238 EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcFlags),
239 static_cast<uint32_t>(BmcFlags::ready));
Brandon Kimcf0b9752022-06-15 10:32:21 -0700240}
241
Brandon Kim82ab8322023-08-17 00:50:18 +0000242TEST_F(BufferTest, GetMaxOffsetQueueSizeFail)
243{
244 InSequence s;
245 static constexpr size_t wrongQueueSize = testQueueSize - 1;
246 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
247 .WillOnce(Return(testRegionSize));
248 const std::vector<uint8_t> emptyArray(wrongQueueSize, 0);
249 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
250 .WillOnce(Return(wrongQueueSize));
251
252 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
253 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400254 EXPECT_NO_THROW(
255 bufferImpl->initialize(testBmcInterfaceVersion, wrongQueueSize,
256 testUeRegionSize, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000257 EXPECT_THROW(
258 try {
259 bufferImpl->getMaxOffset();
260 } catch (const std::runtime_error& e) {
261 EXPECT_STREQ(e.what(),
262 "[getMaxOffset] runtime queueSize '511' did not match "
263 "compile-time queueSize '512'. This indicates that the"
264 " buffer was corrupted");
265 throw;
266 },
267 std::runtime_error);
268}
269
270TEST_F(BufferTest, GetMaxOffsetUeRegionSizeFail)
271{
272 InSequence s;
273 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
274 .WillOnce(Return(testRegionSize));
275 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
276 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
277 .WillOnce(Return(testQueueSize));
278
279 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
280 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400281 EXPECT_NO_THROW(
282 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
283 testUeRegionSize + 1, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000284 EXPECT_THROW(
285 try {
286 bufferImpl->getMaxOffset();
287 } catch (const std::runtime_error& e) {
288 EXPECT_STREQ(
289 e.what(),
290 "[getMaxOffset] runtime ueRegionSize '81' did not match "
291 "compile-time ueRegionSize '80'. This indicates that the"
292 " buffer was corrupted");
293 throw;
294 },
295 std::runtime_error);
296}
297
298TEST_F(BufferTest, GetOffsetUeRegionSizeFail)
299{
300 InSequence s;
301 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
302 .WillOnce(Return(testRegionSize));
303 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
304 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
305 .WillOnce(Return(testQueueSize));
306
307 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
308 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400309 EXPECT_NO_THROW(
310 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
311 testUeRegionSize - 1, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000312 EXPECT_THROW(
313 try {
314 bufferImpl->getQueueOffset();
315 } catch (const std::runtime_error& e) {
316 EXPECT_STREQ(
317 e.what(),
318 "[getQueueOffset] runtime ueRegionSize '79' did not match "
319 "compile-time ueRegionSize '80'. This indicates that the"
320 " buffer was corrupted");
321 throw;
322 },
323 std::runtime_error);
324}
325
Brandon Kim9836cfa2022-06-15 11:21:11 -0700326class BufferWraparoundReadTest : public BufferTest
327{
328 protected:
329 BufferWraparoundReadTest()
330 {
Brandon Kim4662b1b2022-06-16 21:38:02 -0700331 initializeFuncMock();
332 }
333 void initializeFuncMock()
334 {
Brandon Kim9836cfa2022-06-15 11:21:11 -0700335 // Initialize the memory and the cachedBufferHeader
336 InSequence s;
337 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
338 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +0000339 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700340 EXPECT_CALL(*dataInterfaceMockPtr,
341 write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000342 .WillOnce(Return(testQueueSize));
Brandon Kim9836cfa2022-06-15 11:21:11 -0700343
Brandon Kim4662b1b2022-06-16 21:38:02 -0700344 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700345 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400346 EXPECT_NO_THROW(
347 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
348 testUeRegionSize, testMagicNumber));
Brandon Kim9836cfa2022-06-15 11:21:11 -0700349 }
Brandon Kim271d2312022-09-02 16:34:55 +0000350 static constexpr size_t expectedWriteSize = 3;
351 static constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700352 static constexpr size_t expectedqueueOffset = 0x30 + testUeRegionSize;
Brandon Kim4662b1b2022-06-16 21:38:02 -0700353
Patrick Williams1a643562024-08-16 15:22:05 -0400354 static constexpr size_t testMaxOffset =
355 testQueueSize - testUeRegionSize - sizeof(struct CircularBufferHeader);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700356 uint8_t* testInitializationHeaderPtr =
357 reinterpret_cast<uint8_t*>(&testInitializationHeader);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700358};
359
Brandon Kim82ab8322023-08-17 00:50:18 +0000360TEST_F(BufferWraparoundReadTest, GetMaxOffsetPassTest)
Brandon Kim3def3c82022-09-13 05:29:20 +0000361{
362 EXPECT_EQ(bufferImpl->getMaxOffset(), testMaxOffset);
363}
364
Brandon Kim82ab8322023-08-17 00:50:18 +0000365TEST_F(BufferWraparoundReadTest, GetQueueOffsetPassTest)
366{
367 EXPECT_EQ(bufferImpl->getQueueOffset(),
368 bufferHeaderSize + testUeRegionSize);
369}
370
Brandon Kim35d43352022-06-16 11:13:36 -0700371TEST_F(BufferWraparoundReadTest, ParamsTooBigFail)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700372{
373 InSequence s;
Brandon Kim3def3c82022-09-13 05:29:20 +0000374 size_t tooBigOffset = testMaxOffset + 1;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700375 EXPECT_THROW(
376 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700377 bufferImpl->wraparoundRead(tooBigOffset, /* length */ 1);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700378 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700379 EXPECT_STREQ(
380 e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +0000381 "[wraparoundRead] relativeOffset '385' was bigger than maxOffset '384'");
Brandon Kim35d43352022-06-16 11:13:36 -0700382 throw;
383 },
384 std::runtime_error);
385
Brandon Kim3def3c82022-09-13 05:29:20 +0000386 size_t tooBigLength = testMaxOffset + 1;
Brandon Kim35d43352022-06-16 11:13:36 -0700387 EXPECT_THROW(
388 try {
389 bufferImpl->wraparoundRead(/* relativeOffset */ 0, tooBigLength);
390 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +0000391 EXPECT_STREQ(e.what(), "[wraparoundRead] length '385' was bigger "
392 "than maxOffset '384'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700393 throw;
394 },
395 std::runtime_error);
396}
397
Brandon Kim35d43352022-06-16 11:13:36 -0700398TEST_F(BufferWraparoundReadTest, NoWrapAroundReadFails)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700399{
400 InSequence s;
Brandon Kim35d43352022-06-16 11:13:36 -0700401 size_t testLength = 0x10;
402 size_t testOffset = 0x20;
403
404 // Fail the first read
405 std::vector<std::uint8_t> shortTestBytesRead(testLength - 1);
406 EXPECT_CALL(*dataInterfaceMockPtr,
407 read(testOffset + expectedqueueOffset, testLength))
408 .WillOnce(Return(shortTestBytesRead));
409
Brandon Kim9836cfa2022-06-15 11:21:11 -0700410 EXPECT_THROW(
411 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700412 bufferImpl->wraparoundRead(testOffset, testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700413 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700414 EXPECT_STREQ(e.what(),
415 "[wraparoundRead] Read '15' which was not the "
416 "requested length of '16'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700417 throw;
418 },
419 std::runtime_error);
420}
421
422TEST_F(BufferWraparoundReadTest, NoWrapAroundReadPass)
423{
424 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700425 size_t testLength = 0x10;
Brandon Kim35d43352022-06-16 11:13:36 -0700426 size_t testOffset = 0x20;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700427
428 // Successfully read all the requested length without a wrap around
429 std::vector<std::uint8_t> testBytesRead(testLength);
Brandon Kim35d43352022-06-16 11:13:36 -0700430 EXPECT_CALL(*dataInterfaceMockPtr,
431 read(testOffset + expectedqueueOffset, testLength))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700432 .WillOnce(Return(testBytesRead));
433
434 // Call to updateReadPtr is triggered
435 const std::vector<uint8_t> expectedReadPtr{
Brandon Kim271d2312022-09-02 16:34:55 +0000436 static_cast<uint8_t>(testOffset + testLength), 0x0, 0x0};
Brandon Kim9836cfa2022-06-15 11:21:11 -0700437 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
438 ElementsAreArray(expectedReadPtr)))
439 .WillOnce(Return(expectedWriteSize));
440
441 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
442 ElementsAreArray(testBytesRead));
Brandon Kim35d43352022-06-16 11:13:36 -0700443 struct CircularBufferHeader cachedBufferHeader =
444 bufferImpl->getCachedBufferHeader();
445 // The bmcReadPtr should have been updated
446 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
447 testOffset + testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700448}
449
450TEST_F(BufferWraparoundReadTest, WrapAroundReadFails)
451{
452 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700453 size_t testBytesLeft = 3;
454 size_t testLength = 0x10;
Brandon Kim3def3c82022-09-13 05:29:20 +0000455 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700456
Brandon Kim35d43352022-06-16 11:13:36 -0700457 // Read until the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700458 std::vector<std::uint8_t> testBytesReadShort(testLength - testBytesLeft);
Brandon Kim35d43352022-06-16 11:13:36 -0700459 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
460 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700461 .WillOnce(Return(testBytesReadShort));
462
463 // Read 1 byte short after wraparound
464 std::vector<std::uint8_t> testBytesLeftReadShort(testBytesLeft - 1);
465 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
466 .WillOnce(Return(testBytesLeftReadShort));
467
468 EXPECT_THROW(
469 try {
470 bufferImpl->wraparoundRead(testOffset, testLength);
471 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700472 EXPECT_STREQ(
473 e.what(),
474 "[wraparoundRead] Buffer wrapped around but read '2' which was "
475 "not the requested lenght of '3'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700476 throw;
477 },
478 std::runtime_error);
479}
480
481TEST_F(BufferWraparoundReadTest, WrapAroundReadPasses)
482{
483 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700484 size_t testBytesLeft = 3;
485 size_t testLength = 0x10;
Brandon Kim3def3c82022-09-13 05:29:20 +0000486 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700487
Brandon Kim35d43352022-06-16 11:13:36 -0700488 // Read to the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700489 std::vector<std::uint8_t> testBytesReadFirst{16, 15, 14, 13, 12, 11, 10,
490 9, 8, 7, 6, 5, 4};
Brandon Kim35d43352022-06-16 11:13:36 -0700491 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
492 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700493 .WillOnce(Return(testBytesReadFirst));
494
495 std::vector<std::uint8_t> testBytesReadSecond{3, 2, 1};
496 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
497 .WillOnce(Return(testBytesReadSecond));
498
499 // Call to updateReadPtr is triggered
500 const std::vector<uint8_t> expectedReadPtr{
Brandon Kim271d2312022-09-02 16:34:55 +0000501 static_cast<uint8_t>(testBytesLeft), 0x0, 0x0};
Brandon Kim9836cfa2022-06-15 11:21:11 -0700502 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
503 ElementsAreArray(expectedReadPtr)))
504 .WillOnce(Return(expectedWriteSize));
505
506 std::vector<std::uint8_t> expectedBytes = {16, 15, 14, 13, 12, 11, 10, 9,
507 8, 7, 6, 5, 4, 3, 2, 1};
508 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
509 ElementsAreArray(expectedBytes));
Brandon Kim35d43352022-06-16 11:13:36 -0700510 struct CircularBufferHeader cachedBufferHeader =
511 bufferImpl->getCachedBufferHeader();
512 // The bmcReadPtr should have been updated to reflect the wraparound
513 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
514 testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700515}
516
Brandon Kim4662b1b2022-06-16 21:38:02 -0700517TEST_F(BufferWraparoundReadTest, WrapAroundCornerCasePass)
518{
519 InSequence s;
520 size_t testBytesLeft = 0;
521 size_t testLength = 4;
Brandon Kim3def3c82022-09-13 05:29:20 +0000522 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700523
524 // Read to the very end of the queue
525 std::vector<std::uint8_t> testBytes{4, 3, 2, 1};
526 EXPECT_CALL(*dataInterfaceMockPtr,
527 read(testOffset + expectedqueueOffset, testLength))
528 .WillOnce(Return(testBytes));
529
530 // Call to updateReadPtr is triggered, since we read to the very end of the
531 // buffer, update the readPtr up around to 0
Brandon Kim271d2312022-09-02 16:34:55 +0000532 const std::vector<uint8_t> expectedReadPtr{0x0, 0x0, 0x0};
Brandon Kim4662b1b2022-06-16 21:38:02 -0700533 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
534 ElementsAreArray(expectedReadPtr)))
535 .WillOnce(Return(expectedWriteSize));
536
537 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
538 ElementsAreArray(testBytes));
539 struct CircularBufferHeader cachedBufferHeader =
540 bufferImpl->getCachedBufferHeader();
541 // The bmcReadPtr should have been updated to reflect the wraparound
542 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
543 0);
544}
545
Brandon Kim40ce08e2022-06-15 16:58:44 -0700546class BufferEntryTest : public BufferWraparoundReadTest
Brandon Kim7bac2d62022-06-07 21:37:51 -0700547{
548 protected:
Brandon Kim40ce08e2022-06-15 16:58:44 -0700549 BufferEntryTest()
Brandon Kim7bac2d62022-06-07 21:37:51 -0700550 {
551 testEntryHeader.sequenceId = testSequenceId;
552 testEntryHeader.entrySize = testEntrySize;
553 testEntryHeader.checksum = testChecksum;
554 testEntryHeader.rdeCommandType = testRdeCommandType;
555 }
Brandon Kim40ce08e2022-06-15 16:58:44 -0700556 ~BufferEntryTest() override = default;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700557
Brandon Kim35d43352022-06-16 11:13:36 -0700558 void wraparoundReadMock(const uint32_t relativeOffset,
559 std::span<std::uint8_t> expetedBytesOutput)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700560 {
Brandon Kim35d43352022-06-16 11:13:36 -0700561 InSequence s;
Brandon Kim3def3c82022-09-13 05:29:20 +0000562 const uint32_t queueSizeToQueueEnd = testMaxOffset - relativeOffset;
Brandon Kim35d43352022-06-16 11:13:36 -0700563
564 // This will wrap, split the read mocks in 2
565 if (expetedBytesOutput.size() > queueSizeToQueueEnd)
566 {
567 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
568 .WillOnce(Return(std::vector<std::uint8_t>(
569 expetedBytesOutput.begin(),
570 expetedBytesOutput.begin() + queueSizeToQueueEnd)));
571 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
572 .WillOnce(Return(std::vector<std::uint8_t>(
573 expetedBytesOutput.begin() + queueSizeToQueueEnd,
574 expetedBytesOutput.end())));
575 }
576 else
577 {
578 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
579 .WillOnce(Return(std::vector<std::uint8_t>(
580 expetedBytesOutput.begin(), expetedBytesOutput.end())));
581 }
Brandon Kim7bac2d62022-06-07 21:37:51 -0700582
583 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
584 .WillOnce(Return(expectedWriteSize));
585 }
586
587 static constexpr size_t entryHeaderSize = sizeof(struct QueueEntryHeader);
588 static constexpr uint16_t testSequenceId = 0;
589 static constexpr uint16_t testEntrySize = 0x20;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700590 static constexpr uint8_t testRdeCommandType = 0x01;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700591 // Calculated checksum for the header
592 static constexpr uint8_t testChecksum =
593 (testSequenceId ^ testEntrySize ^ testRdeCommandType);
Brandon Kim613ba532022-09-12 20:55:21 +0000594 size_t testOffset = 0x0;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700595
Patrick Williamsc20d1212024-12-18 11:22:36 -0500596 struct QueueEntryHeader testEntryHeader{};
Brandon Kim7bac2d62022-06-07 21:37:51 -0700597};
598
Brandon Kim40ce08e2022-06-15 16:58:44 -0700599TEST_F(BufferEntryTest, ReadEntryHeaderPass)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700600{
601 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
602 std::vector<uint8_t> testEntryHeaderVector(
603 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700604 wraparoundReadMock(testOffset, testEntryHeaderVector);
Brandon Kim613ba532022-09-12 20:55:21 +0000605 EXPECT_EQ(bufferImpl->readEntryHeader(), testEntryHeader);
Brandon Kim35d43352022-06-16 11:13:36 -0700606 // Check the bmcReadPtr
607 struct CircularBufferHeader cachedBufferHeader =
608 bufferImpl->getCachedBufferHeader();
609 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
610 testOffset + testEntryHeaderVector.size());
Brandon Kim7bac2d62022-06-07 21:37:51 -0700611}
612
Brandon Kim40ce08e2022-06-15 16:58:44 -0700613TEST_F(BufferEntryTest, ReadEntryChecksumFail)
614{
615 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700616 std::vector<uint8_t> testEntryVector(testEntrySize);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700617 // Offset the checksum by 1
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700618 testEntryHeader.checksum += 1;
Brandon Kim40ce08e2022-06-15 16:58:44 -0700619 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
620 std::vector<uint8_t> testEntryHeaderVector(
621 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700622 wraparoundReadMock(testOffset, testEntryHeaderVector);
623 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700624 EXPECT_THROW(
Brandon Kim613ba532022-09-12 20:55:21 +0000625 try { bufferImpl->readEntry(); } catch (const std::runtime_error& e) {
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700626 // Calculation: testChecksum (0x21) XOR (0x22) = 3
Brandon Kim40ce08e2022-06-15 16:58:44 -0700627 EXPECT_STREQ(e.what(),
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700628 "[readEntry] Checksum was '3', expected '0'");
Brandon Kim40ce08e2022-06-15 16:58:44 -0700629 throw;
630 },
631 std::runtime_error);
632}
633
Brandon Kim613ba532022-09-12 20:55:21 +0000634TEST_F(BufferEntryTest, ReadEntryPassWraparound)
Brandon Kim40ce08e2022-06-15 16:58:44 -0700635{
636 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700637 // We expect this will bump checksum up by "testEntrySize" = 0xff ^ 0xff ...
638 // (20 times) = 0 therefore leave the checksum as is
Brandon Kim35d43352022-06-16 11:13:36 -0700639 std::vector<uint8_t> testEntryVector(testEntrySize, 0xff);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700640 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
641 std::vector<uint8_t> testEntryHeaderVector(
642 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim613ba532022-09-12 20:55:21 +0000643 // Set testOffset so that we can test the wraparound here at the header and
644 // update the readPtr
Brandon Kim3def3c82022-09-13 05:29:20 +0000645 testOffset = testMaxOffset - 1;
Brandon Kim613ba532022-09-12 20:55:21 +0000646 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
647 .WillOnce(Return(expectedWriteSize));
648 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
649
Brandon Kim35d43352022-06-16 11:13:36 -0700650 wraparoundReadMock(testOffset, testEntryHeaderVector);
651 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700652
653 EntryPair testedEntryPair;
Brandon Kim613ba532022-09-12 20:55:21 +0000654 EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
Brandon Kim40ce08e2022-06-15 16:58:44 -0700655 EXPECT_EQ(testedEntryPair.first, testEntryHeader);
656 EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
Brandon Kim35d43352022-06-16 11:13:36 -0700657 struct CircularBufferHeader cachedBufferHeader =
658 bufferImpl->getCachedBufferHeader();
659 // The bmcReadPtr should have been updated to reflect the wraparound
660 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
Brandon Kim613ba532022-09-12 20:55:21 +0000661 entryHeaderSize + testEntrySize - 1);
662
663 // Set testOffset so that we can test the wraparound here as well on our
664 // second read for the entry (by 1 byte)
Brandon Kim3def3c82022-09-13 05:29:20 +0000665 testOffset = testMaxOffset - entryHeaderSize - 1;
Brandon Kim613ba532022-09-12 20:55:21 +0000666 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
667 .WillOnce(Return(expectedWriteSize));
668 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
669
670 wraparoundReadMock(testOffset, testEntryHeaderVector);
671 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
672
673 EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
674 EXPECT_EQ(testedEntryPair.first, testEntryHeader);
675 EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
676 cachedBufferHeader = bufferImpl->getCachedBufferHeader();
677 // The bmcReadPtr should have been updated to reflect the wraparound
678 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
Brandon Kim35d43352022-06-16 11:13:36 -0700679 testEntrySize - 1);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700680}
681
Brandon Kim4662b1b2022-06-16 21:38:02 -0700682class BufferReadErrorLogsTest : public BufferEntryTest
683{
684 protected:
685 BufferReadErrorLogsTest() = default;
686
687 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
688 size_t entryAndHeaderSize = entryHeaderSize + testEntrySize;
689};
690
691TEST_F(BufferReadErrorLogsTest, PtrsTooBigFail)
692{
693 InSequence s;
694 // Set the biosWritePtr too big
695 testInitializationHeader.biosWritePtr =
Brandon Kim3def3c82022-09-13 05:29:20 +0000696 boost::endian::native_to_little((testMaxOffset + 1));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700697 initializeFuncMock();
698
699 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400700 .WillOnce(Return(std::vector<uint8_t>(
701 testInitializationHeaderPtr,
702 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700703 EXPECT_THROW(
704 try {
705 bufferImpl->readErrorLogs();
706 } catch (const std::runtime_error& e) {
707 EXPECT_STREQ(e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +0000708 "[readErrorLogs] currentBiosWritePtr was '385' "
709 "which was bigger than maxOffset '384'");
Brandon Kim4662b1b2022-06-16 21:38:02 -0700710 throw;
711 },
712 std::runtime_error);
713
714 // Reset the biosWritePtr and set the bmcReadPtr too big
715 testInitializationHeader.biosWritePtr = 0;
716 initializeFuncMock();
717 testInitializationHeader.bmcReadPtr =
Brandon Kim3def3c82022-09-13 05:29:20 +0000718 boost::endian::native_to_little((testMaxOffset + 1));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700719 initializeFuncMock();
720
721 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400722 .WillOnce(Return(std::vector<uint8_t>(
723 testInitializationHeaderPtr,
724 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700725 EXPECT_THROW(
726 try {
727 bufferImpl->readErrorLogs();
728 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +0000729 EXPECT_STREQ(e.what(), "[readErrorLogs] currentReadPtr was '385' "
730 "which was bigger than maxOffset '384'");
Brandon Kim4662b1b2022-06-16 21:38:02 -0700731 throw;
732 },
733 std::runtime_error);
734}
735
736TEST_F(BufferReadErrorLogsTest, IdenticalPtrsPass)
737{
738 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400739 .WillOnce(Return(std::vector<uint8_t>(
740 testInitializationHeaderPtr,
741 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700742 EXPECT_NO_THROW(bufferImpl->readErrorLogs());
743}
744
745TEST_F(BufferReadErrorLogsTest, NoWraparoundPass)
746{
747 InSequence s;
748 // Set the biosWritePtr to 1 entryHeader + entry size
749 testInitializationHeader.biosWritePtr =
750 boost::endian::native_to_little((entryAndHeaderSize));
751 initializeFuncMock();
752 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400753 .WillOnce(Return(std::vector<uint8_t>(
754 testInitializationHeaderPtr,
755 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700756 std::vector<uint8_t> testEntryHeaderVector(
757 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
758 std::vector<uint8_t> testEntryVector(testEntrySize);
759 wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
760 wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
761
762 std::vector<EntryPair> entryPairs;
763 EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
764
765 // Check that we only read one entryPair and that the content is correct
Brandon Kim1a3dc602022-06-17 11:34:33 -0700766 EXPECT_EQ(entryPairs.size(), 1U);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700767 EXPECT_EQ(entryPairs[0].first, testEntryHeader);
768 EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
769}
770
771TEST_F(BufferReadErrorLogsTest, WraparoundMultiplEntryPass)
772{
773 InSequence s;
774 // Set the bmcReadPtr to 1 entryHeader + entry size from the "end" exactly
Brandon Kim3def3c82022-09-13 05:29:20 +0000775 uint32_t entryAndHeaderSizeAwayFromEnd = testMaxOffset - entryAndHeaderSize;
Brandon Kim4662b1b2022-06-16 21:38:02 -0700776 testInitializationHeader.bmcReadPtr =
777 boost::endian::native_to_little(entryAndHeaderSizeAwayFromEnd);
778 // Set the biosWritePtr to 1 entryHeader + entry size from the "beginning"
779 testInitializationHeader.biosWritePtr = entryAndHeaderSize;
780 initializeFuncMock();
781 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400782 .WillOnce(Return(std::vector<uint8_t>(
783 testInitializationHeaderPtr,
784 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700785
786 std::vector<uint8_t> testEntryHeaderVector(
787 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
788 std::vector<uint8_t> testEntryVector(testEntrySize);
789 wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd,
790 testEntryHeaderVector);
791 wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd +
792 entryHeaderSize,
793 testEntryVector);
794 wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize,
795 testEntryHeaderVector);
796 wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize +
797 entryHeaderSize,
798 testEntryVector);
799
800 std::vector<EntryPair> entryPairs;
801 EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
802
803 // Check that we only read one entryPair and that the content is correct
804 EXPECT_EQ(entryPairs.size(), 2);
805 EXPECT_EQ(entryPairs[0].first, testEntryHeader);
806 EXPECT_EQ(entryPairs[1].first, testEntryHeader);
807 EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
808 EXPECT_THAT(entryPairs[1].second, ElementsAreArray(testEntryVector));
809}
810
811TEST_F(BufferReadErrorLogsTest, WraparoundMismatchingPtrsFail)
812{
813 InSequence s;
814 testInitializationHeader.bmcReadPtr = boost::endian::native_to_little(0);
815 // Make the biosWritePtr intentially 1 smaller than expected
816 testInitializationHeader.biosWritePtr =
817 boost::endian::native_to_little(entryAndHeaderSize - 1);
818 initializeFuncMock();
819 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400820 .WillOnce(Return(std::vector<uint8_t>(
821 testInitializationHeaderPtr,
822 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700823
824 std::vector<uint8_t> testEntryHeaderVector(
825 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
826 std::vector<uint8_t> testEntryVector(testEntrySize);
827 wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
828 wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
829
830 EXPECT_THROW(
831 try {
832 bufferImpl->readErrorLogs();
833 } catch (const std::runtime_error& e) {
834 EXPECT_STREQ(
835 e.what(),
836 "[readErrorLogs] biosWritePtr '37' and bmcReaddPtr '38' "
837 "are not identical after reading through all the logs");
838 throw;
839 },
840 std::runtime_error);
841}
842
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700843} // namespace
844} // namespace bios_bmc_smm_error_logger