| Brandon Kim | 714e388 | 2020-06-22 12:36:32 -0700 | [diff] [blame] | 1 | #include <ipmiblob/blob_errors.hpp> | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 2 | #include <ipmiblob/blob_handler.hpp> | 
| Patrick Venture | 1681f7f | 2019-03-07 12:59:29 -0800 | [diff] [blame] | 3 | #include <ipmiblob/test/crc_mock.hpp> | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 4 | #include <ipmiblob/test/ipmi_interface_mock.hpp> | 
| Patrick Venture | 60edc61 | 2020-06-24 15:06:41 -0700 | [diff] [blame] | 5 |  | 
 | 6 | #include <cstdint> | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 7 | #include <memory> | 
 | 8 | #include <vector> | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 9 |  | 
 | 10 | #include <gtest/gtest.h> | 
 | 11 |  | 
| Patrick Venture | 1470bec | 2019-03-06 07:33:12 -0800 | [diff] [blame] | 12 | namespace ipmiblob | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 13 | { | 
 | 14 | CrcInterface* crcIntf = nullptr; | 
 | 15 |  | 
 | 16 | std::uint16_t generateCrc(const std::vector<std::uint8_t>& data) | 
 | 17 | { | 
 | 18 |     return (crcIntf) ? crcIntf->generateCrc(data) : 0x00; | 
 | 19 | } | 
 | 20 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 21 | using ::testing::ContainerEq; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 22 | using ::testing::Eq; | 
 | 23 | using ::testing::Return; | 
 | 24 |  | 
 | 25 | class BlobHandlerTest : public ::testing::Test | 
 | 26 | { | 
 | 27 |   protected: | 
 | 28 |     void SetUp() override | 
 | 29 |     { | 
 | 30 |         crcIntf = &crcMock; | 
 | 31 |     } | 
 | 32 |  | 
 | 33 |     CrcMock crcMock; | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 34 |  | 
 | 35 |     std::unique_ptr<IpmiInterface> CreateIpmiMock() | 
 | 36 |     { | 
 | 37 |         return std::make_unique<IpmiInterfaceMock>(); | 
 | 38 |     } | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 39 | }; | 
 | 40 |  | 
 | 41 | TEST_F(BlobHandlerTest, getCountIpmiHappy) | 
 | 42 | { | 
 | 43 |     /* Verify returns the value specified by the IPMI response. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 44 |     auto ipmi = CreateIpmiMock(); | 
 | 45 |     IpmiInterfaceMock* ipmiMock = | 
 | 46 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 47 |     BlobHandler blob(std::move(ipmi)); | 
 | 48 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 49 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 50 |         0xcf, 0xc2, 0x00, | 
 | 51 |         static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount)}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 52 |  | 
 | 53 |     /* return 1 blob count. */ | 
 | 54 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, | 
 | 55 |                                       0x01, 0x00, 0x00, 0x00}; | 
 | 56 |  | 
 | 57 |     std::vector<std::uint8_t> bytes = {0x01, 0x00, 0x00, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 58 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes))) | 
 | 59 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 60 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 61 |     EXPECT_CALL(*ipmiMock, | 
 | 62 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 63 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 64 |     EXPECT_EQ(1, blob.getBlobCount()); | 
 | 65 | } | 
 | 66 |  | 
 | 67 | TEST_F(BlobHandlerTest, enumerateBlobIpmiHappy) | 
 | 68 | { | 
 | 69 |     /* Verify returns the name specified by the IPMI response. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 70 |     auto ipmi = CreateIpmiMock(); | 
 | 71 |     IpmiInterfaceMock* ipmiMock = | 
 | 72 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 73 |     BlobHandler blob(std::move(ipmi)); | 
 | 74 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 75 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 76 |         0xcf, 0xc2, | 
 | 77 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate), | 
 | 78 |         0x00, 0x00, | 
 | 79 |         0x01, 0x00, | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 80 |         0x00, 0x00}; | 
 | 81 |  | 
 | 82 |     /* return value. */ | 
 | 83 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, | 
 | 84 |                                       'a',  'b',  'c',  'd',  0x00}; | 
 | 85 |  | 
 | 86 |     std::vector<std::uint8_t> bytes = {'a', 'b', 'c', 'd', 0x00}; | 
 | 87 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 88 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 89 |         .WillOnce(Return(0x00)); | 
 | 90 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes))) | 
 | 91 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 92 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 93 |     EXPECT_CALL(*ipmiMock, | 
 | 94 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 95 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 96 |     EXPECT_STREQ("abcd", blob.enumerateBlob(1).c_str()); | 
 | 97 | } | 
 | 98 |  | 
 | 99 | TEST_F(BlobHandlerTest, enumerateBlobIpmiNoBytes) | 
 | 100 | { | 
 | 101 |     /* Simulate a case where the IPMI command returns no data. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 102 |     auto ipmi = CreateIpmiMock(); | 
 | 103 |     IpmiInterfaceMock* ipmiMock = | 
 | 104 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 105 |     BlobHandler blob(std::move(ipmi)); | 
 | 106 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 107 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 108 |         0xcf, 0xc2, | 
 | 109 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate), | 
 | 110 |         0x00, 0x00, | 
 | 111 |         0x01, 0x00, | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 112 |         0x00, 0x00}; | 
 | 113 |  | 
 | 114 |     /* return value. */ | 
 | 115 |     std::vector<std::uint8_t> resp = {}; | 
 | 116 |  | 
 | 117 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 118 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 119 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 120 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 121 |     EXPECT_CALL(*ipmiMock, | 
 | 122 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 123 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 124 |     EXPECT_STREQ("", blob.enumerateBlob(1).c_str()); | 
 | 125 | } | 
 | 126 |  | 
 | 127 | TEST_F(BlobHandlerTest, getBlobListIpmiHappy) | 
 | 128 | { | 
 | 129 |     /* Verify returns the list built via the above two commands. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 130 |     auto ipmi = CreateIpmiMock(); | 
 | 131 |     IpmiInterfaceMock* ipmiMock = | 
 | 132 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 133 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 134 |  | 
 | 135 |     std::vector<std::uint8_t> request1 = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 136 |         0xcf, 0xc2, 0x00, | 
 | 137 |         static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount)}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 138 |  | 
 | 139 |     /* return 1 blob count. */ | 
 | 140 |     std::vector<std::uint8_t> resp1 = {0xcf, 0xc2, 0x00, 0x00, 0x00, | 
 | 141 |                                        0x01, 0x00, 0x00, 0x00}; | 
 | 142 |  | 
 | 143 |     std::vector<std::uint8_t> bytes1 = {0x01, 0x00, 0x00, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 144 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes1))) | 
 | 145 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 146 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 147 |     EXPECT_CALL(*ipmiMock, | 
 | 148 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request1))) | 
 | 149 |         .WillOnce(Return(resp1)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 150 |  | 
 | 151 |     std::vector<std::uint8_t> request2 = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 152 |         0xcf, 0xc2, | 
 | 153 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate), | 
 | 154 |         0x00, 0x00, | 
 | 155 |         0x00, 0x00, | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 156 |         0x00, 0x00}; | 
 | 157 |  | 
 | 158 |     /* return value. */ | 
 | 159 |     std::vector<std::uint8_t> resp2 = {0xcf, 0xc2, 0x00, 0x00, 0x00, | 
 | 160 |                                        'a',  'b',  'c',  'd',  0x00}; | 
 | 161 |  | 
 | 162 |     std::vector<std::uint8_t> reqCrc = {0x00, 0x00, 0x00, 0x00}; | 
 | 163 |     std::vector<std::uint8_t> bytes2 = {'a', 'b', 'c', 'd', 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 164 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 165 |         .WillOnce(Return(0x00)); | 
 | 166 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(bytes2))) | 
 | 167 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 168 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 169 |     EXPECT_CALL(*ipmiMock, | 
 | 170 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request2))) | 
 | 171 |         .WillOnce(Return(resp2)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 172 |  | 
 | 173 |     /* A std::string is not nul-terminated by default. */ | 
 | 174 |     std::vector<std::string> expectedList = {std::string{"abcd"}}; | 
 | 175 |  | 
 | 176 |     EXPECT_EQ(expectedList, blob.getBlobList()); | 
 | 177 | } | 
 | 178 |  | 
 | 179 | TEST_F(BlobHandlerTest, getStatWithMetadata) | 
 | 180 | { | 
 | 181 |     /* Stat received metadata. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 182 |     auto ipmi = CreateIpmiMock(); | 
 | 183 |     IpmiInterfaceMock* ipmiMock = | 
 | 184 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 185 |     BlobHandler blob(std::move(ipmi)); | 
 | 186 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 187 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 188 |         0xcf, 0xc2, | 
 | 189 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat), | 
 | 190 |         0x00, 0x00, | 
 | 191 |         'a',  'b', | 
 | 192 |         'c',  'd', | 
 | 193 |         0x00}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 194 |  | 
 | 195 |     /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ | 
 | 196 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, | 
 | 197 |                                       0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x45}; | 
 | 198 |  | 
 | 199 |     std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; | 
 | 200 |     std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, | 
 | 201 |                                          0x00, 0x02, 0x34, 0x45}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 202 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 203 |         .WillOnce(Return(0x00)); | 
 | 204 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 205 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 206 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 207 |     EXPECT_CALL(*ipmiMock, | 
 | 208 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 209 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 210 |  | 
 | 211 |     auto meta = blob.getStat("abcd"); | 
 | 212 |     EXPECT_EQ(meta.blob_state, 0xffff); | 
 | 213 |     EXPECT_EQ(meta.size, 0x00); | 
 | 214 |     std::vector<std::uint8_t> metadata = {0x34, 0x45}; | 
 | 215 |     EXPECT_EQ(metadata, meta.metadata); | 
 | 216 | } | 
 | 217 |  | 
| Brandon Kim | 714e388 | 2020-06-22 12:36:32 -0700 | [diff] [blame] | 218 | TEST_F(BlobHandlerTest, getStatWithWrongMetadataLength) | 
 | 219 | { | 
 | 220 |     /* Stat fails when wrong metadata length is received */ | 
 | 221 |     auto ipmi = CreateIpmiMock(); | 
 | 222 |     IpmiInterfaceMock* ipmiMock = | 
 | 223 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 224 |     BlobHandler blob(std::move(ipmi)); | 
 | 225 |  | 
 | 226 |     std::vector<std::uint8_t> request = { | 
 | 227 |         0xcf, 0xc2, | 
 | 228 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat), | 
 | 229 |         0x00, 0x00, | 
 | 230 |         'a',  'b', | 
 | 231 |         'c',  'd', | 
 | 232 |         0x00}; | 
 | 233 |  | 
 | 234 |     /* return blob_state: 0xffff, size: 0x00, len: 1, metadata 0x3445 */ | 
 | 235 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, | 
 | 236 |                                       0x00, 0x00, 0x00, 0x00, 0x01, 0x34, 0x45}; | 
 | 237 |  | 
 | 238 |     std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; | 
 | 239 |     std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, | 
 | 240 |                                          0x00, 0x01, 0x34, 0x45}; | 
 | 241 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 242 |         .WillOnce(Return(0x00)); | 
 | 243 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 244 |         .WillOnce(Return(0x00)); | 
 | 245 |  | 
 | 246 |     EXPECT_CALL(*ipmiMock, | 
 | 247 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 248 |         .WillOnce(Return(resp)); | 
 | 249 |  | 
 | 250 |     EXPECT_THROW(blob.getStat("abcd"), BlobException); | 
 | 251 | } | 
 | 252 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 253 | TEST_F(BlobHandlerTest, getStatNoMetadata) | 
 | 254 | { | 
 | 255 |     /* Stat received no metadata. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 256 |     auto ipmi = CreateIpmiMock(); | 
 | 257 |     IpmiInterfaceMock* ipmiMock = | 
 | 258 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 259 |     BlobHandler blob(std::move(ipmi)); | 
 | 260 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 261 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 262 |         0xcf, 0xc2, | 
 | 263 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat), | 
 | 264 |         0x00, 0x00, | 
 | 265 |         'a',  'b', | 
 | 266 |         'c',  'd', | 
 | 267 |         0x00}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 268 |  | 
| Brandon Kim | 714e388 | 2020-06-22 12:36:32 -0700 | [diff] [blame] | 269 |     /* return blob_state: 0xffff, size: 0x00, metadata 0x0000 */ | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 270 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, | 
 | 271 |                                       0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; | 
 | 272 |  | 
 | 273 |     std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; | 
 | 274 |     std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, | 
 | 275 |                                          0x00, 0x00, 0x00}; | 
 | 276 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 277 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 278 |         .WillOnce(Return(0x00)); | 
 | 279 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 280 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 281 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 282 |     EXPECT_CALL(*ipmiMock, | 
 | 283 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 284 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 285 |  | 
 | 286 |     auto meta = blob.getStat("abcd"); | 
 | 287 |     EXPECT_EQ(meta.blob_state, 0xffff); | 
 | 288 |     EXPECT_EQ(meta.size, 0x00); | 
 | 289 |     std::vector<std::uint8_t> metadata = {}; | 
 | 290 |     EXPECT_EQ(metadata, meta.metadata); | 
 | 291 | } | 
 | 292 |  | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 293 | TEST_F(BlobHandlerTest, getSessionStatNoMetadata) | 
 | 294 | { | 
 | 295 |     /* The get session stat succeeds. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 296 |     auto ipmi = CreateIpmiMock(); | 
 | 297 |     IpmiInterfaceMock* ipmiMock = | 
 | 298 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 299 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 300 |  | 
 | 301 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 302 |         0xcf, 0xc2, | 
 | 303 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat), | 
 | 304 |         0x00, 0x00, | 
 | 305 |         0x01, 0x00}; | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 306 |  | 
| Brandon Kim | 714e388 | 2020-06-22 12:36:32 -0700 | [diff] [blame] | 307 |     /* return blob_state: 0xffff, size: 0x00, metadata 0x0000 */ | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 308 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, | 
 | 309 |                                       0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; | 
 | 310 |  | 
 | 311 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00}; | 
 | 312 |     std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, | 
 | 313 |                                          0x00, 0x00, 0x00}; | 
 | 314 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 315 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 316 |         .WillOnce(Return(0x00)); | 
 | 317 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 318 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 319 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 320 |     EXPECT_CALL(*ipmiMock, | 
 | 321 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 322 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 16a99a6 | 2019-05-03 17:21:30 -0700 | [diff] [blame] | 323 |  | 
 | 324 |     auto meta = blob.getStat(0x0001); | 
 | 325 |     EXPECT_EQ(meta.blob_state, 0xffff); | 
 | 326 |     EXPECT_EQ(meta.size, 0x00); | 
 | 327 |     std::vector<std::uint8_t> metadata = {}; | 
 | 328 |     EXPECT_EQ(metadata, meta.metadata); | 
 | 329 | } | 
 | 330 |  | 
| Brandon Kim | 714e388 | 2020-06-22 12:36:32 -0700 | [diff] [blame] | 331 | TEST_F(BlobHandlerTest, getSessionStatEmptyResp) | 
 | 332 | { | 
 | 333 |     /* The get session stat fails after getting empty response */ | 
 | 334 |     auto ipmi = CreateIpmiMock(); | 
 | 335 |     IpmiInterfaceMock* ipmiMock = | 
 | 336 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 337 |     BlobHandler blob(std::move(ipmi)); | 
 | 338 |  | 
 | 339 |     std::vector<std::uint8_t> request = { | 
 | 340 |         0xcf, 0xc2, | 
 | 341 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat), | 
 | 342 |         0x00, 0x00, | 
 | 343 |         0x01, 0x00}; | 
 | 344 |  | 
 | 345 |     std::vector<std::uint8_t> resp; | 
 | 346 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00}; | 
 | 347 |  | 
 | 348 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 349 |         .WillOnce(Return(0x00)); | 
 | 350 |  | 
 | 351 |     EXPECT_CALL(*ipmiMock, | 
 | 352 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 353 |         .WillOnce(Return(resp)); | 
 | 354 |  | 
 | 355 |     EXPECT_THROW(blob.getStat(0x0001), BlobException); | 
 | 356 | } | 
 | 357 |  | 
 | 358 | TEST_F(BlobHandlerTest, getSessionStatInvalidHeader) | 
 | 359 | { | 
 | 360 |     /* The get session stat fails after getting a response shorter than the | 
 | 361 |      * expected headersize but with the expected OEN | 
 | 362 |      */ | 
 | 363 |     auto ipmi = CreateIpmiMock(); | 
 | 364 |     IpmiInterfaceMock* ipmiMock = | 
 | 365 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 366 |     BlobHandler blob(std::move(ipmi)); | 
 | 367 |  | 
 | 368 |     std::vector<std::uint8_t> request = { | 
 | 369 |         0xcf, 0xc2, | 
 | 370 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat), | 
 | 371 |         0x00, 0x00, | 
 | 372 |         0x01, 0x00}; | 
 | 373 |  | 
 | 374 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00}; | 
 | 375 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00}; | 
 | 376 |  | 
 | 377 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 378 |         .WillOnce(Return(0x00)); | 
 | 379 |  | 
 | 380 |     EXPECT_CALL(*ipmiMock, | 
 | 381 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 382 |         .WillOnce(Return(resp)); | 
 | 383 |  | 
 | 384 |     EXPECT_THROW(blob.getStat(0x0001), BlobException); | 
 | 385 | } | 
 | 386 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 387 | TEST_F(BlobHandlerTest, openBlobSucceeds) | 
 | 388 | { | 
 | 389 |     /* The open blob succeeds. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 390 |     auto ipmi = CreateIpmiMock(); | 
 | 391 |     IpmiInterfaceMock* ipmiMock = | 
 | 392 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 393 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 394 |  | 
 | 395 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 396 |         0xcf, 0xc2, | 
 | 397 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen), | 
 | 398 |         0x00, 0x00, | 
 | 399 |         0x02, 0x04, | 
 | 400 |         'a',  'b', | 
 | 401 |         'c',  'd', | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 402 |         0x00}; | 
 | 403 |  | 
 | 404 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xfe, 0xed}; | 
 | 405 |  | 
 | 406 |     std::vector<std::uint8_t> reqCrc = {0x02, 0x04, 'a', 'b', 'c', 'd', 0x00}; | 
 | 407 |     std::vector<std::uint8_t> respCrc = {0xfe, 0xed}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 408 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 409 |         .WillOnce(Return(0x00)); | 
 | 410 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 411 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 412 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 413 |     EXPECT_CALL(*ipmiMock, | 
 | 414 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 415 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 416 |  | 
 | 417 |     const int writeBit = (1 << 1); | 
 | 418 |     const int lpcBit = (1 << 10); | 
 | 419 |  | 
 | 420 |     auto session = blob.openBlob("abcd", writeBit | lpcBit); | 
 | 421 |     EXPECT_EQ(0xedfe, session); | 
 | 422 | } | 
 | 423 |  | 
 | 424 | TEST_F(BlobHandlerTest, closeBlobSucceeds) | 
 | 425 | { | 
 | 426 |     /* The close succeeds. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 427 |     auto ipmi = CreateIpmiMock(); | 
 | 428 |     IpmiInterfaceMock* ipmiMock = | 
 | 429 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 430 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 431 |  | 
 | 432 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 433 |         0xcf, 0xc2, | 
 | 434 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobClose), | 
 | 435 |         0x00, 0x00, | 
 | 436 |         0x01, 0x00}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 437 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; | 
 | 438 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 439 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 440 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 441 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 442 |     EXPECT_CALL(*ipmiMock, | 
 | 443 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 444 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 445 |  | 
 | 446 |     blob.closeBlob(0x0001); | 
 | 447 | } | 
 | 448 |  | 
| Patrick Venture | 8865e40 | 2019-05-14 13:29:10 -0700 | [diff] [blame] | 449 | TEST_F(BlobHandlerTest, commitSucceedsNoData) | 
 | 450 | { | 
 | 451 |     /* The commit succeeds. */ | 
 | 452 |     auto ipmi = CreateIpmiMock(); | 
 | 453 |     IpmiInterfaceMock* ipmiMock = | 
 | 454 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 455 |     BlobHandler blob(std::move(ipmi)); | 
 | 456 |  | 
 | 457 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 458 |         0xcf, 0xc2, | 
 | 459 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit), | 
 | 460 |         0x00, 0x00, | 
 | 461 |         0x01, 0x00, | 
| Patrick Venture | 8865e40 | 2019-05-14 13:29:10 -0700 | [diff] [blame] | 462 |         0x00}; | 
 | 463 |  | 
 | 464 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; | 
 | 465 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 466 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 467 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 8865e40 | 2019-05-14 13:29:10 -0700 | [diff] [blame] | 468 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 469 |     EXPECT_CALL(*ipmiMock, | 
 | 470 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 471 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 8865e40 | 2019-05-14 13:29:10 -0700 | [diff] [blame] | 472 |  | 
 | 473 |     blob.commit(0x0001, {}); | 
 | 474 | } | 
 | 475 |  | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 476 | TEST_F(BlobHandlerTest, writeBytesSucceeds) | 
 | 477 | { | 
 | 478 |     /* The write bytes succeeds. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 479 |     auto ipmi = CreateIpmiMock(); | 
 | 480 |     IpmiInterfaceMock* ipmiMock = | 
 | 481 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 482 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 483 |  | 
 | 484 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 485 |         0xcf, 0xc2, | 
 | 486 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), | 
 | 487 |         0x00, 0x00, | 
 | 488 |         0x01, 0x00, | 
 | 489 |         0x00, 0x00, | 
 | 490 |         0x00, 0x00, | 
 | 491 |         'a',  'b', | 
 | 492 |         'c',  'd'}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 493 |  | 
 | 494 |     std::vector<std::uint8_t> bytes = {'a', 'b', 'c', 'd'}; | 
 | 495 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; | 
 | 496 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, | 
 | 497 |                                         0x00, 'a',  'b',  'c',  'd'}; | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 498 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 499 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 500 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 501 |     EXPECT_CALL(*ipmiMock, | 
 | 502 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 503 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 504 |  | 
 | 505 |     blob.writeBytes(0x0001, 0, bytes); | 
 | 506 | } | 
 | 507 |  | 
 | 508 | TEST_F(BlobHandlerTest, readBytesSucceeds) | 
 | 509 | { | 
 | 510 |     /* The reading of bytes succeeds. */ | 
| Patrick Venture | 786a541 | 2019-05-13 07:40:22 -0700 | [diff] [blame] | 511 |     auto ipmi = CreateIpmiMock(); | 
 | 512 |     IpmiInterfaceMock* ipmiMock = | 
 | 513 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 514 |     BlobHandler blob(std::move(ipmi)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 515 |  | 
 | 516 |     std::vector<std::uint8_t> request = { | 
| Patrick Venture | 4447464 | 2019-05-20 19:11:04 -0700 | [diff] [blame] | 517 |         0xcf, 0xc2, | 
 | 518 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobRead), | 
 | 519 |         0x00, 0x00, | 
 | 520 |         0x01, 0x00, | 
 | 521 |         0x00, 0x00, | 
 | 522 |         0x00, 0x00, | 
 | 523 |         0x04, 0x00, | 
 | 524 |         0x00, 0x00}; | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 525 |  | 
 | 526 |     std::vector<std::uint8_t> expectedBytes = {'a', 'b', 'c', 'd'}; | 
 | 527 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, | 
 | 528 |                                       'a',  'b',  'c',  'd'}; | 
 | 529 |     std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, | 
 | 530 |                                         0x00, 0x04, 0x00, 0x00, 0x00}; | 
 | 531 |     std::vector<std::uint8_t> respCrc = {'a', 'b', 'c', 'd'}; | 
 | 532 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 533 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 534 |         .WillOnce(Return(0x00)); | 
 | 535 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc))) | 
 | 536 |         .WillOnce(Return(0x00)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 537 |  | 
| Patrick Venture | 958f1ce | 2019-05-31 17:07:25 -0700 | [diff] [blame] | 538 |     EXPECT_CALL(*ipmiMock, | 
 | 539 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 540 |         .WillOnce(Return(resp)); | 
| Patrick Venture | 123b5c0 | 2019-03-05 14:01:00 -0800 | [diff] [blame] | 541 |  | 
 | 542 |     EXPECT_EQ(blob.readBytes(0x0001, 0, 4), expectedBytes); | 
 | 543 | } | 
 | 544 |  | 
| Brandon Kim | cc4ef0c | 2019-10-18 10:08:37 -0700 | [diff] [blame] | 545 | TEST_F(BlobHandlerTest, deleteBlobSucceeds) | 
 | 546 | { | 
 | 547 |     /* The delete succeeds. */ | 
 | 548 |     auto ipmi = CreateIpmiMock(); | 
 | 549 |     IpmiInterfaceMock* ipmiMock = | 
 | 550 |         reinterpret_cast<IpmiInterfaceMock*>(ipmi.get()); | 
 | 551 |     BlobHandler blob(std::move(ipmi)); | 
 | 552 |  | 
 | 553 |     std::vector<std::uint8_t> request = { | 
 | 554 |         0xcf, 0xc2, | 
 | 555 |         0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete), | 
 | 556 |         0x00, 0x00, | 
 | 557 |         'a',  'b', | 
 | 558 |         'c',  'd', | 
 | 559 |         0x00}; | 
 | 560 |  | 
 | 561 |     std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; | 
 | 562 |     std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; | 
 | 563 |     EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc))) | 
 | 564 |         .WillOnce(Return(0x00)); | 
 | 565 |  | 
 | 566 |     EXPECT_CALL(*ipmiMock, | 
 | 567 |                 sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request))) | 
 | 568 |         .WillOnce(Return(resp)); | 
 | 569 |  | 
 | 570 |     blob.deleteBlob("abcd"); | 
 | 571 | } | 
 | 572 |  | 
| Patrick Venture | 1470bec | 2019-03-06 07:33:12 -0800 | [diff] [blame] | 573 | } // namespace ipmiblob |