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::Matcher;
15 using ::testing::NotNull;
16 using ::testing::Return;
17 using ::testing::StrEq;
18 
19 // ipmid.hpp isn't installed where we can grab it and this value is per BMC
20 // SoC.
21 #define MAX_IPMI_BUFFER 64
22 
23 TEST(BlobStatTest, InvalidRequestLengthReturnsFailure)
24 {
25     // There is a minimum blobId length of one character, this test verifies
26     // we check that.
27 
28     ManagerMock mgr;
29     size_t dataLen;
30     uint8_t request[MAX_IPMI_BUFFER] = {0};
31     uint8_t reply[MAX_IPMI_BUFFER] = {0};
32     auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
33     std::string blobId = "abc";
34 
35     req->cmd = BlobOEMCommands::bmcBlobStat;
36     req->crc = 0;
37     // length() doesn't include the nul-terminator.
38     std::memcpy(req->blobId, blobId.c_str(), blobId.length());
39 
40     dataLen = sizeof(struct BmcBlobStatTx) + blobId.length();
41 
42     EXPECT_EQ(IPMI_CC_INVALID, statBlob(&mgr, request, reply, &dataLen));
43 }
44 
45 TEST(BlobStatTest, RequestRejectedReturnsFailure)
46 {
47     // The blobId is rejected for any reason.
48 
49     ManagerMock mgr;
50     size_t dataLen;
51     uint8_t request[MAX_IPMI_BUFFER] = {0};
52     uint8_t reply[MAX_IPMI_BUFFER] = {0};
53     auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
54     std::string blobId = "a";
55 
56     req->cmd = BlobOEMCommands::bmcBlobStat;
57     req->crc = 0;
58     // length() doesn't include the nul-terminator, request buff is initialized
59     // to 0s
60     std::memcpy(req->blobId, blobId.c_str(), blobId.length());
61 
62     dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
63 
64     EXPECT_CALL(mgr, stat(Matcher<const std::string&>(StrEq(blobId)),
65                           Matcher<struct BlobMeta*>(_)))
66         .WillOnce(Return(false));
67 
68     EXPECT_EQ(IPMI_CC_INVALID, statBlob(&mgr, request, reply, &dataLen));
69 }
70 
71 TEST(BlobStatTest, RequestSucceedsNoMetadata)
72 {
73     // Stat request succeeeds but there were no metadata bytes.
74 
75     ManagerMock mgr;
76     size_t dataLen;
77     uint8_t request[MAX_IPMI_BUFFER] = {0};
78     uint8_t reply[MAX_IPMI_BUFFER] = {0};
79     auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
80     std::string blobId = "a";
81 
82     req->cmd = BlobOEMCommands::bmcBlobStat;
83     req->crc = 0;
84     // length() doesn't include the nul-terminator, request buff is initialized
85     // to 0s
86     std::memcpy(req->blobId, blobId.c_str(), blobId.length());
87 
88     dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
89 
90     struct BmcBlobStatRx rep;
91     rep.crc = 0x00;
92     rep.blobState = 0x01;
93     rep.size = 0x100;
94     rep.metadataLen = 0x00;
95 
96     EXPECT_CALL(mgr, stat(Matcher<const std::string&>(StrEq(blobId)),
97                           Matcher<struct BlobMeta*>(NotNull())))
98         .WillOnce(Invoke([&](const std::string& path, struct BlobMeta* meta) {
99             meta->blobState = rep.blobState;
100             meta->size = rep.size;
101             return true;
102         }));
103 
104     EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
105 
106     EXPECT_EQ(sizeof(rep), dataLen);
107     EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
108 }
109 
110 TEST(BlobStatTest, RequestSucceedsWithMetadata)
111 {
112     // Stat request succeeds and there were metadata bytes.
113 
114     ManagerMock mgr;
115     size_t dataLen;
116     uint8_t request[MAX_IPMI_BUFFER] = {0};
117     uint8_t reply[MAX_IPMI_BUFFER] = {0};
118     auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
119     std::string blobId = "a";
120 
121     req->cmd = BlobOEMCommands::bmcBlobStat;
122     req->crc = 0;
123     // length() doesn't include the nul-terminator, request buff is initialized
124     // to 0s
125     std::memcpy(req->blobId, blobId.c_str(), blobId.length());
126 
127     dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
128 
129     struct BlobMeta lmeta;
130     lmeta.blobState = 0x01;
131     lmeta.size = 0x100;
132     lmeta.metadata.push_back(0x01);
133     lmeta.metadata.push_back(0x02);
134     lmeta.metadata.push_back(0x03);
135     lmeta.metadata.push_back(0x04);
136 
137     struct BmcBlobStatRx rep;
138     rep.crc = 0x00;
139     rep.blobState = lmeta.blobState;
140     rep.size = lmeta.size;
141     rep.metadataLen = lmeta.metadata.size();
142 
143     EXPECT_CALL(mgr, stat(Matcher<const std::string&>(StrEq(blobId)),
144                           Matcher<struct BlobMeta*>(NotNull())))
145         .WillOnce(Invoke([&](const std::string& path, struct BlobMeta* meta) {
146             (*meta) = lmeta;
147             return true;
148         }));
149 
150     EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
151 
152     EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), dataLen);
153     EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
154     EXPECT_EQ(0, std::memcmp(reply + sizeof(rep), lmeta.metadata.data(),
155                              lmeta.metadata.size()));
156 }
157 } // namespace blobs
158