blob: 2f064f87df65eab9e4fca6353c15d843fad3ae01 [file]
#include "libpldmresponder/base.hpp"
#include "libpldmresponder/file_transfer.hpp"
#include "libpldmresponder/platform.hpp"
#include <libpldm/base.h>
#include <libpldm/edac.h>
#include <libpldm/file.h>
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <numeric>
#include <random>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace fs = std::filesystem;
using namespace pldm::responder;
using namespace pldm::responder::file_transfer;
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
// Test fixture for the standalone fileRead function
class FileReadTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Create a temporary file with known content
char tmppath[] = "/tmp/pldm_fileread_test.XXXXXX";
dir = fs::path(mkdtemp(tmppath));
testFilePath = dir / "testfile.bin";
std::ofstream testFile(testFilePath, std::ios::binary);
fileContent.resize(256);
std::iota(fileContent.begin(), fileContent.end(), 0);
testFile.write(reinterpret_cast<const char*>(fileContent.data()),
fileContent.size());
testFile.close();
fileSize = fileContent.size();
}
void TearDown() override
{
fs::remove_all(dir);
}
fs::path dir;
fs::path testFilePath;
std::vector<uint8_t> fileContent;
uint32_t fileSize;
};
TEST_F(FileReadTest, SuccessCases)
{
FILE* fp = fopen(testFilePath.c_str(), "rb");
ASSERT_NE(fp, nullptr);
// Read from start
uint32_t readSize = 64;
std::vector<uint8_t> buffer(readSize);
EXPECT_EQ(fileRead(fp, fileSize, 0, readSize, buffer.data()), 0);
EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data(), readSize));
// Read from middle
uint32_t offset = 100;
readSize = 50;
buffer.resize(readSize);
EXPECT_EQ(fileRead(fp, fileSize, offset, readSize, buffer.data()), 0);
EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data() + offset, readSize));
// Test case where offset + readSize == fileSize
offset = 128;
readSize = fileSize - offset;
buffer.resize(readSize);
EXPECT_EQ(fileRead(fp, fileSize, offset, readSize, buffer.data()), 0);
EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data() + offset, readSize));
// Read the full file
buffer.resize(fileSize);
EXPECT_EQ(fileRead(fp, fileSize, 0, fileSize, buffer.data()), 0);
EXPECT_EQ(buffer, fileContent);
fclose(fp);
}
TEST_F(FileReadTest, FailureCases)
{
std::vector<uint8_t> buffer(10);
// Null file pointer
EXPECT_EQ(fileRead(nullptr, fileSize, 0, 10, buffer.data()), -1);
FILE* fp = fopen(testFilePath.c_str(), "rb");
ASSERT_NE(fp, nullptr);
// Null data buffer
EXPECT_EQ(fileRead(fp, fileSize, 0, 10, nullptr), -1);
// Offset >= fileSize
EXPECT_EQ(fileRead(fp, fileSize, fileSize, 1, buffer.data()), -1);
EXPECT_EQ(fileRead(fp, fileSize, fileSize + 1, 1, buffer.data()), -1);
// Read size > fileSize
std::vector<uint8_t> largeBuffer(fileSize + 1);
EXPECT_EQ(fileRead(fp, fileSize, 0, fileSize + 1, largeBuffer.data()), -1);
// Read would go beyond file
EXPECT_EQ(fileRead(fp, fileSize, fileSize - 5, 10, buffer.data()), -1);
fclose(fp);
}
class FileTransferTests : public ::testing::Test
{
protected:
FileTransferTests() :
event(sdeventplus::Event::get_default()),
// platform::Handler needs a valid directory for PDRs
pdrDir(fs::temp_directory_path() / "pldm_pdr"),
pdrRepo(pldm_pdr_init(), pldm_pdr_destroy),
platformHandler(nullptr, 0, nullptr, pdrDir, pdrRepo.get(), nullptr,
nullptr, nullptr, nullptr, nullptr, event, true),
baseHandler(event), handler(&baseHandler, &platformHandler)
{
baseHandler.registerMultipartReceiveHandler(PLDM_FILE, &handler);
}
void SetUp() override
{
// Create a directory to hold the PDR JSON files
fs::create_directories(pdrDir);
// Create a target file that the PDR will point to
char tmppath[] = "/tmp/pldm_target_file.XXXXXX";
targetFileDir = fs::path(mkdtemp(tmppath));
targetFilePath = targetFileDir / "testfile.bin";
fileContent.resize(400);
// Assign random values to the file
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(0, 255);
std::generate(fileContent.begin(), fileContent.end(),
[&]() { return distrib(gen); });
std::ofstream testFile(targetFilePath, std::ios::binary);
testFile.write(reinterpret_cast<const char*>(fileContent.data()),
fileContent.size());
}
void TearDown() override
{
// Clean up the created directories and files
fs::remove_all(targetFileDir);
fs::remove_all(pdrDir);
}
/**
* @brief Creates a PDR JSON file to set up the platform handler's state
*
* @param fileIdentifier The identifier for the file PDR
* @param filePath The path to the file on disk
*/
void setupPDR(uint16_t fileIdentifier, const fs::path& filePath,
pldm_tid_t tid = 0)
{
uint32_t fileSize = fs::file_size(filePath);
// Construct the JSON content
nlohmann::json pdrJson = {
{"fileDescriptorPDRs",
{{{"entries",
{{{"EntityType", 9},
{"Path", targetFileDir.string()},
{"Files",
{{{"FileIdentifier", fileIdentifier},
{"FileName", filePath.filename().string()},
{"FileSize", fileSize}}}}}}}}}}};
// Write the JSON to a file in the PDR directory
std::ofstream jsonFile(pdrDir / "test_pdr.json");
jsonFile << pdrJson;
jsonFile.close();
uint32_t handle = 0;
do
{
std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
getPdrReq{};
auto req = reinterpret_cast<pldm_msg*>(getPdrReq.data());
auto reqPayload = reinterpret_cast<pldm_get_pdr_req*>(req->payload);
reqPayload->record_handle = handle;
reqPayload->request_count = 100;
auto respMsg =
platformHandler.getPDR(tid, req, PLDM_GET_PDR_REQ_BYTES);
if (respMsg.size() <
sizeof(pldm_msg_hdr) + sizeof(pldm_get_pdr_resp))
{
std::cerr << "getPDR failed with cc: "
<< (int)respMsg[sizeof(pldm_msg_hdr)] << std::endl;
break;
}
auto respPtr = reinterpret_cast<pldm_msg*>(respMsg.data());
auto respPayload =
reinterpret_cast<pldm_get_pdr_resp*>(respPtr->payload);
handle = respPayload->next_record_handle;
} while (handle != 0);
}
sdeventplus::Event event;
fs::path pdrDir;
std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> pdrRepo;
pldm::responder::platform::Handler platformHandler;
pldm::responder::base::Handler baseHandler;
pldm::responder::file_transfer::Handler handler;
fs::path targetFileDir;
fs::path targetFilePath;
std::vector<uint8_t> fileContent;
};
// Verify successfully opening a file
TEST_F(FileTransferTests, DfOpenSuccess)
{
uint16_t fileIdentifier = 1;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> request_msg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
struct pldm_msg* openRequest =
reinterpret_cast<struct pldm_msg*>(request_msg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int encode_rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&requestPayloadLength);
ASSERT_EQ(encode_rc, 0);
auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
ASSERT_GE(response.size(), sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_RESP_BYTES);
struct pldm_file_df_open_resp decoded_resp{};
decode_pldm_file_df_open_resp(
responsePtr, response.size() - sizeof(pldm_msg_hdr), &decoded_resp);
ASSERT_EQ(decoded_resp.completion_code, PLDM_SUCCESS);
}
// Invalid DfOpen request length
TEST_F(FileTransferTests, InvalidDfOpenRequestLength)
{
pldm_msg request{};
// Use an incorrect payload length
size_t invalidPayloadLength = PLDM_DF_OPEN_REQ_BYTES - 1;
// FIX: Use the correct 'handle' method name
auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, &request,
invalidPayloadLength);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
EXPECT_EQ(responsePtr->payload[0], PLDM_ERROR);
}
// Successfully open a file and read a section
TEST_F(FileTransferTests, DfOpenAndRead)
{
// Setup PDR for the test file
uint16_t fileIdentifier = 1;
setupPDR(fileIdentifier, targetFilePath);
// Open the file via dfOpen
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Read a portion of the file via dfRead
uint32_t offset = 10;
uint32_t lengthToRead = 64;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = 0;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handlers
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
// Verify the response
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END);
EXPECT_EQ(resp.data.length, lengthToRead);
const uint8_t* responseData = resp.data.ptr;
EXPECT_EQ(0,
memcmp(responseData, fileContent.data() + offset, lengthToRead));
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(responseData, lengthToRead));
}
// Opening a file with an invalid file identifier
TEST_F(FileTransferTests, InvalidFileIdentifier)
{
// Setup: We set up a PDR for a specific ID.
uint16_t validFileIdentifier = 1;
setupPDR(validFileIdentifier, targetFilePath);
// Create request for a DIFFERENT, invalid ID.
uint16_t invalidFileIdentifier = 99;
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = invalidFileIdentifier;
size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int encode_rc =
encode_pldm_file_df_open_req(0, &req, request, &requestPayloadLength);
ASSERT_EQ(encode_rc, 0);
// Process request and check for the expected error.
auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, request,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
struct pldm_file_df_open_resp decodedOpenResp{};
ASSERT_EQ(decode_pldm_file_df_open_resp(
responsePtr, response.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp),
0);
ASSERT_EQ(decodedOpenResp.completion_code,
PLDM_FILE_CC_INVALID_FILE_IDENTIFIER);
}
// Successfully open a file and close it
TEST_F(FileTransferTests, OpenAndClose)
{
uint16_t fileIdentifier = 1;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openeRquestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
struct pldm_msg* openRequest =
reinterpret_cast<struct pldm_msg*>(openeRquestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int encode_rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&requestPayloadLength);
ASSERT_EQ(encode_rc, 0);
// Send the request to the handler
auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
struct pldm_file_df_open_resp decoded_resp{};
decode_pldm_file_df_open_resp(
responsePtr, response.size() - sizeof(pldm_msg_hdr), &decoded_resp);
uint16_t new_fd = decoded_resp.file_descriptor;
std::vector<uint8_t> closeRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES);
struct pldm_msg* closeRequest =
reinterpret_cast<struct pldm_msg*>(closeRequestMsg.data());
struct pldm_file_df_close_req close_req{};
close_req.file_descriptor = new_fd;
size_t closePayloadLength = PLDM_DF_CLOSE_REQ_BYTES;
encode_rc = encode_pldm_file_df_close_req(0, &close_req, closeRequest,
&closePayloadLength);
ASSERT_EQ(encode_rc, 0);
// Send the request to the handler
auto close_response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE,
closeRequest, PLDM_DF_CLOSE_REQ_BYTES);
ASSERT_NE(close_response.data(), nullptr);
auto closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data());
EXPECT_EQ(closeResponsePtr->payload[0], PLDM_SUCCESS);
}
// Close with a invalid file descriptor
TEST_F(FileTransferTests, DfCloseInvalidFileDescriptor)
{
// Attempt to close a file descriptor that was never opened.
uint16_t invalidFileDescriptor = 999;
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
struct pldm_file_df_close_req req{};
req.file_descriptor = invalidFileDescriptor;
size_t payloadLength = PLDM_DF_CLOSE_REQ_BYTES;
int rc = encode_pldm_file_df_close_req(0, &req, request, &payloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE, request,
PLDM_DF_CLOSE_REQ_BYTES);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
EXPECT_EQ(responsePtr->payload[0], PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR);
}
// Invalid DfClose request length
TEST_F(FileTransferTests, DfCloseInvalidRequestLength)
{
// Attempt to close with an incorrect payload length.
uint16_t fileDescriptor = 123; // Can be any value
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
struct pldm_file_df_close_req req{};
req.file_descriptor = fileDescriptor;
size_t payloadLength = PLDM_DF_CLOSE_REQ_BYTES;
int rc = encode_pldm_file_df_close_req(0, &req, request, &payloadLength);
ASSERT_EQ(rc, 0);
// Use an invalid length
size_t invalidPayloadLength = PLDM_DF_CLOSE_REQ_BYTES - 1;
auto response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE, request,
invalidPayloadLength);
ASSERT_NE(response.data(), nullptr);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
EXPECT_EQ(responsePtr->payload[0], PLDM_ERROR);
}
// Open and read a file completely with multiple multipart request messages
TEST_F(FileTransferTests, DfReadCompleteFile)
{
uint16_t fileIdentifier = 2;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Initialize variables for multi-part read
uint32_t offset = 0;
uint32_t transferHandle = 0;
uint8_t transferFlag = PLDM_XFER_FIRST_PART;
std::vector<uint8_t> receivedData;
uint32_t lengthToRead = fileContent.size();
uint32_t final_checksum = 0;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
// Read the file in multiple parts
while (transferFlag != PLDM_END && transferFlag != PLDM_START_AND_END)
{
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = transferFlag;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = transferHandle;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr,
readResponse.size() - sizeof(pldm_msg_hdr), &resp,
&data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
transferFlag = resp.transfer_flag;
final_checksum = data_integrity_checksum;
uint32_t dataLengthBytes = resp.data.length;
const uint8_t* responseData = resp.data.ptr;
receivedData.insert(receivedData.end(), responseData,
responseData + dataLengthBytes);
offset += dataLengthBytes;
transferHandle = offset; // Update transferHandle for next request
lengthToRead = 0;
offset = 0;
}
// Verify that all data has been read correctly
ASSERT_EQ(receivedData.size(), fileContent.size());
EXPECT_EQ(0, memcmp(receivedData.data(), fileContent.data(),
fileContent.size()));
EXPECT_EQ(final_checksum,
pldm_edac_crc32(fileContent.data(), fileContent.size()));
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_COMPLETE;
read_req.transfer_ctx = fileDescriptor;
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_ACKNOWLEDGE_COMPLETION);
}
// Open and read a file at a given offset
TEST_F(FileTransferTests, DfReadWithOffset)
{
uint16_t fileIdentifier = 3;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
uint32_t offset = 35;
uint32_t lengthToRead = 100;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = 0;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END);
EXPECT_EQ(resp.data.length, lengthToRead);
const uint8_t* responseData = resp.data.ptr;
EXPECT_EQ(0,
memcmp(responseData, fileContent.data() + offset, lengthToRead));
}
// Open and read a file then restart read without closing the file
TEST_F(FileTransferTests, DfReadRestart)
{
uint16_t fileIdentifier = 4;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
uint32_t offset1 = 0;
uint32_t lengthToRead1 = 100;
std::vector<uint8_t> readRequestMsg1(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest1 = reinterpret_cast<pldm_msg*>(readRequestMsg1.data());
size_t readRequestPayloadLength1 = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset1;
read_req1.section_length = lengthToRead1;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest1,
&readRequestPayloadLength1);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse1 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest1,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse1.data(), nullptr);
auto readResponsePtr1 = reinterpret_cast<pldm_msg*>(readResponse1.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END);
EXPECT_EQ(resp.data.length, lengthToRead1);
const uint8_t* responseData1 = resp.data.ptr;
EXPECT_EQ(0, memcmp(responseData1, fileContent.data(), lengthToRead1));
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(fileContent.data(), lengthToRead1));
uint32_t offset2 = 35;
uint32_t lengthToRead2 = 200;
std::vector<uint8_t> readRequestMsg2(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest2 = reinterpret_cast<pldm_msg*>(readRequestMsg2.data());
size_t readRequestPayloadLength2 = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req2.transfer_ctx = fileDescriptor;
read_req2.transfer_handle = 0;
read_req2.section_offset = offset2;
read_req2.section_length = lengthToRead2;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest2,
&readRequestPayloadLength2);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse2 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest2,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse2.data(), nullptr);
auto readResponsePtr2 = reinterpret_cast<pldm_msg*>(readResponse2.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END);
EXPECT_EQ(resp.data.length, lengthToRead2);
const uint8_t* responseData2 = resp.data.ptr;
EXPECT_EQ(0, memcmp(responseData2, fileContent.data() + offset2,
lengthToRead2));
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(fileContent.data() + offset2, lengthToRead2));
}
// Open and read a file then re request the current part
TEST_F(FileTransferTests, DfReadCurrentPart)
{
uint16_t fileIdentifier = 5;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
uint32_t offset = 10;
uint32_t lengthToRead = 380;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
// Send the read request for the first part
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset;
read_req1.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse1 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse1.data(), nullptr);
auto readResponsePtr1 = reinterpret_cast<pldm_msg*>(readResponse1.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
uint32_t request2TransferHandle = resp.next_transfer_handle;
uint32_t dataLengthBytes = resp.data.length;
ASSERT_EQ(dataLengthBytes, 239);
ASSERT_EQ(request2TransferHandle, 239);
EXPECT_EQ(0, memcmp(readResponsePtr1->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
fileContent.data() + offset, dataLengthBytes));
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(fileContent.data() + offset, dataLengthBytes));
// Send the read request for the next part
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_NEXT_PART;
read_req2.transfer_ctx = fileDescriptor;
read_req2.transfer_handle = request2TransferHandle;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse2 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse2.data(), nullptr);
auto readResponsePtr2 = reinterpret_cast<pldm_msg*>(readResponse2.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.data.length, 141);
EXPECT_EQ(0, memcmp(readResponsePtr2->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
fileContent.data() + offset + 239, resp.data.length));
// Verify the checksum over data in both responses.
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(fileContent.data() + offset, lengthToRead));
// Try requesting the current part
struct pldm_base_multipart_receive_req read_req3{};
read_req3.pldm_type = PLDM_FILE;
read_req3.transfer_opflag = PLDM_XFER_CURRENT_PART;
read_req3.transfer_ctx = fileDescriptor;
read_req3.transfer_handle = request2TransferHandle;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req3, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse3 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse3.data(), nullptr);
auto readResponsePtr3 = reinterpret_cast<pldm_msg*>(readResponse3.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr3, readResponse3.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(readResponse2.size(), readResponse3.size());
EXPECT_EQ(0, memcmp(readResponsePtr3->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
fileContent.data() + offset + 239, 141));
EXPECT_EQ(0, memcmp(readResponse2.data(), readResponse3.data(),
readResponse2.size()));
}
// Open and read the first part and then re-request the current part
TEST_F(FileTransferTests, DfReadCurrentPartAgain)
{
uint16_t fileIdentifier = 12;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
uint32_t offset = 10;
uint32_t lengthToRead = 380;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
// Send the read request for the first part
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset;
read_req1.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse1 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse1.data(), nullptr);
auto readResponsePtr1 = reinterpret_cast<pldm_msg*>(readResponse1.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
uint32_t dataLengthBytes = resp.data.length;
ASSERT_EQ(dataLengthBytes, 239);
EXPECT_EQ(0, memcmp(readResponsePtr1->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
fileContent.data() + offset, dataLengthBytes));
EXPECT_EQ(data_integrity_checksum,
pldm_edac_crc32(fileContent.data() + offset, dataLengthBytes));
// Try requesting the current part
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_CURRENT_PART;
read_req2.transfer_ctx = fileDescriptor;
read_req2.transfer_handle = 0;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse2 =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse2.data(), nullptr);
auto readResponsePtr2 = reinterpret_cast<pldm_msg*>(readResponse2.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(readResponse1.size(), readResponse2.size());
EXPECT_EQ(0, memcmp(readResponsePtr1->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
readResponsePtr2->payload +
PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
dataLengthBytes));
EXPECT_EQ(0, memcmp(readResponse1.data(), readResponse2.data(),
readResponse1.size()));
}
// Open and read the first part and then abort the read
TEST_F(FileTransferTests, DfReadAbort)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 9;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Send a first read request to start a transfer
uint32_t offset = 0;
uint32_t lengthToRead = 100;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset;
read_req1.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto firstReadResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(firstReadResponse.data(), nullptr);
auto firstReadResponsePtr =
reinterpret_cast<pldm_msg*>(firstReadResponse.data());
ASSERT_EQ(firstReadResponsePtr->payload[0], PLDM_SUCCESS);
// Send an abort request
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_ABORT;
read_req2.transfer_ctx = fileDescriptor;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto abortResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
// Verify the abort response
ASSERT_NE(abortResponse.data(), nullptr);
auto abortResponsePtr = reinterpret_cast<pldm_msg*>(abortResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
abortResponsePtr, abortResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
EXPECT_EQ(resp.transfer_flag, PLDM_ACKNOWLEDGE_COMPLETION);
EXPECT_EQ(resp.data.length, 0);
}
// Open the file and send a read request with an invalid transfer handle
TEST_F(FileTransferTests, DfReadFirstPartInvalidTransferHandle)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 6;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Send dfRead with non-zero transfer handle for FIRST_PART
uint32_t offset = 0;
uint32_t lengthToRead = 64;
uint32_t invalidTransferHandle = 1; // Should be 0 for FIRST_PART
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = invalidTransferHandle;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
// Verify the error response
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA);
}
// Open the file and send a read request with an invalid offset
TEST_F(FileTransferTests, DfReadFirstPartInvalidOffset)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 7;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Send dfRead with offset >= fileSize
uint32_t invalidOffset = fileContent.size(); // 400
uint32_t lengthToRead = 1;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = 0;
read_req.section_offset = invalidOffset;
read_req.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
// Verify the error response
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA);
}
// Open the file and send a read request with an invalid read length
TEST_F(FileTransferTests, DfReadFirstPartInvalidLength)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 8;
setupPDR(fileIdentifier, targetFilePath);
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Send dfRead with offset + length > fileSize
uint32_t offset = 100;
uint32_t invalidLength = fileContent.size() - offset + 1; // 301
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = 0;
read_req.section_offset = offset;
read_req.section_length = invalidLength;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
// Verify the error response
ASSERT_NE(readResponse.data(), nullptr);
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA);
}
// A client with a different TID should not be able to access the file
// descriptor.
TEST_F(FileTransferTests, DfOperationWithWrongTid)
{
// Setup PDR for the test file
uint16_t fileIdentifier = 1;
setupPDR(fileIdentifier, targetFilePath, 1);
pldm_tid_t tid1 = 1;
pldm_tid_t tid2 = 2;
// Open the file via dfOpen from client with TID 1
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
auto openResponse = handler.handle(tid1, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Try to read a portion of the file via dfRead from client with TID 2
uint32_t offset = 10;
uint32_t lengthToRead = 64;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = fileDescriptor;
read_req.transfer_handle = 0;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handlers from client with TID 2
auto readResponse =
baseHandler.handle(tid2, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
// Verify the response
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR);
// Try to close the file from client with TID 2
std::vector<uint8_t> closeRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES);
struct pldm_msg* closeRequest =
reinterpret_cast<struct pldm_msg*>(closeRequestMsg.data());
struct pldm_file_df_close_req close_req{};
close_req.file_descriptor = fileDescriptor;
size_t closePayloadLength = PLDM_DF_CLOSE_REQ_BYTES;
rc = encode_pldm_file_df_close_req(0, &close_req, closeRequest,
&closePayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto close_response = handler.handle(tid2, PLDM_FILE_CMD_DF_CLOSE,
closeRequest, PLDM_DF_CLOSE_REQ_BYTES);
ASSERT_NE(close_response.data(), nullptr);
auto closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data());
EXPECT_EQ(closeResponsePtr->payload[0],
PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR);
// Read a portion of the file via dfRead from client with TID 1
readResponse = baseHandler.handle(tid1, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
// Close the file from client with TID 1
close_response = handler.handle(tid1, PLDM_FILE_CMD_DF_CLOSE, closeRequest,
PLDM_DF_CLOSE_REQ_BYTES);
ASSERT_NE(close_response.data(), nullptr);
closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data());
EXPECT_EQ(closeResponsePtr->payload[0], PLDM_SUCCESS);
}
// Try to read from a file descriptor that has not been opened.
TEST_F(FileTransferTests, DfReadWithInvalidFileDescriptor)
{
// Try to read a portion of the file via dfRead from client with TID 1
uint32_t offset = 10;
uint32_t lengthToRead = 64;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req{};
read_req.pldm_type = PLDM_FILE;
read_req.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req.transfer_ctx = 0;
read_req.transfer_handle = 0;
read_req.section_offset = offset;
read_req.section_length = lengthToRead;
int rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handlers from client with TID 1
auto readResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(readResponse.data(), nullptr);
// Verify the response
auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR);
}
// Open the file and read the first part. Then send a transfer handle less than
// the start offset
TEST_F(FileTransferTests, DfReadNextPartInvalidTransferHandleTooSmall)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 10;
setupPDR(fileIdentifier, targetFilePath);
// Encode the request
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
// Send a first read request to establish starting_offset
uint32_t offset = 100;
uint32_t lengthToRead = 50;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset;
read_req1.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto firstReadResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(firstReadResponse.data(), nullptr);
auto firstReadResponsePtr =
reinterpret_cast<pldm_msg*>(firstReadResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
firstReadResponsePtr,
firstReadResponse.size() - sizeof(pldm_msg_hdr), &resp,
&data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
// Send a next part request with transfer_handle < starting_offset
uint32_t invalidTransferHandle = offset - 1;
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_NEXT_PART;
read_req2.transfer_ctx = fileDescriptor;
read_req2.transfer_handle = invalidTransferHandle;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto errorResponse = baseHandler.handle(
0, PLDM_MULTIPART_RECEIVE, readRequest, readRequestPayloadLength);
// Verify the error response
ASSERT_NE(errorResponse.data(), nullptr);
auto errorResponsePtr = reinterpret_cast<pldm_msg*>(errorResponse.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
errorResponsePtr, errorResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA);
}
// Open the file and read the first part. Then send a transfer handle greater
// than the end offset
TEST_F(FileTransferTests, DfReadNextPartInvalidTransferHandleTooLarge)
{
// Setup PDR and open the file
uint16_t fileIdentifier = 11;
setupPDR(fileIdentifier, targetFilePath);
// Encode the request
std::vector<uint8_t> openRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES);
auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data());
struct pldm_file_df_open_req req{};
req.file_identifier = fileIdentifier;
size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES;
int rc = encode_pldm_file_df_open_req(0, &req, openRequest,
&openRequestPayloadLength);
ASSERT_EQ(rc, 0);
// Send the request to the handler
auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest,
PLDM_DF_OPEN_REQ_BYTES);
// Verify the response
ASSERT_NE(openResponse.data(), nullptr);
auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data());
struct pldm_file_df_open_resp decodedOpenResp{};
decode_pldm_file_df_open_resp(openResponsePtr,
openResponse.size() - sizeof(pldm_msg_hdr),
&decodedOpenResp);
ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS);
// Send a first read request to establish starting_offset and section_length
uint16_t fileDescriptor = decodedOpenResp.file_descriptor;
uint32_t offset = 100;
uint32_t lengthToRead = 50;
std::vector<uint8_t> readRequestMsg(
sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES);
auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data());
size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
struct pldm_base_multipart_receive_req read_req1{};
read_req1.pldm_type = PLDM_FILE;
read_req1.transfer_opflag = PLDM_XFER_FIRST_PART;
read_req1.transfer_ctx = fileDescriptor;
read_req1.transfer_handle = 0;
read_req1.section_offset = offset;
read_req1.section_length = lengthToRead;
rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
auto firstReadResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
ASSERT_NE(firstReadResponse.data(), nullptr);
auto firstReadResponsePtr =
reinterpret_cast<pldm_msg*>(firstReadResponse.data());
uint32_t data_integrity_checksum;
pldm_base_multipart_receive_resp resp;
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
firstReadResponsePtr,
firstReadResponse.size() - sizeof(pldm_msg_hdr), &resp,
&data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_SUCCESS);
// Send a next part request with transfer_handle >= starting_offset +
// section_length
uint32_t invalidTransferHandle = offset + lengthToRead;
struct pldm_base_multipart_receive_req read_req2{};
read_req2.pldm_type = PLDM_FILE;
read_req2.transfer_opflag = PLDM_XFER_NEXT_PART;
read_req2.transfer_ctx = fileDescriptor;
read_req2.transfer_handle = invalidTransferHandle;
readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES;
rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
&readRequestPayloadLength);
ASSERT_EQ(rc, 0);
auto errorResponse =
baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
PLDM_MULTIPART_RECEIVE_REQ_BYTES);
// Verify the error response
ASSERT_NE(errorResponse.data(), nullptr);
auto errorResponsePtr = reinterpret_cast<pldm_msg*>(errorResponse.data());
ASSERT_EQ(decode_pldm_base_multipart_receive_resp(
errorResponsePtr, errorResponse.size() - sizeof(pldm_msg_hdr),
&resp, &data_integrity_checksum),
0);
EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA);
}