1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-09 20:42:44 +03:00
Files
mvfst/quic/state/test/QPRFunctionsTest.cpp
Amaury Séchet 04c63839e4 Start splitting the fizz specific parts of the server (#160)
Summary:
This is following a similar pattern than what was done for the client side.

Pull Request resolved: https://github.com/facebookincubator/mvfst/pull/160

Reviewed By: yangchi

Differential Revision: D23560951

Pulled By: xttjsn

fbshipit-source-id: 351417cbfa3230112fff4c4de59b307f88389cf6
2020-09-08 17:17:47 -07:00

278 lines
10 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
#include <quic/server/state/ServerStateMachine.h>
#include <quic/state/QPRFunctions.h>
using namespace folly;
using namespace testing;
namespace quic {
namespace test {
class QPRFunctionsTest : public Test {
public:
QPRFunctionsTest()
: conn(std::make_shared<FizzServerQuicHandshakeContext>()) {}
void SetUp() override {
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiLocal =
kDefaultStreamWindowSize;
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote =
kDefaultStreamWindowSize;
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetUni =
kDefaultStreamWindowSize;
conn.flowControlState.peerAdvertisedMaxOffset =
kDefaultConnectionWindowSize;
conn.streamManager->setMaxLocalBidirectionalStreams(
kDefaultMaxStreamsBidirectional);
conn.streamManager->setMaxLocalUnidirectionalStreams(
kDefaultMaxStreamsUnidirectional);
conn.partialReliabilityEnabled = true;
}
QuicServerConnectionState conn;
};
TEST_F(QPRFunctionsTest, RecvExpiredStreamDataFrame) {
// case1. sending only stream
auto sendingOnlyStream =
conn.streamManager->createNextUnidirectionalStream().value();
ExpiredStreamDataFrame expiredStreamDataFrame(sendingOnlyStream->id, 10);
EXPECT_THROW(
onRecvExpiredStreamDataFrame(sendingOnlyStream, expiredStreamDataFrame),
QuicTransportException);
auto stream = conn.streamManager->createNextBidirectionalStream().value();
stream->currentReceiveOffset = 100;
expiredStreamDataFrame.streamId = stream->id;
// case2. loss reordering
expiredStreamDataFrame.minimumStreamOffset = 10;
onRecvExpiredStreamDataFrame(stream, expiredStreamDataFrame);
EXPECT_EQ(stream->currentReceiveOffset, 100);
// case3. normal case
stream->currentReadOffset = 100;
stream->conn.flowControlState.sumCurReadOffset = 100;
auto buf1 = IOBuf::copyBuffer("XXXXXXXXXX"); // 140-149
StreamBuffer buffer{buf1->clone(), 140, false};
stream->readBuffer.emplace_back(std::move(buffer));
expiredStreamDataFrame.minimumStreamOffset = 145;
onRecvExpiredStreamDataFrame(stream, expiredStreamDataFrame);
EXPECT_EQ(stream->currentReceiveOffset, 145);
EXPECT_EQ(stream->currentReadOffset, 145);
EXPECT_FALSE(stream->readBuffer.empty());
EXPECT_EQ(stream->readBuffer.front().offset, 145);
EXPECT_EQ(stream->readBuffer.front().data.chainLength(), 5);
EXPECT_EQ(stream->conn.flowControlState.sumCurReadOffset, 145);
}
TEST_F(QPRFunctionsTest, AdvanceMinimumRetransmittableOffset) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
// case 0. currentWriteOffset = 0, must be moved to 4.
stream->currentWriteOffset = 0;
auto result = advanceMinimumRetransmittableOffset(stream, 4);
EXPECT_EQ(stream->currentWriteOffset, 4);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(stream->minimumRetransmittableOffset, 4);
// case1. minimumRetransmittableOffset to set is too small
stream->minimumRetransmittableOffset = 10;
result = advanceMinimumRetransmittableOffset(stream, 1);
EXPECT_FALSE(result.has_value());
EXPECT_EQ(stream->minimumRetransmittableOffset, 10);
auto buf = folly::IOBuf::copyBuffer("aaaaaaaaaa");
// case2. has no unacked data below 139
stream->currentWriteOffset = 150;
stream->retransmissionBuffer.emplace(
140, std::make_unique<StreamBuffer>(buf->clone(), 140));
result = advanceMinimumRetransmittableOffset(stream, 139);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 139);
EXPECT_EQ(stream->minimumRetransmittableOffset, 139);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
// case3. ExpiredStreamDataFrame is wired
stream->minimumRetransmittableOffset = 139;
stream->retransmissionBuffer.emplace(
140, std::make_unique<StreamBuffer>(buf->clone(), 140));
result = advanceMinimumRetransmittableOffset(stream, 150);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 150);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
{
ExpiredStreamDataFrame* expiredFrame =
stream->conn.pendingEvents.frames[0].asExpiredStreamDataFrame();
if (expiredFrame) {
EXPECT_EQ(expiredFrame->minimumStreamOffset, 150);
}
}
EXPECT_TRUE(stream->retransmissionBuffer.empty());
// case4. update existing pending event.
stream->minimumRetransmittableOffset = 150;
stream->retransmissionBuffer.emplace(
150, std::make_unique<StreamBuffer>(buf->clone(), 150));
stream->conn.pendingEvents.frames.clear();
stream->conn.pendingEvents.frames.emplace_back(
ExpiredStreamDataFrame(stream->id, 160));
result = advanceMinimumRetransmittableOffset(stream, 200);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 200);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
{
ExpiredStreamDataFrame* expiredFrame =
stream->conn.pendingEvents.frames[0].asExpiredStreamDataFrame();
if (expiredFrame) {
EXPECT_EQ(expiredFrame->minimumStreamOffset, 200);
}
}
}
TEST_F(QPRFunctionsTest, RecvMinStreamDataFrame) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
// case1. invalid frame data
MinStreamDataFrame maximumDataLessThanMinimumStreamOffset(stream->id, 5, 10);
PacketNum packetNum(10);
EXPECT_THROW(
onRecvMinStreamDataFrame(
stream, maximumDataLessThanMinimumStreamOffset, packetNum),
QuicTransportException);
// case2. offset is less than currentMinimumRetransmittableOffset
MinStreamDataFrame offsetLessThanMinimumRetransmittableOffset(
stream->id, 1000, 100);
stream->minimumRetransmittableOffset = 1000;
onRecvMinStreamDataFrame(
stream, offsetLessThanMinimumRetransmittableOffset, packetNum);
EXPECT_EQ(stream->minimumRetransmittableOffset, 1000);
// case3. normal case
stream->minimumRetransmittableOffset = 100;
MinStreamDataFrame okMinStreamDataFrame(
stream->id, stream->flowControlState.peerAdvertisedMaxOffset, 200);
onRecvMinStreamDataFrame(stream, okMinStreamDataFrame, packetNum);
EXPECT_EQ(stream->minimumRetransmittableOffset, 200);
}
TEST_F(QPRFunctionsTest, RecvMinStreamDataFrameShrinkBuffer) {
// case 1. where we have enough bytes in writeBuffer to shrink
auto stream = conn.streamManager->createNextBidirectionalStream().value();
PacketNum packetNum(10);
stream->minimumRetransmittableOffset = 100;
stream->currentWriteOffset = 100;
auto buf = folly::IOBuf::copyBuffer("aaaaaaaaaabbbbbbbbbb");
stream->writeBuffer.append(std::move(buf));
stream->conn.flowControlState.sumCurStreamBufferLen = 20;
auto writtenBuffer = folly::IOBuf::copyBuffer("cccccccccc");
stream->retransmissionBuffer.emplace(
90, std::make_unique<StreamBuffer>(std::move(writtenBuffer), 90, false));
MinStreamDataFrame shrinkMinStreamDataFrame(
stream->id, stream->flowControlState.peerAdvertisedMaxOffset, 110);
onRecvMinStreamDataFrame(stream, shrinkMinStreamDataFrame, packetNum);
EXPECT_EQ(stream->minimumRetransmittableOffset, 110);
EXPECT_EQ(stream->currentWriteOffset, 110);
EXPECT_FALSE(stream->writeBuffer.empty());
EXPECT_EQ(stream->writeBuffer.chainLength(), 10);
EXPECT_TRUE(stream->retransmissionBuffer.empty());
EXPECT_EQ(stream->conn.flowControlState.sumCurStreamBufferLen, 10);
// case 2. where we skip beyond what we have in writeBuffer
stream->minimumRetransmittableOffset = 100;
stream->currentWriteOffset = 100;
stream->writeBuffer.move();
stream->conn.flowControlState.sumCurStreamBufferLen = 0;
onRecvMinStreamDataFrame(stream, shrinkMinStreamDataFrame, packetNum);
EXPECT_EQ(stream->minimumRetransmittableOffset, 110);
EXPECT_EQ(stream->currentWriteOffset, 110);
EXPECT_EQ(stream->conn.flowControlState.sumCurStreamBufferLen, 0);
}
TEST_F(QPRFunctionsTest, RecvMinStreamDataFrameOnUnidirectionalStream) {
auto stream = conn.streamManager->createNextUnidirectionalStream().value();
stream->sendState = StreamSendState::Closed_E;
stream->recvState = StreamRecvState::Closed_E;
PacketNum packetNum(10);
MinStreamDataFrame frame(
stream->id, stream->flowControlState.peerAdvertisedMaxOffset + 100, 100);
EXPECT_THROW(
onRecvMinStreamDataFrame(stream, frame, packetNum),
QuicTransportException);
}
TEST_F(QPRFunctionsTest, AdvanceCurrentReceiveOffset) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
// case1. nothing happend
stream->currentReadOffset = 10;
stream->currentReceiveOffset = 10;
auto result = advanceCurrentReceiveOffset(stream, 1);
EXPECT_EQ(stream->currentReceiveOffset, 10);
EXPECT_FALSE(result.has_value());
// case2. MinStreamDataFrame is put on the wire
stream->currentReadOffset = 10;
stream->currentReceiveOffset = 10;
result = advanceCurrentReceiveOffset(stream, 100);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
{
MinStreamDataFrame* minStreamDataFrame =
stream->conn.pendingEvents.frames[0].asMinStreamDataFrame();
if (minStreamDataFrame) {
EXPECT_EQ(minStreamDataFrame->minimumStreamOffset, 100);
}
}
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 100);
// case3. update existing pending event
stream->currentReadOffset = 100;
stream->currentReceiveOffset = 100;
stream->conn.pendingEvents.frames.clear();
stream->conn.pendingEvents.frames.emplace_back(
MinStreamDataFrame(stream->id, 100, 120));
result = advanceCurrentReceiveOffset(stream, 150);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
{
MinStreamDataFrame* minStreamDataFrame =
stream->conn.pendingEvents.frames[0].asMinStreamDataFrame();
if (minStreamDataFrame) {
EXPECT_EQ(minStreamDataFrame->minimumStreamOffset, 150);
}
}
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 150);
// case4. where offset was adjusted
stream->currentReadOffset = 100;
stream->currentReceiveOffset = 100;
stream->finalReadOffset = folly::make_optional((uint64_t)120);
result = advanceCurrentReceiveOffset(stream, 150);
EXPECT_EQ(stream->conn.pendingEvents.frames.size(), 1);
{
MinStreamDataFrame* minStreamDataFrame =
stream->conn.pendingEvents.frames[0].asMinStreamDataFrame();
if (minStreamDataFrame) {
EXPECT_EQ(minStreamDataFrame->minimumStreamOffset, 120);
}
}
EXPECT_TRUE(result.has_value());
EXPECT_EQ(*result, 120);
}
} // namespace test
} // namespace quic