blob: 603c0c6d8c500db4603af208c073da35c6b3f6d0 [file] [log] [blame]
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05301#include "libpldmresponder/file_io.hpp"
Sampa Misra854e61f2019-08-22 04:36:47 -05002#include "libpldmresponder/file_io_by_type.hpp"
3#include "libpldmresponder/file_io_type_pel.hpp"
Tom Joseph0c6d22c2019-06-26 09:58:41 +05304#include "libpldmresponder/file_table.hpp"
Sampa Misra854e61f2019-08-22 04:36:47 -05005#include "xyz/openbmc_project/Common/error.hpp"
Tom Joseph0c6d22c2019-06-26 09:58:41 +05306
7#include <filesystem>
8#include <fstream>
9#include <nlohmann/json.hpp>
Sampa Misra854e61f2019-08-22 04:36:47 -050010#include <phosphor-logging/elog-errors.hpp>
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +053011
12#include "libpldm/base.h"
13#include "libpldm/file_io.h"
14
15#include <gmock/gmock-matchers.h>
16#include <gmock/gmock.h>
17#include <gtest/gtest.h>
Tom Joseph0c6d22c2019-06-26 09:58:41 +053018
Tom Joseph0c6d22c2019-06-26 09:58:41 +053019namespace fs = std::filesystem;
20using Json = nlohmann::json;
21using namespace pldm::filetable;
22
23class TestFileTable : public testing::Test
24{
25 public:
26 void SetUp() override
27 {
28 // Create a temporary directory to hold the config file and files to
29 // populate the file table.
30 char tmppldm[] = "/tmp/pldm_fileio_table.XXXXXX";
31 dir = fs::path(mkdtemp(tmppldm));
32
33 // Copy the sample image files to the directory
34 fs::copy("./files", dir);
35
36 imageFile = dir / "NVRAM-IMAGE";
37 auto jsonObjects = Json::array();
38 auto obj = Json::object();
39 obj["path"] = imageFile.c_str();
40 obj["file_traits"] = 1;
41
42 jsonObjects.push_back(obj);
43 obj.clear();
44 cksumFile = dir / "NVRAM-IMAGE-CKSUM";
45 obj["path"] = cksumFile.c_str();
46 obj["file_traits"] = 4;
47 jsonObjects.push_back(obj);
48
49 fileTableConfig = dir / "configFile.json";
50 std::ofstream file(fileTableConfig.c_str());
51 file << std::setw(4) << jsonObjects << std::endl;
52 }
53
54 void TearDown() override
55 {
56 fs::remove_all(dir);
57 }
58
59 fs::path dir;
60 fs::path imageFile;
61 fs::path cksumFile;
62 fs::path fileTableConfig;
63
64 // <4 bytes - File handle - 0 (0x00 0x00 0x00 0x00)>,
65 // <2 bytes - Filename length - 11 (0x0b 0x00>
66 // <11 bytes - Filename - ASCII for NVRAM-IMAGE>
67 // <4 bytes - File size - 1024 (0x00 0x04 0x00 0x00)>
68 // <4 bytes - File traits - 1 (0x01 0x00 0x00 0x00)>
69 // <4 bytes - File handle - 1 (0x01 0x00 0x00 0x00)>,
70 // <2 bytes - Filename length - 17 (0x11 0x00>
71 // <17 bytes - Filename - ASCII for NVRAM-IMAGE-CKSUM>
72 // <4 bytes - File size - 16 (0x0f 0x00 0x00 0x00)>
73 // <4 bytes - File traits - 4 (0x04 0x00 0x00 0x00)>
74 // No pad bytes added since the length for both the file entries in the
75 // table is 56, which is a multiple of 4.
76 // <4 bytes - Checksum - 2088303182(0x4e 0xfa 0x78 0x7c)>
77 Table attrTable = {
78 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 0x2d,
79 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
80 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d,
81 0x2d, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x2d, 0x43, 0x4b, 0x53, 0x55, 0x4d,
82 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0xfa, 0x78, 0x7c};
83};
84
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +053085namespace pldm
86{
87
88namespace responder
89{
90
91namespace dma
92{
93
94class MockDMA
95{
96 public:
97 MOCK_METHOD5(transferDataHost,
98 int(const fs::path& file, uint32_t offset, uint32_t length,
99 uint64_t address, bool upstream));
100};
101
102} // namespace dma
103} // namespace responder
104} // namespace pldm
105using namespace pldm::responder;
106using ::testing::_;
107using ::testing::Return;
108
109TEST(TransferDataHost, GoodPath)
110{
111 using namespace pldm::responder::dma;
112
113 MockDMA dmaObj;
114 fs::path path("");
115
116 // Minimum length of 16 and expect transferDataHost to be called once
117 // returns the default value of 0 (the return type of transferDataHost is
118 // int, the default value for int is 0)
119 uint32_t length = minSize;
120 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
121 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530122 path, 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530123 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
124 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
125 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
126 &length, sizeof(length)));
127
128 // maxsize of DMA
129 length = maxSize;
130 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
131 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530132 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530133 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
134 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
135 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
136 &length, sizeof(length)));
137
138 // length greater than maxsize of DMA
139 length = maxSize + minSize;
140 EXPECT_CALL(dmaObj, transferDataHost(path, 0, maxSize, 0, true)).Times(1);
141 EXPECT_CALL(dmaObj, transferDataHost(path, maxSize, minSize, maxSize, true))
142 .Times(1);
143 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530144 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530145 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
146 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
147 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
148 &length, sizeof(length)));
149
150 // length greater than 2*maxsize of DMA
151 length = 3 * maxSize;
152 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, true)).Times(3);
153 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530154 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530155 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
156 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
157 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
158 &length, sizeof(length)));
159
160 // check for downstream(copy data from host to BMC) parameter
161 length = minSize;
162 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, false)).Times(1);
163 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530164 0, length, 0, false, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530165 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
166 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
167 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
168 &length, sizeof(length)));
169}
170
171TEST(TransferDataHost, BadPath)
172{
173 using namespace pldm::responder::dma;
174
175 MockDMA dmaObj;
176 fs::path path("");
177
178 // Minimum length of 16 and transferDataHost returning a negative errno
179 uint32_t length = minSize;
180 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1));
181 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530182 path, 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530183 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
184 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
185
186 // length greater than maxsize of DMA and transferDataHost returning a
187 // negative errno
188 length = maxSize + minSize;
189 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1));
190 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530191 0, length, 0, true, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530192 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
193 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
194}
195
196TEST(ReadFileIntoMemory, BadPath)
197{
198 uint32_t fileHandle = 0;
199 uint32_t offset = 0;
200 uint32_t length = 10;
201 uint64_t address = 0;
202
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500203 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
204 requestMsg{};
205 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
206 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
207 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
208 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530209 sizeof(length));
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500210 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530211 sizeof(length),
212 &address, sizeof(address));
213
214 // Pass invalid payload length
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500215 auto response = readFileIntoMemory(request, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530216 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
217 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
218}
219
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530220TEST_F(TestFileTable, ReadFileInvalidFileHandle)
221{
222 // Invalid file handle in the file table
223 uint32_t fileHandle = 2;
224 uint32_t offset = 0;
225 uint32_t length = 0;
226 uint64_t address = 0;
227
228 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
229 requestMsg{};
230 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
231 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
232 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
233 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
234 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
235 sizeof(length));
236 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
237 sizeof(length),
238 &address, sizeof(address));
239
240 using namespace pldm::filetable;
241 // Initialise the file table with 2 valid file handles 0 & 1.
242 auto& table = buildFileTable(fileTableConfig.c_str());
243
244 auto response = readFileIntoMemory(request, requestPayloadLength);
245 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
246 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
247 // Clear the file table contents.
248 table.clear();
249}
250
251TEST_F(TestFileTable, ReadFileInvalidOffset)
252{
253 uint32_t fileHandle = 0;
254 // The file size is 1024, so the offset is invalid
255 uint32_t offset = 1024;
256 uint32_t length = 0;
257 uint64_t address = 0;
258
259 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
260 requestMsg{};
261 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
262 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
263 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
264 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
265 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
266 sizeof(length));
267 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
268 sizeof(length),
269 &address, sizeof(address));
270
271 using namespace pldm::filetable;
272 auto& table = buildFileTable(fileTableConfig.c_str());
273
274 auto response = readFileIntoMemory(request, requestPayloadLength);
275 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
276 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
277 // Clear the file table contents.
278 table.clear();
279}
280
281TEST_F(TestFileTable, ReadFileInvalidLength)
282{
283 uint32_t fileHandle = 0;
284 uint32_t offset = 100;
285 // Length should be a multiple of dma min size(16)
286 uint32_t length = 10;
287 uint64_t address = 0;
288
289 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
290 requestMsg{};
291 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
292 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
293 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
294 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
295 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
296 sizeof(length));
297 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
298 sizeof(length),
299 &address, sizeof(address));
300
301 using namespace pldm::filetable;
302 auto& table = buildFileTable(fileTableConfig.c_str());
303
304 auto response = readFileIntoMemory(request, requestPayloadLength);
305 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
306 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
307 // Clear the file table contents.
308 table.clear();
309}
310
311TEST_F(TestFileTable, ReadFileInvalidEffectiveLength)
312{
313 uint32_t fileHandle = 0;
314 // valid offset
315 uint32_t offset = 100;
316 // length + offset exceeds the size, so effective length is
317 // filesize(1024) - offset(100). The effective length is not a multiple of
318 // DMA min size(16)
319 uint32_t length = 1024;
320 uint64_t address = 0;
321
322 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
323 requestMsg{};
324 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
325 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
326 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
327 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
328 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
329 sizeof(length));
330 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
331 sizeof(length),
332 &address, sizeof(address));
333
334 using namespace pldm::filetable;
335 auto& table = buildFileTable(fileTableConfig.c_str());
336
337 auto response = readFileIntoMemory(request, requestPayloadLength);
338 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
339 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
340 // Clear the file table contents.
341 table.clear();
342}
343
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530344TEST(WriteFileFromMemory, BadPath)
345{
346 uint32_t fileHandle = 0;
347 uint32_t offset = 0;
348 uint32_t length = 10;
349 uint64_t address = 0;
350
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500351 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
352 requestMsg{};
353 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
354 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
355 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
356 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
357 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530358 sizeof(length));
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500359 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530360 sizeof(length),
361 &address, sizeof(address));
362
363 // Pass invalid payload length
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500364 auto response = writeFileFromMemory(request, 0);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530365 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
366 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
367
368 // The length field is not a multiple of DMA minsize
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500369 response = writeFileFromMemory(request, requestPayloadLength);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530370 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
371 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
372}
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530373
374TEST_F(TestFileTable, WriteFileInvalidFileHandle)
375{
376 // Invalid file handle in the file table
377 uint32_t fileHandle = 2;
378 uint32_t offset = 0;
379 uint32_t length = 16;
380 uint64_t address = 0;
381
382 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
383 requestMsg{};
384 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
385 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
386 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
387 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
388 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
389 sizeof(length));
390 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
391 sizeof(length),
392 &address, sizeof(address));
393
394 using namespace pldm::filetable;
395 // Initialise the file table with 2 valid file handles 0 & 1.
396 auto& table = buildFileTable(fileTableConfig.c_str());
397
398 auto response = writeFileFromMemory(request, requestPayloadLength);
399 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
400 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
401 // Clear the file table contents.
402 table.clear();
403}
404
405TEST_F(TestFileTable, WriteFileInvalidOffset)
406{
407 uint32_t fileHandle = 0;
408 // The file size is 1024, so the offset is invalid
409 uint32_t offset = 1024;
410 uint32_t length = 16;
411 uint64_t address = 0;
412
413 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
414 requestMsg{};
415 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
416 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
417 memcpy(request->payload, &fileHandle, sizeof(fileHandle));
418 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
419 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
420 sizeof(length));
421 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
422 sizeof(length),
423 &address, sizeof(address));
424
425 using namespace pldm::filetable;
426 // Initialise the file table with 2 valid file handles 0 & 1.
427 auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str());
428
429 auto response = writeFileFromMemory(request, requestPayloadLength);
430 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
431 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
432 // Clear the file table contents.
433 table.clear();
434}
435
436TEST(FileTable, ConfigNotExist)
437{
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530438 FileTable tableObj("");
John Wang881cde12019-10-24 15:08:48 +0800439 EXPECT_EQ(tableObj.isEmpty(), true);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530440}
441
442TEST_F(TestFileTable, ValidateFileEntry)
443{
444 FileTable tableObj(fileTableConfig.c_str());
445
446 // Test file handle 0, the file size is 1K bytes.
447 auto value = tableObj.at(0);
448 ASSERT_EQ(value.handle, 0);
449 ASSERT_EQ(strcmp(value.fsPath.c_str(), imageFile.c_str()), 0);
450 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value.fsPath)), 1024);
451 ASSERT_EQ(value.traits.value, 1);
452 ASSERT_EQ(true, fs::exists(value.fsPath));
453
454 // Test file handle 1, the file size is 16 bytes
455 auto value1 = tableObj.at(1);
456 ASSERT_EQ(value1.handle, 1);
457 ASSERT_EQ(strcmp(value1.fsPath.c_str(), cksumFile.c_str()), 0);
458 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value1.fsPath)), 16);
459 ASSERT_EQ(value1.traits.value, 4);
460 ASSERT_EQ(true, fs::exists(value1.fsPath));
461
462 // Test invalid file handle
463 ASSERT_THROW(tableObj.at(2), std::out_of_range);
464}
465
466TEST_F(TestFileTable, ValidateFileTable)
467{
468 FileTable tableObj(fileTableConfig.c_str());
469
470 // Validate file attribute table
471 auto table = tableObj();
472 ASSERT_EQ(true,
473 std::equal(attrTable.begin(), attrTable.end(), table.begin()));
474}
475
476TEST_F(TestFileTable, GetFileTableCommand)
477{
478 // Initialise the file table with a valid handle of 0 & 1
479 auto& table = buildFileTable(fileTableConfig.c_str());
480
481 uint32_t transferHandle = 0;
482 uint8_t opFlag = 0;
483 uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE;
484 uint32_t nextTransferHandle = 0;
485 uint8_t transferFlag = PLDM_START_AND_END;
486
487 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
488 requestMsg{};
489 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
490 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
491 auto request = reinterpret_cast<pldm_get_file_table_req*>(
492 requestMsg.data() + sizeof(pldm_msg_hdr));
493 request->transfer_handle = transferHandle;
494 request->operation_flag = opFlag;
495 request->table_type = type;
496
497 auto response = getFileTable(requestMsgPtr, requestPayloadLength);
498 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
499 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
500 size_t offsetSize = sizeof(responsePtr->payload[0]);
501 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle,
502 sizeof(nextTransferHandle)));
503 offsetSize += sizeof(nextTransferHandle);
504 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag,
505 sizeof(transferFlag)));
506 offsetSize += sizeof(transferFlag);
507 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(),
508 attrTable.size()));
509 table.clear();
510}
511
512TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch)
513{
514 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
515 requestMsg{};
516 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
517
518 // Pass invalid command payload length
519 auto response = getFileTable(request, 0);
520 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
521 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
522}
523
524TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable)
525{
526 uint32_t transferHandle = 0;
527 uint8_t opFlag = 0;
528 uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE;
529
530 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
531 requestMsg{};
532 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
533 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
534 auto request = reinterpret_cast<pldm_get_file_table_req*>(
535 requestMsg.data() + sizeof(pldm_msg_hdr));
536 request->transfer_handle = transferHandle;
537 request->operation_flag = opFlag;
538 request->table_type = type;
539
540 auto response = getFileTable(requestMsgPtr, requestPayloadLength);
541 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
542 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE);
543}
vkaverap5b914c32019-06-30 22:23:54 -0500544
545TEST_F(TestFileTable, ReadFileBadPath)
546{
547 uint32_t fileHandle = 1;
548 uint32_t offset = 0;
549 uint32_t length = 0x4;
550
551 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
552 requestMsg{};
553 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
554 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
555 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() +
556 sizeof(pldm_msg_hdr));
557
558 request->file_handle = fileHandle;
559 request->offset = offset;
560 request->length = length;
561
562 using namespace pldm::filetable;
563 // Initialise the file table with 2 valid file handles 0 & 1.
564 auto& table = buildFileTable(fileTableConfig.c_str());
565
566 // Invalid payload length
567 auto response = readFile(requestMsgPtr, 0);
568 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
569 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
570
571 // Data out of range. File size is 1024, offset = 1024 is invalid.
572 request->offset = 1024;
573
574 response = readFile(requestMsgPtr, payload_length);
575 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
576 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
577
578 // Invalid file handle
579 request->file_handle = 2;
580
581 response = readFile(requestMsgPtr, payload_length);
582 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
583 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
584
585 table.clear();
586}
587
588TEST_F(TestFileTable, ReadFileGoodPath)
589{
590 uint32_t fileHandle = 0;
591 uint32_t offset = 0;
592 uint32_t length = 0x4;
593
594 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
595 requestMsg{};
596 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
597 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
598 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() +
599 sizeof(pldm_msg_hdr));
600
601 request->file_handle = fileHandle;
602 request->offset = offset;
603 request->length = length;
604
605 using namespace pldm::filetable;
606 // Initialise the file table with 2 valid file handles 0 & 1.
607 auto& table = buildFileTable(fileTableConfig.c_str());
608 FileEntry value{};
609 value = table.at(fileHandle);
610
611 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
612 stream.seekg(offset);
613 std::vector<char> buffer(length);
614 stream.read(buffer.data(), length);
615
616 auto responseMsg = readFile(requestMsgPtr, payload_length);
617 auto response = reinterpret_cast<pldm_read_file_resp*>(
618 responseMsg.data() + sizeof(pldm_msg_hdr));
619 ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
620 ASSERT_EQ(response->length, length);
621 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), length));
622
623 // Test condition offset + length > fileSize;
624 size_t fileSize = 1024;
625 request->offset = 1023;
626 request->length = 10;
627
628 stream.seekg(request->offset);
629 buffer.resize(fileSize - request->offset);
630 stream.read(buffer.data(), (fileSize - request->offset));
631
632 responseMsg = readFile(requestMsgPtr, payload_length);
633 response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() +
634 sizeof(pldm_msg_hdr));
635 ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
636 ASSERT_EQ(response->length, (fileSize - request->offset));
637 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(),
638 (fileSize - request->offset)));
639
640 table.clear();
641}
642
643TEST_F(TestFileTable, WriteFileBadPath)
644{
645 uint32_t fileHandle = 0;
646 uint32_t offset = 0;
647 uint32_t length = 0x10;
648
649 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
650 PLDM_WRITE_FILE_REQ_BYTES + length);
651 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
652 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
653 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() +
654 sizeof(pldm_msg_hdr));
655
656 using namespace pldm::filetable;
657 // Initialise the file table with 2 valid file handles 0 & 1.
658 auto& table = buildFileTable(fileTableConfig.c_str());
659
660 request->file_handle = fileHandle;
661 request->offset = offset;
662 request->length = length;
663
664 // Invalid payload length
665 auto response = writeFile(requestMsgPtr, 0);
666 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
667 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
668
669 // Data out of range. File size is 1024, offset = 1024 is invalid.
670 request->offset = 1024;
671
672 response = writeFile(requestMsgPtr, payload_length);
673 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
674 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
675
676 // Invalid file handle
677 request->file_handle = 2;
678
679 response = writeFile(requestMsgPtr, payload_length);
680 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
681 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
682
683 table.clear();
684}
685
686TEST_F(TestFileTable, WriteFileGoodPath)
687{
688 uint32_t fileHandle = 1;
689 uint32_t offset = 0;
690 std::array<uint8_t, 4> fileData = {0x41, 0x42, 0x43, 0x44};
691 uint32_t length = fileData.size();
692
693 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
694 PLDM_WRITE_FILE_REQ_BYTES + length);
695 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
696 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
697 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() +
698 sizeof(pldm_msg_hdr));
699
700 using namespace pldm::filetable;
701 // Initialise the file table with 2 valid file handles 0 & 1.
702 auto& table = buildFileTable(fileTableConfig.c_str());
703 FileEntry value{};
704 value = table.at(fileHandle);
705
706 request->file_handle = fileHandle;
707 request->offset = offset;
708 request->length = length;
709 memcpy(request->file_data, fileData.data(), fileData.size());
710
711 auto responseMsg = writeFile(requestMsgPtr, payload_length);
712 auto response = reinterpret_cast<pldm_read_file_resp*>(
713 responseMsg.data() + sizeof(pldm_msg_hdr));
714
715 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
716 stream.seekg(offset);
717 std::vector<char> buffer(length);
718 stream.read(buffer.data(), length);
719
720 ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
721 ASSERT_EQ(response->length, length);
722 ASSERT_EQ(0, memcmp(fileData.data(), buffer.data(), length));
723
724 table.clear();
725}
Sampa Misra854e61f2019-08-22 04:36:47 -0500726
727TEST(writeFileByTypeFromMemory, testBadPath)
728{
729 const auto hdr_size = sizeof(pldm_msg_hdr);
730 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES>
731 requestMsg{};
732 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
733 size_t requestPayloadLength = requestMsg.size() - hdr_size;
734 struct pldm_read_write_file_by_type_memory_req* request =
735 reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>(
736 req->payload);
737 request->file_type = PLDM_FILE_TYPE_PEL;
738 request->file_handle = 0xFFFFFFFF;
739 request->offset = 0;
740 request->length = 17;
741 request->address = 0;
742
743 auto response = writeFileByTypeFromMemory(req, 0);
744 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
745
746 struct pldm_read_write_file_by_type_memory_resp* resp =
747 reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
748 responsePtr->payload);
749 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
750
751 response = writeFileByTypeFromMemory(req, requestPayloadLength);
752 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
753
754 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
755 responsePtr->payload);
756 ASSERT_EQ(PLDM_INVALID_WRITE_LENGTH, resp->completion_code);
757}
758
759TEST(getHandlerByType, allPaths)
760{
761 uint32_t fileHandle{};
762 auto handler = getHandlerByType(PLDM_FILE_TYPE_PEL, fileHandle);
763 auto pelType = dynamic_cast<PelHandler*>(handler.get());
764 ASSERT_TRUE(pelType != nullptr);
765
766 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
767 ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure);
768}