blob: 3c8007abac36b347965264d91f28f5a6513c9f2f [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
Brandon Kimfcbc3db2022-06-06 21:26:18 -070054 struct CircularBufferHeader testInitializationHeader
55 {};
56
57 std::unique_ptr<DataInterfaceMock> dataInterfaceMock;
58 DataInterfaceMock* dataInterfaceMockPtr;
Brandon Kimfcbc3db2022-06-06 21:26:18 -070059 std::unique_ptr<BufferImpl> bufferImpl;
60};
61
62TEST_F(BufferTest, BufferInitializeEraseFail)
63{
64 InSequence s;
Brandon Kim26660e92022-06-15 16:58:44 -070065 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
66 .WillOnce(Return(testRegionSize));
67 EXPECT_THROW(
68 try {
69 // Test too big of a proposed buffer compared to the memori size
Brandon Kim3def3c82022-09-13 05:29:20 +000070 uint16_t bigQueueSize = 0x201;
Brandon Kim26660e92022-06-15 16:58:44 -070071 uint16_t bigUeRegionSize = 0x50;
72 bufferImpl->initialize(testBmcInterfaceVersion, bigQueueSize,
73 bigUeRegionSize, testMagicNumber);
74 } catch (const std::runtime_error& e) {
75 EXPECT_STREQ(
76 e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +000077 "[initialize] Proposed queue size '513' is bigger than the BMC's allocated MMIO region of '512'");
Brandon Kim26660e92022-06-15 16:58:44 -070078 throw;
79 },
80 std::runtime_error);
81 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070082
83 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
84 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +000085 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070086 // Return a smaller write than the intended testRegionSize to test the error
87 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +000088 .WillOnce(Return(testQueueSize - 1));
Brandon Kimfcbc3db2022-06-06 21:26:18 -070089 EXPECT_THROW(
90 try {
91 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
92 testUeRegionSize, testMagicNumber);
93 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +000094 EXPECT_STREQ(e.what(), "[initialize] Only erased '511'");
Brandon Kimfcbc3db2022-06-06 21:26:18 -070095 throw;
96 },
97 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -070098 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -070099
100 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
101 .WillOnce(Return(testRegionSize));
102 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000103 .WillOnce(Return(testQueueSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700104 // Return a smaller write than the intended initializationHeader to test the
105 // error
106 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0));
107 EXPECT_THROW(
108 try {
109 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
110 testUeRegionSize, testMagicNumber);
111 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700112 EXPECT_STREQ(e.what(),
113 "[initialize] Only wrote '0' bytes of the header");
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700114 throw;
115 },
116 std::runtime_error);
Brandon Kim60cab572022-06-15 14:20:05 -0700117 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700118}
119
120TEST_F(BufferTest, BufferInitializePass)
121{
122 InSequence s;
123 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
124 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +0000125 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700126 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000127 .WillOnce(Return(testQueueSize));
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700128
129 uint8_t* testInitializationHeaderPtr =
130 reinterpret_cast<uint8_t*>(&testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700131 EXPECT_CALL(*dataInterfaceMockPtr,
132 write(0, ElementsAreArray(testInitializationHeaderPtr,
Brandon Kim17ee1a92022-06-07 21:04:08 -0700133 bufferHeaderSize)))
134 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400135 EXPECT_NO_THROW(
136 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
137 testUeRegionSize, testMagicNumber));
Brandon Kim60cab572022-06-15 14:20:05 -0700138 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700139}
140
Brandon Kim17ee1a92022-06-07 21:04:08 -0700141TEST_F(BufferTest, BufferHeaderReadFail)
142{
143 std::vector<std::uint8_t> testBytesRead{};
144 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
145 .WillOnce(Return(testBytesRead));
146 EXPECT_THROW(
147 try {
148 bufferImpl->readBufferHeader();
149 } catch (const std::runtime_error& e) {
150 EXPECT_STREQ(e.what(),
151 "Buffer header read only read '0', expected '48'");
152 throw;
153 },
154 std::runtime_error);
155}
156
157TEST_F(BufferTest, BufferHeaderReadPass)
158{
159 uint8_t* testInitializationHeaderPtr =
160 reinterpret_cast<uint8_t*>(&testInitializationHeader);
161 std::vector<uint8_t> testInitializationHeaderVector(
162 testInitializationHeaderPtr,
163 testInitializationHeaderPtr + bufferHeaderSize);
164
165 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
166 .WillOnce(Return(testInitializationHeaderVector));
167 EXPECT_NO_THROW(bufferImpl->readBufferHeader());
168 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
169}
170
Brandon Kimcf0b9752022-06-15 10:32:21 -0700171TEST_F(BufferTest, BufferUpdateReadPtrFail)
172{
173 // Return write size that is not 2 which is sizeof(little_uint16_t)
174 constexpr size_t wrongWriteSize = 1;
175 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
176 .WillOnce(Return(wrongWriteSize));
177 EXPECT_THROW(
178 try {
179 bufferImpl->updateReadPtr(0);
180 } catch (const std::runtime_error& e) {
181 EXPECT_STREQ(
182 e.what(),
Brandon Kim271d2312022-09-02 16:34:55 +0000183 "[updateReadPtr] Wrote '1' bytes, instead of expected '3'");
Brandon Kimcf0b9752022-06-15 10:32:21 -0700184 throw;
185 },
186 std::runtime_error);
187}
188
189TEST_F(BufferTest, BufferUpdateReadPtrPass)
190{
Brandon Kim271d2312022-09-02 16:34:55 +0000191 constexpr size_t expectedWriteSize = 3;
192 constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
193 // Check that we truncate the highest 24bits
Brandon Kimcf0b9752022-06-15 10:32:21 -0700194 const uint32_t testNewReadPtr = 0x99881234;
Brandon Kim271d2312022-09-02 16:34:55 +0000195 const std::vector<uint8_t> expectedReadPtr{0x34, 0x12, 0x88};
Brandon Kimcf0b9752022-06-15 10:32:21 -0700196
197 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
198 ElementsAreArray(expectedReadPtr)))
199 .WillOnce(Return(expectedWriteSize));
200 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr));
Brandon Kimc49284b2022-06-17 09:55:26 -0700201
202 auto cachedHeader = bufferImpl->getCachedBufferHeader();
Brandon Kim271d2312022-09-02 16:34:55 +0000203 EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcReadPtr),
204 0x881234);
Brandon Kimc49284b2022-06-17 09:55:26 -0700205}
206
207TEST_F(BufferTest, BufferUpdateBmcFlagsFail)
208{
209 // Return write size that is not 4 which is sizeof(little_uint32_t)
210 constexpr size_t wrongWriteSize = 1;
211 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
212 .WillOnce(Return(wrongWriteSize));
213 EXPECT_THROW(
214 try {
215 bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready));
216 } catch (const std::runtime_error& e) {
217 EXPECT_STREQ(
218 e.what(),
219 "[updateBmcFlags] Wrote '1' bytes, instead of expected '4'");
220 throw;
221 },
222 std::runtime_error);
223}
224
225TEST_F(BufferTest, BufferUpdateBmcFlagsPass)
226{
227 constexpr size_t expectedWriteSize = 4;
Brandon Kim271d2312022-09-02 16:34:55 +0000228 constexpr uint8_t expectedBmcReadPtrOffset = 0x1d;
Brandon Kimc49284b2022-06-17 09:55:26 -0700229 const std::vector<uint8_t> expectedNewBmcFlagsVector{0x04, 0x0, 0x0, 0x00};
230
231 EXPECT_CALL(*dataInterfaceMockPtr,
232 write(expectedBmcReadPtrOffset,
233 ElementsAreArray(expectedNewBmcFlagsVector)))
234 .WillOnce(Return(expectedWriteSize));
235 EXPECT_NO_THROW(
236 bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready)));
237
238 auto cachedHeader = bufferImpl->getCachedBufferHeader();
239 EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcFlags),
240 static_cast<uint32_t>(BmcFlags::ready));
Brandon Kimcf0b9752022-06-15 10:32:21 -0700241}
242
Brandon Kim82ab8322023-08-17 00:50:18 +0000243TEST_F(BufferTest, GetMaxOffsetQueueSizeFail)
244{
245 InSequence s;
246 static constexpr size_t wrongQueueSize = testQueueSize - 1;
247 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
248 .WillOnce(Return(testRegionSize));
249 const std::vector<uint8_t> emptyArray(wrongQueueSize, 0);
250 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
251 .WillOnce(Return(wrongQueueSize));
252
253 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
254 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400255 EXPECT_NO_THROW(
256 bufferImpl->initialize(testBmcInterfaceVersion, wrongQueueSize,
257 testUeRegionSize, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000258 EXPECT_THROW(
259 try {
260 bufferImpl->getMaxOffset();
261 } catch (const std::runtime_error& e) {
262 EXPECT_STREQ(e.what(),
263 "[getMaxOffset] runtime queueSize '511' did not match "
264 "compile-time queueSize '512'. This indicates that the"
265 " buffer was corrupted");
266 throw;
267 },
268 std::runtime_error);
269}
270
271TEST_F(BufferTest, GetMaxOffsetUeRegionSizeFail)
272{
273 InSequence s;
274 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
275 .WillOnce(Return(testRegionSize));
276 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
277 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
278 .WillOnce(Return(testQueueSize));
279
280 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
281 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400282 EXPECT_NO_THROW(
283 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
284 testUeRegionSize + 1, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000285 EXPECT_THROW(
286 try {
287 bufferImpl->getMaxOffset();
288 } catch (const std::runtime_error& e) {
289 EXPECT_STREQ(
290 e.what(),
291 "[getMaxOffset] runtime ueRegionSize '81' did not match "
292 "compile-time ueRegionSize '80'. This indicates that the"
293 " buffer was corrupted");
294 throw;
295 },
296 std::runtime_error);
297}
298
299TEST_F(BufferTest, GetOffsetUeRegionSizeFail)
300{
301 InSequence s;
302 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
303 .WillOnce(Return(testRegionSize));
304 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
305 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
306 .WillOnce(Return(testQueueSize));
307
308 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
309 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400310 EXPECT_NO_THROW(
311 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
312 testUeRegionSize - 1, testMagicNumber));
Brandon Kim82ab8322023-08-17 00:50:18 +0000313 EXPECT_THROW(
314 try {
315 bufferImpl->getQueueOffset();
316 } catch (const std::runtime_error& e) {
317 EXPECT_STREQ(
318 e.what(),
319 "[getQueueOffset] runtime ueRegionSize '79' did not match "
320 "compile-time ueRegionSize '80'. This indicates that the"
321 " buffer was corrupted");
322 throw;
323 },
324 std::runtime_error);
325}
326
Brandon Kim9836cfa2022-06-15 11:21:11 -0700327class BufferWraparoundReadTest : public BufferTest
328{
329 protected:
330 BufferWraparoundReadTest()
331 {
Brandon Kim4662b1b2022-06-16 21:38:02 -0700332 initializeFuncMock();
333 }
334 void initializeFuncMock()
335 {
Brandon Kim9836cfa2022-06-15 11:21:11 -0700336 // Initialize the memory and the cachedBufferHeader
337 InSequence s;
338 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
339 .WillOnce(Return(testRegionSize));
Brandon Kim3def3c82022-09-13 05:29:20 +0000340 const std::vector<uint8_t> emptyArray(testQueueSize, 0);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700341 EXPECT_CALL(*dataInterfaceMockPtr,
342 write(0, ElementsAreArray(emptyArray)))
Brandon Kim3def3c82022-09-13 05:29:20 +0000343 .WillOnce(Return(testQueueSize));
Brandon Kim9836cfa2022-06-15 11:21:11 -0700344
Brandon Kim4662b1b2022-06-16 21:38:02 -0700345 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700346 .WillOnce(Return(bufferHeaderSize));
Patrick Williams1a643562024-08-16 15:22:05 -0400347 EXPECT_NO_THROW(
348 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
349 testUeRegionSize, testMagicNumber));
Brandon Kim9836cfa2022-06-15 11:21:11 -0700350 }
Brandon Kim271d2312022-09-02 16:34:55 +0000351 static constexpr size_t expectedWriteSize = 3;
352 static constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700353 static constexpr size_t expectedqueueOffset = 0x30 + testUeRegionSize;
Brandon Kim4662b1b2022-06-16 21:38:02 -0700354
Patrick Williams1a643562024-08-16 15:22:05 -0400355 static constexpr size_t testMaxOffset =
356 testQueueSize - testUeRegionSize - sizeof(struct CircularBufferHeader);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700357 uint8_t* testInitializationHeaderPtr =
358 reinterpret_cast<uint8_t*>(&testInitializationHeader);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700359};
360
Brandon Kim82ab8322023-08-17 00:50:18 +0000361TEST_F(BufferWraparoundReadTest, GetMaxOffsetPassTest)
Brandon Kim3def3c82022-09-13 05:29:20 +0000362{
363 EXPECT_EQ(bufferImpl->getMaxOffset(), testMaxOffset);
364}
365
Brandon Kim82ab8322023-08-17 00:50:18 +0000366TEST_F(BufferWraparoundReadTest, GetQueueOffsetPassTest)
367{
368 EXPECT_EQ(bufferImpl->getQueueOffset(),
369 bufferHeaderSize + testUeRegionSize);
370}
371
Brandon Kim35d43352022-06-16 11:13:36 -0700372TEST_F(BufferWraparoundReadTest, ParamsTooBigFail)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700373{
374 InSequence s;
Brandon Kim3def3c82022-09-13 05:29:20 +0000375 size_t tooBigOffset = testMaxOffset + 1;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700376 EXPECT_THROW(
377 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700378 bufferImpl->wraparoundRead(tooBigOffset, /* length */ 1);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700379 } catch (const std::runtime_error& e) {
Brandon Kim26660e92022-06-15 16:58:44 -0700380 EXPECT_STREQ(
381 e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +0000382 "[wraparoundRead] relativeOffset '385' was bigger than maxOffset '384'");
Brandon Kim35d43352022-06-16 11:13:36 -0700383 throw;
384 },
385 std::runtime_error);
386
Brandon Kim3def3c82022-09-13 05:29:20 +0000387 size_t tooBigLength = testMaxOffset + 1;
Brandon Kim35d43352022-06-16 11:13:36 -0700388 EXPECT_THROW(
389 try {
390 bufferImpl->wraparoundRead(/* relativeOffset */ 0, tooBigLength);
391 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +0000392 EXPECT_STREQ(e.what(), "[wraparoundRead] length '385' was bigger "
393 "than maxOffset '384'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700394 throw;
395 },
396 std::runtime_error);
397}
398
Brandon Kim35d43352022-06-16 11:13:36 -0700399TEST_F(BufferWraparoundReadTest, NoWrapAroundReadFails)
Brandon Kim9836cfa2022-06-15 11:21:11 -0700400{
401 InSequence s;
Brandon Kim35d43352022-06-16 11:13:36 -0700402 size_t testLength = 0x10;
403 size_t testOffset = 0x20;
404
405 // Fail the first read
406 std::vector<std::uint8_t> shortTestBytesRead(testLength - 1);
407 EXPECT_CALL(*dataInterfaceMockPtr,
408 read(testOffset + expectedqueueOffset, testLength))
409 .WillOnce(Return(shortTestBytesRead));
410
Brandon Kim9836cfa2022-06-15 11:21:11 -0700411 EXPECT_THROW(
412 try {
Brandon Kim35d43352022-06-16 11:13:36 -0700413 bufferImpl->wraparoundRead(testOffset, testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700414 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700415 EXPECT_STREQ(e.what(),
416 "[wraparoundRead] Read '15' which was not the "
417 "requested length of '16'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700418 throw;
419 },
420 std::runtime_error);
421}
422
423TEST_F(BufferWraparoundReadTest, NoWrapAroundReadPass)
424{
425 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700426 size_t testLength = 0x10;
Brandon Kim35d43352022-06-16 11:13:36 -0700427 size_t testOffset = 0x20;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700428
429 // Successfully read all the requested length without a wrap around
430 std::vector<std::uint8_t> testBytesRead(testLength);
Brandon Kim35d43352022-06-16 11:13:36 -0700431 EXPECT_CALL(*dataInterfaceMockPtr,
432 read(testOffset + expectedqueueOffset, testLength))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700433 .WillOnce(Return(testBytesRead));
434
435 // Call to updateReadPtr is triggered
436 const std::vector<uint8_t> expectedReadPtr{
Brandon Kim271d2312022-09-02 16:34:55 +0000437 static_cast<uint8_t>(testOffset + testLength), 0x0, 0x0};
Brandon Kim9836cfa2022-06-15 11:21:11 -0700438 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
439 ElementsAreArray(expectedReadPtr)))
440 .WillOnce(Return(expectedWriteSize));
441
442 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
443 ElementsAreArray(testBytesRead));
Brandon Kim35d43352022-06-16 11:13:36 -0700444 struct CircularBufferHeader cachedBufferHeader =
445 bufferImpl->getCachedBufferHeader();
446 // The bmcReadPtr should have been updated
447 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
448 testOffset + testLength);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700449}
450
451TEST_F(BufferWraparoundReadTest, WrapAroundReadFails)
452{
453 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700454 size_t testBytesLeft = 3;
455 size_t testLength = 0x10;
Brandon Kim3def3c82022-09-13 05:29:20 +0000456 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700457
Brandon Kim35d43352022-06-16 11:13:36 -0700458 // Read until the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700459 std::vector<std::uint8_t> testBytesReadShort(testLength - testBytesLeft);
Brandon Kim35d43352022-06-16 11:13:36 -0700460 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
461 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700462 .WillOnce(Return(testBytesReadShort));
463
464 // Read 1 byte short after wraparound
465 std::vector<std::uint8_t> testBytesLeftReadShort(testBytesLeft - 1);
466 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
467 .WillOnce(Return(testBytesLeftReadShort));
468
469 EXPECT_THROW(
470 try {
471 bufferImpl->wraparoundRead(testOffset, testLength);
472 } catch (const std::runtime_error& e) {
Brandon Kim35d43352022-06-16 11:13:36 -0700473 EXPECT_STREQ(
474 e.what(),
475 "[wraparoundRead] Buffer wrapped around but read '2' which was "
476 "not the requested lenght of '3'");
Brandon Kim9836cfa2022-06-15 11:21:11 -0700477 throw;
478 },
479 std::runtime_error);
480}
481
482TEST_F(BufferWraparoundReadTest, WrapAroundReadPasses)
483{
484 InSequence s;
Brandon Kim9836cfa2022-06-15 11:21:11 -0700485 size_t testBytesLeft = 3;
486 size_t testLength = 0x10;
Brandon Kim3def3c82022-09-13 05:29:20 +0000487 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700488
Brandon Kim35d43352022-06-16 11:13:36 -0700489 // Read to the end of the queue
Brandon Kim9836cfa2022-06-15 11:21:11 -0700490 std::vector<std::uint8_t> testBytesReadFirst{16, 15, 14, 13, 12, 11, 10,
491 9, 8, 7, 6, 5, 4};
Brandon Kim35d43352022-06-16 11:13:36 -0700492 EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
493 testLength - testBytesLeft))
Brandon Kim9836cfa2022-06-15 11:21:11 -0700494 .WillOnce(Return(testBytesReadFirst));
495
496 std::vector<std::uint8_t> testBytesReadSecond{3, 2, 1};
497 EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
498 .WillOnce(Return(testBytesReadSecond));
499
500 // Call to updateReadPtr is triggered
501 const std::vector<uint8_t> expectedReadPtr{
Brandon Kim271d2312022-09-02 16:34:55 +0000502 static_cast<uint8_t>(testBytesLeft), 0x0, 0x0};
Brandon Kim9836cfa2022-06-15 11:21:11 -0700503 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
504 ElementsAreArray(expectedReadPtr)))
505 .WillOnce(Return(expectedWriteSize));
506
507 std::vector<std::uint8_t> expectedBytes = {16, 15, 14, 13, 12, 11, 10, 9,
508 8, 7, 6, 5, 4, 3, 2, 1};
509 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
510 ElementsAreArray(expectedBytes));
Brandon Kim35d43352022-06-16 11:13:36 -0700511 struct CircularBufferHeader cachedBufferHeader =
512 bufferImpl->getCachedBufferHeader();
513 // The bmcReadPtr should have been updated to reflect the wraparound
514 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
515 testBytesLeft);
Brandon Kim9836cfa2022-06-15 11:21:11 -0700516}
517
Brandon Kim4662b1b2022-06-16 21:38:02 -0700518TEST_F(BufferWraparoundReadTest, WrapAroundCornerCasePass)
519{
520 InSequence s;
521 size_t testBytesLeft = 0;
522 size_t testLength = 4;
Brandon Kim3def3c82022-09-13 05:29:20 +0000523 size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700524
525 // Read to the very end of the queue
526 std::vector<std::uint8_t> testBytes{4, 3, 2, 1};
527 EXPECT_CALL(*dataInterfaceMockPtr,
528 read(testOffset + expectedqueueOffset, testLength))
529 .WillOnce(Return(testBytes));
530
531 // Call to updateReadPtr is triggered, since we read to the very end of the
532 // buffer, update the readPtr up around to 0
Brandon Kim271d2312022-09-02 16:34:55 +0000533 const std::vector<uint8_t> expectedReadPtr{0x0, 0x0, 0x0};
Brandon Kim4662b1b2022-06-16 21:38:02 -0700534 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
535 ElementsAreArray(expectedReadPtr)))
536 .WillOnce(Return(expectedWriteSize));
537
538 EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
539 ElementsAreArray(testBytes));
540 struct CircularBufferHeader cachedBufferHeader =
541 bufferImpl->getCachedBufferHeader();
542 // The bmcReadPtr should have been updated to reflect the wraparound
543 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
544 0);
545}
546
Brandon Kim40ce08e2022-06-15 16:58:44 -0700547class BufferEntryTest : public BufferWraparoundReadTest
Brandon Kim7bac2d62022-06-07 21:37:51 -0700548{
549 protected:
Brandon Kim40ce08e2022-06-15 16:58:44 -0700550 BufferEntryTest()
Brandon Kim7bac2d62022-06-07 21:37:51 -0700551 {
552 testEntryHeader.sequenceId = testSequenceId;
553 testEntryHeader.entrySize = testEntrySize;
554 testEntryHeader.checksum = testChecksum;
555 testEntryHeader.rdeCommandType = testRdeCommandType;
556 }
Brandon Kim40ce08e2022-06-15 16:58:44 -0700557 ~BufferEntryTest() override = default;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700558
Brandon Kim35d43352022-06-16 11:13:36 -0700559 void wraparoundReadMock(const uint32_t relativeOffset,
560 std::span<std::uint8_t> expetedBytesOutput)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700561 {
Brandon Kim35d43352022-06-16 11:13:36 -0700562 InSequence s;
Brandon Kim3def3c82022-09-13 05:29:20 +0000563 const uint32_t queueSizeToQueueEnd = testMaxOffset - relativeOffset;
Brandon Kim35d43352022-06-16 11:13:36 -0700564
565 // This will wrap, split the read mocks in 2
566 if (expetedBytesOutput.size() > queueSizeToQueueEnd)
567 {
568 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
569 .WillOnce(Return(std::vector<std::uint8_t>(
570 expetedBytesOutput.begin(),
571 expetedBytesOutput.begin() + queueSizeToQueueEnd)));
572 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
573 .WillOnce(Return(std::vector<std::uint8_t>(
574 expetedBytesOutput.begin() + queueSizeToQueueEnd,
575 expetedBytesOutput.end())));
576 }
577 else
578 {
579 EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
580 .WillOnce(Return(std::vector<std::uint8_t>(
581 expetedBytesOutput.begin(), expetedBytesOutput.end())));
582 }
Brandon Kim7bac2d62022-06-07 21:37:51 -0700583
584 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
585 .WillOnce(Return(expectedWriteSize));
586 }
587
588 static constexpr size_t entryHeaderSize = sizeof(struct QueueEntryHeader);
589 static constexpr uint16_t testSequenceId = 0;
590 static constexpr uint16_t testEntrySize = 0x20;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700591 static constexpr uint8_t testRdeCommandType = 0x01;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700592 // Calculated checksum for the header
593 static constexpr uint8_t testChecksum =
594 (testSequenceId ^ testEntrySize ^ testRdeCommandType);
Brandon Kim613ba532022-09-12 20:55:21 +0000595 size_t testOffset = 0x0;
Brandon Kim7bac2d62022-06-07 21:37:51 -0700596
597 struct QueueEntryHeader testEntryHeader
598 {};
599};
600
Brandon Kim40ce08e2022-06-15 16:58:44 -0700601TEST_F(BufferEntryTest, ReadEntryHeaderPass)
Brandon Kim7bac2d62022-06-07 21:37:51 -0700602{
603 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
604 std::vector<uint8_t> testEntryHeaderVector(
605 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700606 wraparoundReadMock(testOffset, testEntryHeaderVector);
Brandon Kim613ba532022-09-12 20:55:21 +0000607 EXPECT_EQ(bufferImpl->readEntryHeader(), testEntryHeader);
Brandon Kim35d43352022-06-16 11:13:36 -0700608 // Check the bmcReadPtr
609 struct CircularBufferHeader cachedBufferHeader =
610 bufferImpl->getCachedBufferHeader();
611 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
612 testOffset + testEntryHeaderVector.size());
Brandon Kim7bac2d62022-06-07 21:37:51 -0700613}
614
Brandon Kim40ce08e2022-06-15 16:58:44 -0700615TEST_F(BufferEntryTest, ReadEntryChecksumFail)
616{
617 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700618 std::vector<uint8_t> testEntryVector(testEntrySize);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700619 // Offset the checksum by 1
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700620 testEntryHeader.checksum += 1;
Brandon Kim40ce08e2022-06-15 16:58:44 -0700621 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
622 std::vector<uint8_t> testEntryHeaderVector(
623 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim35d43352022-06-16 11:13:36 -0700624 wraparoundReadMock(testOffset, testEntryHeaderVector);
625 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700626 EXPECT_THROW(
Brandon Kim613ba532022-09-12 20:55:21 +0000627 try { bufferImpl->readEntry(); } catch (const std::runtime_error& e) {
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700628 // Calculation: testChecksum (0x21) XOR (0x22) = 3
Brandon Kim40ce08e2022-06-15 16:58:44 -0700629 EXPECT_STREQ(e.what(),
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700630 "[readEntry] Checksum was '3', expected '0'");
Brandon Kim40ce08e2022-06-15 16:58:44 -0700631 throw;
632 },
633 std::runtime_error);
634}
635
Brandon Kim613ba532022-09-12 20:55:21 +0000636TEST_F(BufferEntryTest, ReadEntryPassWraparound)
Brandon Kim40ce08e2022-06-15 16:58:44 -0700637{
638 InSequence s;
Brandon Kimf0e4adc2022-06-16 23:14:25 -0700639 // We expect this will bump checksum up by "testEntrySize" = 0xff ^ 0xff ...
640 // (20 times) = 0 therefore leave the checksum as is
Brandon Kim35d43352022-06-16 11:13:36 -0700641 std::vector<uint8_t> testEntryVector(testEntrySize, 0xff);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700642 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
643 std::vector<uint8_t> testEntryHeaderVector(
644 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
Brandon Kim613ba532022-09-12 20:55:21 +0000645 // Set testOffset so that we can test the wraparound here at the header and
646 // update the readPtr
Brandon Kim3def3c82022-09-13 05:29:20 +0000647 testOffset = testMaxOffset - 1;
Brandon Kim613ba532022-09-12 20:55:21 +0000648 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
649 .WillOnce(Return(expectedWriteSize));
650 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
651
Brandon Kim35d43352022-06-16 11:13:36 -0700652 wraparoundReadMock(testOffset, testEntryHeaderVector);
653 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700654
655 EntryPair testedEntryPair;
Brandon Kim613ba532022-09-12 20:55:21 +0000656 EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
Brandon Kim40ce08e2022-06-15 16:58:44 -0700657 EXPECT_EQ(testedEntryPair.first, testEntryHeader);
658 EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
Brandon Kim35d43352022-06-16 11:13:36 -0700659 struct CircularBufferHeader cachedBufferHeader =
660 bufferImpl->getCachedBufferHeader();
661 // The bmcReadPtr should have been updated to reflect the wraparound
662 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
Brandon Kim613ba532022-09-12 20:55:21 +0000663 entryHeaderSize + testEntrySize - 1);
664
665 // Set testOffset so that we can test the wraparound here as well on our
666 // second read for the entry (by 1 byte)
Brandon Kim3def3c82022-09-13 05:29:20 +0000667 testOffset = testMaxOffset - entryHeaderSize - 1;
Brandon Kim613ba532022-09-12 20:55:21 +0000668 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
669 .WillOnce(Return(expectedWriteSize));
670 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
671
672 wraparoundReadMock(testOffset, testEntryHeaderVector);
673 wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
674
675 EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
676 EXPECT_EQ(testedEntryPair.first, testEntryHeader);
677 EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
678 cachedBufferHeader = bufferImpl->getCachedBufferHeader();
679 // The bmcReadPtr should have been updated to reflect the wraparound
680 EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
Brandon Kim35d43352022-06-16 11:13:36 -0700681 testEntrySize - 1);
Brandon Kim40ce08e2022-06-15 16:58:44 -0700682}
683
Brandon Kim4662b1b2022-06-16 21:38:02 -0700684class BufferReadErrorLogsTest : public BufferEntryTest
685{
686 protected:
687 BufferReadErrorLogsTest() = default;
688
689 uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
690 size_t entryAndHeaderSize = entryHeaderSize + testEntrySize;
691};
692
693TEST_F(BufferReadErrorLogsTest, PtrsTooBigFail)
694{
695 InSequence s;
696 // Set the biosWritePtr too big
697 testInitializationHeader.biosWritePtr =
Brandon Kim3def3c82022-09-13 05:29:20 +0000698 boost::endian::native_to_little((testMaxOffset + 1));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700699 initializeFuncMock();
700
701 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400702 .WillOnce(Return(std::vector<uint8_t>(
703 testInitializationHeaderPtr,
704 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700705 EXPECT_THROW(
706 try {
707 bufferImpl->readErrorLogs();
708 } catch (const std::runtime_error& e) {
709 EXPECT_STREQ(e.what(),
Brandon Kim3def3c82022-09-13 05:29:20 +0000710 "[readErrorLogs] currentBiosWritePtr was '385' "
711 "which was bigger than maxOffset '384'");
Brandon Kim4662b1b2022-06-16 21:38:02 -0700712 throw;
713 },
714 std::runtime_error);
715
716 // Reset the biosWritePtr and set the bmcReadPtr too big
717 testInitializationHeader.biosWritePtr = 0;
718 initializeFuncMock();
719 testInitializationHeader.bmcReadPtr =
Brandon Kim3def3c82022-09-13 05:29:20 +0000720 boost::endian::native_to_little((testMaxOffset + 1));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700721 initializeFuncMock();
722
723 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400724 .WillOnce(Return(std::vector<uint8_t>(
725 testInitializationHeaderPtr,
726 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700727 EXPECT_THROW(
728 try {
729 bufferImpl->readErrorLogs();
730 } catch (const std::runtime_error& e) {
Brandon Kim3def3c82022-09-13 05:29:20 +0000731 EXPECT_STREQ(e.what(), "[readErrorLogs] currentReadPtr was '385' "
732 "which was bigger than maxOffset '384'");
Brandon Kim4662b1b2022-06-16 21:38:02 -0700733 throw;
734 },
735 std::runtime_error);
736}
737
738TEST_F(BufferReadErrorLogsTest, IdenticalPtrsPass)
739{
740 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400741 .WillOnce(Return(std::vector<uint8_t>(
742 testInitializationHeaderPtr,
743 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700744 EXPECT_NO_THROW(bufferImpl->readErrorLogs());
745}
746
747TEST_F(BufferReadErrorLogsTest, NoWraparoundPass)
748{
749 InSequence s;
750 // Set the biosWritePtr to 1 entryHeader + entry size
751 testInitializationHeader.biosWritePtr =
752 boost::endian::native_to_little((entryAndHeaderSize));
753 initializeFuncMock();
754 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400755 .WillOnce(Return(std::vector<uint8_t>(
756 testInitializationHeaderPtr,
757 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700758 std::vector<uint8_t> testEntryHeaderVector(
759 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
760 std::vector<uint8_t> testEntryVector(testEntrySize);
761 wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
762 wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
763
764 std::vector<EntryPair> entryPairs;
765 EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
766
767 // Check that we only read one entryPair and that the content is correct
Brandon Kim1a3dc602022-06-17 11:34:33 -0700768 EXPECT_EQ(entryPairs.size(), 1U);
Brandon Kim4662b1b2022-06-16 21:38:02 -0700769 EXPECT_EQ(entryPairs[0].first, testEntryHeader);
770 EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
771}
772
773TEST_F(BufferReadErrorLogsTest, WraparoundMultiplEntryPass)
774{
775 InSequence s;
776 // Set the bmcReadPtr to 1 entryHeader + entry size from the "end" exactly
Brandon Kim3def3c82022-09-13 05:29:20 +0000777 uint32_t entryAndHeaderSizeAwayFromEnd = testMaxOffset - entryAndHeaderSize;
Brandon Kim4662b1b2022-06-16 21:38:02 -0700778 testInitializationHeader.bmcReadPtr =
779 boost::endian::native_to_little(entryAndHeaderSizeAwayFromEnd);
780 // Set the biosWritePtr to 1 entryHeader + entry size from the "beginning"
781 testInitializationHeader.biosWritePtr = entryAndHeaderSize;
782 initializeFuncMock();
783 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400784 .WillOnce(Return(std::vector<uint8_t>(
785 testInitializationHeaderPtr,
786 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700787
788 std::vector<uint8_t> testEntryHeaderVector(
789 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
790 std::vector<uint8_t> testEntryVector(testEntrySize);
791 wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd,
792 testEntryHeaderVector);
793 wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd +
794 entryHeaderSize,
795 testEntryVector);
796 wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize,
797 testEntryHeaderVector);
798 wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize +
799 entryHeaderSize,
800 testEntryVector);
801
802 std::vector<EntryPair> entryPairs;
803 EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
804
805 // Check that we only read one entryPair and that the content is correct
806 EXPECT_EQ(entryPairs.size(), 2);
807 EXPECT_EQ(entryPairs[0].first, testEntryHeader);
808 EXPECT_EQ(entryPairs[1].first, testEntryHeader);
809 EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
810 EXPECT_THAT(entryPairs[1].second, ElementsAreArray(testEntryVector));
811}
812
813TEST_F(BufferReadErrorLogsTest, WraparoundMismatchingPtrsFail)
814{
815 InSequence s;
816 testInitializationHeader.bmcReadPtr = boost::endian::native_to_little(0);
817 // Make the biosWritePtr intentially 1 smaller than expected
818 testInitializationHeader.biosWritePtr =
819 boost::endian::native_to_little(entryAndHeaderSize - 1);
820 initializeFuncMock();
821 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
Patrick Williams1a643562024-08-16 15:22:05 -0400822 .WillOnce(Return(std::vector<uint8_t>(
823 testInitializationHeaderPtr,
824 testInitializationHeaderPtr + bufferHeaderSize)));
Brandon Kim4662b1b2022-06-16 21:38:02 -0700825
826 std::vector<uint8_t> testEntryHeaderVector(
827 testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
828 std::vector<uint8_t> testEntryVector(testEntrySize);
829 wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
830 wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
831
832 EXPECT_THROW(
833 try {
834 bufferImpl->readErrorLogs();
835 } catch (const std::runtime_error& e) {
836 EXPECT_STREQ(
837 e.what(),
838 "[readErrorLogs] biosWritePtr '37' and bmcReaddPtr '38' "
839 "are not identical after reading through all the logs");
840 throw;
841 },
842 std::runtime_error);
843}
844
Brandon Kimfcbc3db2022-06-06 21:26:18 -0700845} // namespace
846} // namespace bios_bmc_smm_error_logger