1 #include "buffer.hpp" 2 #include "data_interface_mock.hpp" 3 4 #include <boost/endian/arithmetic.hpp> 5 #include <boost/endian/conversion.hpp> 6 7 #include <algorithm> 8 #include <array> 9 #include <cstdint> 10 #include <memory> 11 12 #include <gmock/gmock.h> 13 #include <gtest/gtest.h> 14 15 namespace bios_bmc_smm_error_logger 16 { 17 namespace 18 { 19 20 using ::testing::_; 21 using ::testing::ElementsAreArray; 22 using ::testing::InSequence; 23 using ::testing::Return; 24 25 class 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; 36 std::transform(testMagicNumber.begin(), testMagicNumber.end(), 37 testInitializationHeader.magicNumber.begin(), 38 [](uint32_t number) -> little_uint32_t { 39 return boost::endian::native_to_little(number); 40 }); 41 } 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; 47 static constexpr uint16_t testQueueSize = 0x100; 48 static constexpr uint16_t testUeRegionSize = 0x50; 49 static constexpr std::array<uint32_t, 4> testMagicNumber = { 50 0x12345678, 0x22345678, 0x32345678, 0x42345678}; 51 static constexpr size_t bufferHeaderSize = 52 sizeof(struct CircularBufferHeader); 53 54 struct CircularBufferHeader testInitializationHeader 55 {}; 56 57 std::unique_ptr<DataInterfaceMock> dataInterfaceMock; 58 DataInterfaceMock* dataInterfaceMockPtr; 59 std::unique_ptr<BufferImpl> bufferImpl; 60 }; 61 62 TEST_F(BufferTest, BufferInitializeEraseFail) 63 { 64 InSequence s; 65 66 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 67 .WillOnce(Return(testRegionSize)); 68 const std::vector<uint8_t> emptyArray(testRegionSize, 0); 69 // Return a smaller write than the intended testRegionSize to test the error 70 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 71 .WillOnce(Return(testRegionSize - 1)); 72 EXPECT_THROW( 73 try { 74 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize, 75 testUeRegionSize, testMagicNumber); 76 } catch (const std::runtime_error& e) { 77 EXPECT_STREQ(e.what(), "Buffer initialization only erased '511'"); 78 throw; 79 }, 80 std::runtime_error); 81 82 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 83 .WillOnce(Return(testRegionSize)); 84 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 85 .WillOnce(Return(testRegionSize)); 86 // Return a smaller write than the intended initializationHeader to test the 87 // error 88 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0)); 89 EXPECT_THROW( 90 try { 91 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize, 92 testUeRegionSize, testMagicNumber); 93 } catch (const std::runtime_error& e) { 94 EXPECT_STREQ( 95 e.what(), 96 "Buffer initialization buffer header write only wrote '0'"); 97 throw; 98 }, 99 std::runtime_error); 100 } 101 102 TEST_F(BufferTest, BufferInitializePass) 103 { 104 InSequence s; 105 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 106 .WillOnce(Return(testRegionSize)); 107 const std::vector<uint8_t> emptyArray(testRegionSize, 0); 108 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 109 .WillOnce(Return(testRegionSize)); 110 111 uint8_t* testInitializationHeaderPtr = 112 reinterpret_cast<uint8_t*>(&testInitializationHeader); 113 EXPECT_CALL(*dataInterfaceMockPtr, 114 write(0, ElementsAreArray(testInitializationHeaderPtr, 115 bufferHeaderSize))) 116 .WillOnce(Return(bufferHeaderSize)); 117 EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion, 118 testQueueSize, testUeRegionSize, 119 testMagicNumber)); 120 } 121 122 TEST_F(BufferTest, BufferHeaderReadFail) 123 { 124 std::vector<std::uint8_t> testBytesRead{}; 125 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize)) 126 .WillOnce(Return(testBytesRead)); 127 EXPECT_THROW( 128 try { 129 bufferImpl->readBufferHeader(); 130 } catch (const std::runtime_error& e) { 131 EXPECT_STREQ(e.what(), 132 "Buffer header read only read '0', expected '48'"); 133 throw; 134 }, 135 std::runtime_error); 136 } 137 138 TEST_F(BufferTest, BufferHeaderReadPass) 139 { 140 uint8_t* testInitializationHeaderPtr = 141 reinterpret_cast<uint8_t*>(&testInitializationHeader); 142 std::vector<uint8_t> testInitializationHeaderVector( 143 testInitializationHeaderPtr, 144 testInitializationHeaderPtr + bufferHeaderSize); 145 146 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize)) 147 .WillOnce(Return(testInitializationHeaderVector)); 148 EXPECT_NO_THROW(bufferImpl->readBufferHeader()); 149 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader); 150 } 151 152 } // namespace 153 } // namespace bios_bmc_smm_error_logger 154