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