blob: 606737773b18ada38502e5dea102d1be382f6d90 [file] [log] [blame]
#include <string.h>
#include <pw_unit_test/framework.h>
#include <lib/support/tests/ExtraPwTestMacros.h>
#include <protocols/bdx/BdxTransferDiagnosticLog.h>
#include <system/RAIIMockClock.h>
#include <system/SystemClock.h>
#include <system/SystemTimer.h>
using namespace ::chip;
using namespace ::chip::bdx;
using namespace ::chip::Protocols;
using namespace ::chip::System::Clock::Literals;
namespace {
constexpr uint16_t kMaxBlockSize = 512;
constexpr chip::FabricIndex kFabricIndex = 1;
constexpr chip::NodeId kNodeId = 2;
constexpr uint8_t kMetaDataLength = 5;
constexpr uint8_t kMetaData[kMetaDataLength] = { 7, 6, 5, 4, 3 }; // This is not TLV but this is fine for the flows we test here
class TestTransferDiagnosticLog : public ::testing::Test
{
public:
static void SetUpTestSuite() { ASSERT_EQ(Platform::MemoryInit(), CHIP_NO_ERROR); }
static void TearDownTestSuite() { Platform::MemoryShutdown(); }
protected:
TransferSession mTransferSession{};
};
TEST_F(TestTransferDiagnosticLog, InitsDiagnosticLog)
{
System::Clock::Internal::RAIIMockClock mockClock;
EXPECT_SUCCESS(
mTransferSession.WaitForTransfer(TransferRole::kReceiver, TransferControlFlags::kSenderDrive, kMaxBlockSize, 1000_ms));
TransferInit transferInit{};
transferInit.TransferCtlOptions.ClearAll().Set(TransferControlFlags::kSenderDrive, true);
transferInit.Version = 1;
transferInit.MaxLength = static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1;
transferInit.StartOffset = 42;
transferInit.MaxBlockSize = 256;
const char testFileDes[] = "test.txt";
transferInit.FileDesLength = 8;
transferInit.FileDesignator = reinterpret_cast<const uint8_t *>(testFileDes);
transferInit.MetadataLength = kMetaDataLength;
transferInit.Metadata = kMetaData;
size_t msgSize = transferInit.MessageSize();
Encoding::LittleEndian::PacketBufferWriter bbuf(System::PacketBufferHandle::New(msgSize));
ASSERT_FALSE(bbuf.IsNull());
transferInit.WriteToBuffer(bbuf);
System::PacketBufferHandle msgBuf = bbuf.Finalize();
ASSERT_FALSE(msgBuf.IsNull());
System::PacketBufferHandle rcvBuf = System::PacketBufferHandle::NewWithData(msgBuf->Start(), msgSize);
ASSERT_FALSE(rcvBuf.IsNull());
PayloadHeader payloadHeader;
payloadHeader.SetMessageType(Protocols::BDX::Id, to_underlying(MessageType::SendInit));
CHIP_ERROR r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(rcvBuf), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
BDXTransferProxyDiagnosticLog proxyDiagnosticLog{};
r = proxyDiagnosticLog.Init(&mTransferSession);
EXPECT_EQ(r, CHIP_NO_ERROR);
}
TEST_F(TestTransferDiagnosticLog, AccpetsTransferActingAsReceiverWhileInititatorDrivesTransfer)
{
BDXTransferProxyDiagnosticLog proxyDiagnosticLog{};
TransferSession initiator;
TransferSession::TransferInitData transferInitData{ TransferControlFlags(0) };
transferInitData.TransferCtlFlags = TransferControlFlags::kSenderDrive;
transferInitData.MaxBlockSize = kMaxBlockSize;
transferInitData.StartOffset = 0;
transferInitData.Length = 1024;
const char testFileDes[] = "test.txt";
transferInitData.FileDesLength = 9;
transferInitData.FileDesignator = reinterpret_cast<const uint8_t *>(testFileDes);
transferInitData.MetadataLength = kMetaDataLength;
transferInitData.Metadata = kMetaData;
/// Init initiator (and sender) transfer session
CHIP_ERROR r = initiator.StartTransfer(TransferRole::kSender, transferInitData, System::Clock::Seconds16(10));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent initiatorEvent;
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kMsgToSend);
/// Init responder (and receiver) transfer session
r = mTransferSession.WaitForTransfer(TransferRole::kReceiver, TransferControlFlags::kSenderDrive, kMaxBlockSize,
System::Clock::Seconds16(20));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent responderEvent;
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kNone);
chip::PayloadHeader payloadHeader;
payloadHeader.SetMessageType(initiatorEvent.msgTypeData.ProtocolId, initiatorEvent.msgTypeData.MessageType);
r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(initiatorEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kInitReceived);
r = proxyDiagnosticLog.Init(&mTransferSession);
EXPECT_EQ(r, CHIP_NO_ERROR);
proxyDiagnosticLog.SetFabricIndex(kFabricIndex);
proxyDiagnosticLog.SetPeerNodeId(kNodeId);
r = proxyDiagnosticLog.Accept();
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kMsgToSend); // responder sends Accept message
}
TEST_F(TestTransferDiagnosticLog, RejectsInTheMiddleOfTransfer)
{
BDXTransferProxyDiagnosticLog proxyDiagnosticLog{};
TransferSession initiator;
TransferSession::TransferInitData transferInitData{ TransferControlFlags(0) };
transferInitData.TransferCtlFlags = TransferControlFlags::kSenderDrive;
transferInitData.MaxBlockSize = kMaxBlockSize;
transferInitData.StartOffset = 0;
transferInitData.Length = 1024;
const char testFileDes[] = "test.txt";
transferInitData.FileDesLength = 8;
transferInitData.FileDesignator = reinterpret_cast<const uint8_t *>(testFileDes);
transferInitData.MetadataLength = kMetaDataLength;
transferInitData.Metadata = kMetaData;
/// Init initiator (and sender) transfer session
CHIP_ERROR r = initiator.StartTransfer(TransferRole::kSender, transferInitData, System::Clock::Seconds16(10));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent initiatorEvent;
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kMsgToSend);
/// Init responder (and receiver) transfer session
r = mTransferSession.WaitForTransfer(TransferRole::kReceiver, TransferControlFlags::kSenderDrive, kMaxBlockSize,
System::Clock::Seconds16(20));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent responderEvent;
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kNone);
chip::PayloadHeader payloadHeader;
payloadHeader.SetMessageType(initiatorEvent.msgTypeData.ProtocolId, initiatorEvent.msgTypeData.MessageType);
r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(initiatorEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kInitReceived);
r = proxyDiagnosticLog.Init(&mTransferSession);
EXPECT_EQ(r, CHIP_NO_ERROR);
proxyDiagnosticLog.SetFabricIndex(kFabricIndex);
proxyDiagnosticLog.SetPeerNodeId(kNodeId);
r = proxyDiagnosticLog.Accept();
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kMsgToSend); // responder sends Accept message
/// Now, initiator handles SendAccept message
payloadHeader.SetMessageType(responderEvent.msgTypeData.ProtocolId, responderEvent.msgTypeData.MessageType);
r = initiator.HandleMessageReceived(payloadHeader, std::move(responderEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kAcceptReceived);
/// initiator prepares block to send
TransferSession::BlockData blockData;
const uint8_t data[] = { 1, 2, 3, 4, 5 };
blockData.Data = data;
blockData.Length = 5;
blockData.IsEof = false;
blockData.BlockCounter = 0;
EXPECT_SUCCESS(initiator.PrepareBlock(blockData));
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kMsgToSend);
EXPECT_EQ(initiatorEvent.msgTypeData.MessageType, to_underlying(MessageType::Block));
payloadHeader.SetMessageType(initiatorEvent.msgTypeData.ProtocolId, initiatorEvent.msgTypeData.MessageType);
r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(initiatorEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kBlockReceived);
/// proxy acknowledges block
r = proxyDiagnosticLog.Continue();
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kMsgToSend); // responder sends Ack message
EXPECT_EQ(responderEvent.msgTypeData.MessageType, to_underlying(MessageType::BlockAck));
/// Now, initiator handles Block Ack message
payloadHeader.SetMessageType(responderEvent.msgTypeData.ProtocolId, responderEvent.msgTypeData.MessageType);
r = initiator.HandleMessageReceived(payloadHeader, std::move(responderEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kAckReceived);
/// initiator prepares next block to send
blockData.BlockCounter = 10; // while respodner expects 1
EXPECT_SUCCESS(initiator.PrepareBlock(blockData));
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kMsgToSend);
EXPECT_EQ(initiatorEvent.msgTypeData.MessageType, to_underlying(MessageType::Block));
/// responder receives 2nd block
payloadHeader.SetMessageType(initiatorEvent.msgTypeData.ProtocolId, initiatorEvent.msgTypeData.MessageType);
r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(initiatorEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kBlockReceived);
/// proxy rejects transfer
r = proxyDiagnosticLog.Reject(CHIP_ERROR_INVALID_ARGUMENT);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kMsgToSend); // responder sends StatusReport message
/// Now, initiator handles StatusReport message
payloadHeader.SetMessageType(responderEvent.msgTypeData.ProtocolId, responderEvent.msgTypeData.MessageType);
r = initiator.HandleMessageReceived(payloadHeader, std::move(responderEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType,
TransferSession::OutputEventType::kStatusReceived); /// this implies transfer rejection got received
initiator.Reset();
mTransferSession.Reset();
proxyDiagnosticLog.Reset();
}
TEST_F(TestTransferDiagnosticLog, AccpetsTransferAndReceivesNonNullTerminatedDataCorrectly)
{
BDXTransferProxyDiagnosticLog proxyDiagnosticLog{};
TransferSession initiator;
TransferSession::TransferInitData transferInitData;
transferInitData.TransferCtlFlags = TransferControlFlags::kSenderDrive;
transferInitData.MaxBlockSize = kMaxBlockSize;
transferInitData.StartOffset = 0;
transferInitData.Length = 1024;
const char testFileDes[8] = { 't', 'e', 's', 't', '.', 't', 'x', 't' };
transferInitData.FileDesLength = 8;
transferInitData.FileDesignator = reinterpret_cast<const uint8_t *>(testFileDes);
transferInitData.MetadataLength = kMetaDataLength;
transferInitData.Metadata = kMetaData;
/// Init initiator (and sender) transfer session
CHIP_ERROR r = initiator.StartTransfer(TransferRole::kSender, transferInitData, System::Clock::Seconds16(10));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent initiatorEvent;
initiator.PollOutput(initiatorEvent, System::Clock::kZero);
EXPECT_EQ(initiatorEvent.EventType, TransferSession::OutputEventType::kMsgToSend);
/// Init responder (and receiver) transfer session
r = mTransferSession.WaitForTransfer(TransferRole::kReceiver, TransferControlFlags::kSenderDrive, kMaxBlockSize,
System::Clock::Seconds16(20));
EXPECT_EQ(r, CHIP_NO_ERROR);
TransferSession::OutputEvent responderEvent;
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kNone);
chip::PayloadHeader payloadHeader;
payloadHeader.SetMessageType(initiatorEvent.msgTypeData.ProtocolId, initiatorEvent.msgTypeData.MessageType);
r = mTransferSession.HandleMessageReceived(payloadHeader, std::move(initiatorEvent.MsgData), System::Clock::kZero);
EXPECT_EQ(r, CHIP_NO_ERROR);
mTransferSession.PollOutput(responderEvent, System::Clock::kZero);
EXPECT_EQ(responderEvent.EventType, TransferSession::OutputEventType::kInitReceived);
/// Proxy fills its file designator data member from transfer session object passed as argument
r = proxyDiagnosticLog.Init(&mTransferSession);
EXPECT_EQ(r, CHIP_NO_ERROR);
CharSpan fileDesignator = proxyDiagnosticLog.GetFileDesignator();
EXPECT_TRUE(fileDesignator.data_equal(CharSpan{ testFileDes, 8 }));
}
} // namespace