#include #include #include #include #include #include #include namespace ipmiblob { CrcInterface* crcIntf = nullptr; std::uint16_t generateCrc(const std::vector& data) { return (crcIntf) ? crcIntf->generateCrc(data) : 0x00; } using ::testing::ContainerEq; using ::testing::Eq; using ::testing::Return; class BlobHandlerTest : public ::testing::Test { protected: void SetUp() override { crcIntf = &crcMock; } CrcMock crcMock; std::unique_ptr CreateIpmiMock() { return std::make_unique(); } }; TEST_F(BlobHandlerTest, getCountIpmiHappy) { /* Verify returns the value specified by the IPMI response. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobGetCount)}; /* return 1 blob count. */ std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; std::vector bytes = {0x01, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); EXPECT_EQ(1, blob.getBlobCount()); } TEST_F(BlobHandlerTest, enumerateBlobIpmiHappy) { /* Verify returns the name specified by the IPMI response. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobEnumerate), 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; /* return value. */ std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd', 0x00}; std::vector bytes = {'a', 'b', 'c', 'd', 0x00}; std::vector reqCrc = {0x01, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); EXPECT_STREQ("abcd", blob.enumerateBlob(1).c_str()); } TEST_F(BlobHandlerTest, enumerateBlobIpmiNoBytes) { /* Simulate a case where the IPMI command returns no data. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobEnumerate), 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; /* return value. */ std::vector resp = {}; std::vector reqCrc = {0x01, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); EXPECT_STREQ("", blob.enumerateBlob(1).c_str()); } TEST_F(BlobHandlerTest, getBlobListIpmiHappy) { /* Verify returns the list built via the above two commands. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request1 = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobGetCount)}; /* return 1 blob count. */ std::vector resp1 = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; std::vector bytes1 = {0x01, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes1))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request1))) .WillOnce(Return(resp1)); std::vector request2 = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobEnumerate), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /* return value. */ std::vector resp2 = {0xcf, 0xc2, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd', 0x00}; std::vector reqCrc = {0x00, 0x00, 0x00, 0x00}; std::vector bytes2 = {'a', 'b', 'c', 'd', 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes2))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request2))) .WillOnce(Return(resp2)); /* A std::string is not nul-terminated by default. */ std::vector expectedList = {std::string{"abcd"}}; EXPECT_EQ(expectedList, blob.getBlobList()); } TEST_F(BlobHandlerTest, getStatWithMetadata) { /* Stat received metadata. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobStat), 0x00, 0x00, 'a', 'b', 'c', 'd', 0x00}; /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x45}; std::vector reqCrc = {'a', 'b', 'c', 'd', 0x00}; std::vector respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x45}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); auto meta = blob.getStat("abcd"); EXPECT_EQ(meta.blob_state, 0xffff); EXPECT_EQ(meta.size, 0x00); std::vector metadata = {0x34, 0x45}; EXPECT_EQ(metadata, meta.metadata); } TEST_F(BlobHandlerTest, getStatNoMetadata) { /* Stat received no metadata. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobStat), 0x00, 0x00, 'a', 'b', 'c', 'd', 0x00}; /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; std::vector reqCrc = {'a', 'b', 'c', 'd', 0x00}; std::vector respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); auto meta = blob.getStat("abcd"); EXPECT_EQ(meta.blob_state, 0xffff); EXPECT_EQ(meta.size, 0x00); std::vector metadata = {}; EXPECT_EQ(metadata, meta.metadata); } TEST_F(BlobHandlerTest, getSessionStatNoMetadata) { /* The get session stat succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobSessionStat), 0x00, 0x00, 0x01, 0x00}; /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; std::vector reqCrc = {0x01, 0x00}; std::vector respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); auto meta = blob.getStat(0x0001); EXPECT_EQ(meta.blob_state, 0xffff); EXPECT_EQ(meta.size, 0x00); std::vector metadata = {}; EXPECT_EQ(metadata, meta.metadata); } TEST_F(BlobHandlerTest, openBlobSucceeds) { /* The open blob succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobOpen), 0x00, 0x00, 0x02, 0x04, 'a', 'b', 'c', 'd', 0x00}; std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xfe, 0xed}; std::vector reqCrc = {0x02, 0x04, 'a', 'b', 'c', 'd', 0x00}; std::vector respCrc = {0xfe, 0xed}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); const int writeBit = (1 << 1); const int lpcBit = (1 << 10); auto session = blob.openBlob("abcd", writeBit | lpcBit); EXPECT_EQ(0xedfe, session); } TEST_F(BlobHandlerTest, closeBlobSucceeds) { /* The close succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobClose), 0x00, 0x00, 0x01, 0x00}; std::vector resp = {0xcf, 0xc2, 0x00}; std::vector reqCrc = {0x01, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); blob.closeBlob(0x0001); } TEST_F(BlobHandlerTest, commitSucceedsNoData) { /* The commit succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobCommit), 0x00, 0x00, 0x01, 0x00, 0x00}; std::vector resp = {0xcf, 0xc2, 0x00}; std::vector reqCrc = {0x01, 0x00, 0x00}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); blob.commit(0x0001, {}); } TEST_F(BlobHandlerTest, writeBytesSucceeds) { /* The write bytes succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobWrite), 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd'}; std::vector bytes = {'a', 'b', 'c', 'd'}; std::vector resp = {0xcf, 0xc2, 0x00}; std::vector reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd'}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); blob.writeBytes(0x0001, 0, bytes); } TEST_F(BlobHandlerTest, readBytesSucceeds) { /* The reading of bytes succeeds. */ auto ipmi = CreateIpmiMock(); IpmiInterfaceMock* ipmiMock = reinterpret_cast(ipmi.get()); BlobHandler blob(std::move(ipmi)); std::vector request = { 0xcf, 0xc2, 0x00, static_cast(BlobOEMCommands::bmcBlobRead), 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}; std::vector expectedBytes = {'a', 'b', 'c', 'd'}; std::vector resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd'}; std::vector reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}; std::vector respCrc = {'a', 'b', 'c', 'd'}; EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) .WillOnce(Return(0x00)); EXPECT_CALL(*ipmiMock, sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) .WillOnce(Return(resp)); EXPECT_EQ(blob.readBytes(0x0001, 0, 4), expectedBytes); } } // namespace ipmiblob