1 #include "ipmi.hpp"
2 #include "manager_mock.hpp"
3 
4 #include <cstring>
5 #include <string>
6 
7 #include <gtest/gtest.h>
8 
9 namespace blobs
10 {
11 
12 using ::testing::_;
13 using ::testing::Invoke;
14 using ::testing::NotNull;
15 using ::testing::Return;
16 using ::testing::StrEq;
17 
18 // ipmid.hpp isn't installed where we can grab it and this value is per BMC
19 // SoC.
20 #define MAX_IPMI_BUFFER 64
21 
22 TEST(BlobOpenTest, InvalidRequestLengthReturnsFailure)
23 {
24     // There is a minimum blobId length of one character, this test verifies
25     // we check that.
26 
27     ManagerMock mgr;
28     size_t dataLen;
29     uint8_t request[MAX_IPMI_BUFFER] = {0};
30     uint8_t reply[MAX_IPMI_BUFFER] = {0};
31     auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
32     std::string blobId = "abc";
33 
34     req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
35     req->crc = 0;
36     req->flags = 0;
37     // length() doesn't include the nul-terminator.
38     std::memcpy(req + 1, blobId.c_str(), blobId.length());
39 
40     dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length();
41 
42     EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
43               openBlob(&mgr, request, reply, &dataLen));
44 }
45 
46 TEST(BlobOpenTest, RequestRejectedReturnsFailure)
47 {
48     // The blobId is rejected for any reason.
49 
50     ManagerMock mgr;
51     size_t dataLen;
52     uint8_t request[MAX_IPMI_BUFFER] = {0};
53     uint8_t reply[MAX_IPMI_BUFFER] = {0};
54     auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
55     std::string blobId = "a";
56 
57     req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
58     req->crc = 0;
59     req->flags = 0;
60     // length() doesn't include the nul-terminator, request buff is initialized
61     // to 0s
62     std::memcpy(req + 1, blobId.c_str(), blobId.length());
63 
64     dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
65 
66     EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), _))
67         .WillOnce(Return(false));
68 
69     EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
70               openBlob(&mgr, request, reply, &dataLen));
71 }
72 
73 TEST(BlobOpenTest, BlobOpenReturnsOk)
74 {
75     // The boring case where the blobId opens.
76 
77     ManagerMock mgr;
78     size_t dataLen;
79     uint8_t request[MAX_IPMI_BUFFER] = {0};
80     uint8_t reply[MAX_IPMI_BUFFER] = {0};
81     auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
82     struct BmcBlobOpenRx rep;
83     std::string blobId = "a";
84 
85     req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
86     req->crc = 0;
87     req->flags = 0;
88     // length() doesn't include the nul-terminator, request buff is initialized
89     // to 0s
90     std::memcpy(req + 1, blobId.c_str(), blobId.length());
91 
92     dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
93     uint16_t returnedSession = 0x54;
94 
95     EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), NotNull()))
96         .WillOnce(Invoke([&](uint16_t, const std::string&, uint16_t* session) {
97             (*session) = returnedSession;
98             return true;
99         }));
100 
101     EXPECT_EQ(IPMI_CC_OK, openBlob(&mgr, request, reply, &dataLen));
102 
103     rep.crc = 0;
104     rep.sessionId = returnedSession;
105 
106     EXPECT_EQ(sizeof(rep), dataLen);
107     EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
108 }
109 } // namespace blobs
110