1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-09 20:42:44 +03:00
Files
mvfst/quic/state/test/QuicStreamFunctionsTest.cpp
Alan Frindell 90e5e1b3f1 Split stream state machine into send and receive state machines
Summary: This is step 1 for removing reset on reset, since the send side may need to transition to waiting for a reset ack while the read side is an any state.

Reviewed By: lnicco

Differential Revision: D15075849

fbshipit-source-id: 1e094942a8a1ca9a01d4161cd6309b4136a9cfbf
2019-05-06 14:05:31 -07:00

1916 lines
73 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/state/QuicStreamFunctions.h>
#include <quic/client/state/ClientStateMachine.h>
#include <quic/common/test/TestUtils.h>
#include <quic/server/state/ServerStateMachine.h>
using namespace folly;
using namespace testing;
namespace quic {
namespace test {
constexpr uint8_t kStreamIncrement = 0x04;
using PeekIterator = std::deque<StreamBuffer>::const_iterator;
class QuicStreamFunctionsTest : public Test {
public:
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);
}
QuicClientConnectionState conn;
};
class QuicServerStreamFunctionsTest : public Test {
public:
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);
}
QuicServerConnectionState conn;
};
TEST_F(QuicStreamFunctionsTest, TestCreateBidirectionalStream) {
const auto stream =
conn.streamManager->createNextBidirectionalStream().value();
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(stream->id, 0x00);
}
TEST_F(QuicStreamFunctionsTest, TestCreateUnidirectionalStream) {
const auto stream =
conn.streamManager->createNextUnidirectionalStream().value();
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(stream->id, 0x02);
}
TEST_F(QuicStreamFunctionsTest, TestCreateBoth) {
for (int i = 0; i < 50; i++) {
auto stream = conn.streamManager->createNextUnidirectionalStream().value();
ASSERT_EQ(conn.streamManager->streamCount(), i + 1);
ASSERT_EQ(stream->id, 0x02 + i * kStreamIncrement);
}
for (int i = 0; i < 50; i++) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
ASSERT_EQ(conn.streamManager->streamCount(), i + 51);
ASSERT_EQ(stream->id, 0x00 + i * kStreamIncrement);
}
}
TEST_F(QuicStreamFunctionsTest, TestWriteStream) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just met you");
auto buf2 = IOBuf::copyBuffer("and this is crazy");
writeDataToQuicStream(*stream, buf1->clone(), false);
writeDataToQuicStream(*stream, buf2->clone(), false);
IOBufEqualTo eq;
buf1->prependChain(std::move(buf2));
EXPECT_TRUE(eq(stream->writeBuffer.move(), buf1));
}
TEST_F(QuicStreamFunctionsTest, TestReadDataWrittenInOrder) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
auto buf1 = IOBuf::copyBuffer("I just met you ");
buf1->prependChain(IOBuf::copyBuffer("and this is crazy. "));
auto buf2 = IOBuf::copyBuffer("Here's my number ");
buf2->prependChain(IOBuf::copyBuffer("so call me maybe"));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(
*stream,
StreamBuffer(buf2->clone(), buf1->computeChainDataLength(), true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
auto readData1 = readDataFromQuicStream(*stream, 10);
EXPECT_EQ("I just met", readData1.first->moveToFbString().toStdString());
EXPECT_FALSE(readData1.second);
auto readData2 = readDataFromQuicStream(*stream, 30);
EXPECT_EQ(
" you and this is crazy. Here's",
readData2.first->moveToFbString().toStdString());
EXPECT_FALSE(readData2.second);
auto readData3 = readDataFromQuicStream(*stream, 21);
EXPECT_EQ(
" my number so call me", readData3.first->moveToFbString().toStdString());
EXPECT_FALSE(readData3.second);
auto readData4 = readDataFromQuicStream(*stream, 20);
EXPECT_EQ(" maybe", readData4.first->moveToFbString().toStdString());
EXPECT_TRUE(readData4.second);
}
TEST_F(QuicStreamFunctionsTest, TestPeekAndConsumeContiguousData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
auto buf1 = IOBuf::copyBuffer("I just met you ");
buf1->prependChain(IOBuf::copyBuffer("and this is crazy. "));
auto buf2 = IOBuf::copyBuffer("Here's my number ");
buf2->prependChain(IOBuf::copyBuffer("so call me maybe"));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(
*stream,
StreamBuffer(buf2->clone(), buf1->computeChainDataLength(), true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
bool peekCbCalled = false;
auto peekCallback = [&](StreamId /* unused */,
const folly::Range<PeekIterator>& range) {
peekCbCalled = true;
EXPECT_EQ(range.size(), 1);
for (const auto& streamBuf : range) {
auto bufClone = streamBuf.data.front()->clone();
EXPECT_EQ(
"I just met you and this is crazy. Here's my number so call me maybe",
bufClone->moveToFbString().toStdString());
}
};
peekDataFromQuicStream(*stream, peekCallback);
EXPECT_TRUE(peekCbCalled);
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 81));
peekCbCalled = false;
auto peekCallback2 = [&](StreamId /* unused */,
const folly::Range<PeekIterator>& range) {
peekCbCalled = true;
EXPECT_EQ(range.size(), 0);
};
peekDataFromQuicStream(*stream, peekCallback2);
EXPECT_TRUE(peekCbCalled);
}
TEST_F(QuicStreamFunctionsTest, TestPeekAndConsumeNonContiguousData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
auto buf1 = IOBuf::copyBuffer("I just met you ");
buf1->prependChain(IOBuf::copyBuffer("and this is crazy. "));
auto buf2 = IOBuf::copyBuffer("'s my number ");
buf2->prependChain(IOBuf::copyBuffer("so call me maybe"));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(
*stream,
StreamBuffer(buf2->clone(), buf1->computeChainDataLength() + 4, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
bool cbCalled = false;
peekDataFromQuicStream(
*stream,
[&](StreamId /* unused */, const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 2);
auto bufClone = range[0].data.front()->clone();
EXPECT_EQ(
"I just met you and this is crazy. ",
bufClone->moveToFbString().toStdString());
bufClone = range[1].data.front()->clone();
EXPECT_EQ(
"'s my number so call me maybe",
bufClone->moveToFbString().toStdString());
});
EXPECT_TRUE(cbCalled);
// Consume left side.
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 81));
cbCalled = false;
auto peekCallback2 = [&](StreamId /* unused */,
const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 1);
auto bufClone = range[0].data.front()->clone();
EXPECT_EQ(
"'s my number so call me maybe",
bufClone->moveToFbString().toStdString());
};
peekDataFromQuicStream(*stream, peekCallback2);
EXPECT_TRUE(cbCalled);
// Try consuming again.
// Nothing has changed since we're missing data in the middle.
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 81));
cbCalled = false;
peekDataFromQuicStream(*stream, peekCallback2);
EXPECT_TRUE(cbCalled);
// Add missing middle bytes.
auto buf3 = IOBuf::copyBuffer("Here");
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 0));
appendDataToReadBuffer(
*stream, StreamBuffer(buf3->clone(), buf1->computeChainDataLength()));
cbCalled = false;
peekDataFromQuicStream(
*stream,
[&](StreamId /* unused */, const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 1);
auto bufClone = range[0].data.front()->clone();
EXPECT_EQ(
"Here's my number so call me maybe",
bufClone->moveToFbString().toStdString());
});
EXPECT_TRUE(cbCalled);
// Consume the rest of the buffer.
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 81));
cbCalled = false;
peekDataFromQuicStream(
*stream,
[&](StreamId /* unused */, const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 0);
});
EXPECT_TRUE(cbCalled);
}
TEST_F(QuicStreamFunctionsTest, TestPeekAndConsumeEmptyData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
bool cbCalled = false;
auto peekCallback = [&](StreamId /* unused */,
const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 0);
};
peekDataFromQuicStream(*stream, peekCallback);
EXPECT_TRUE(cbCalled);
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 81));
cbCalled = false;
peekDataFromQuicStream(*stream, peekCallback);
EXPECT_TRUE(cbCalled);
}
TEST_F(QuicStreamFunctionsTest, TestPeekAndConsumeEmptyDataEof) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
bool cbCalled = false;
auto peekCallback = [&](StreamId /* unused */,
const folly::Range<PeekIterator>& range) {
cbCalled = true;
EXPECT_EQ(range.size(), 0);
};
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 0, true));
peekDataFromQuicStream(*stream, peekCallback);
EXPECT_TRUE(cbCalled);
EXPECT_NO_THROW(consumeDataFromQuicStream(*stream, 42));
cbCalled = false;
peekDataFromQuicStream(*stream, peekCallback);
EXPECT_TRUE(cbCalled);
}
TEST_F(QuicStreamFunctionsTest, TestReadDataFromMultipleBufs) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just met you ");
buf1->prependChain(IOBuf::copyBuffer("and this is crazy. "));
auto buf2 = IOBuf::copyBuffer("Here's my number ");
buf2->prependChain(IOBuf::copyBuffer("so call me maybe"));
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(
*stream,
StreamBuffer(buf2->clone(), buf1->computeChainDataLength(), true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
"I just met you and this is crazy. Here's my number so call me maybe",
readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.first);
auto readData2 = readDataFromQuicStream(*stream, 30);
EXPECT_EQ(nullptr, readData2.first);
}
TEST_F(QuicStreamFunctionsTest, TestReadDataOutOfOrder) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer(" you ");
buf1->prependChain(IOBuf::copyBuffer("and this is crazy. "));
auto buf2 = IOBuf::copyBuffer("Here's my number ");
buf2->prependChain(IOBuf::copyBuffer("so call me maybe"));
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 10));
appendDataToReadBuffer(
*stream,
StreamBuffer(buf2->clone(), buf1->computeChainDataLength() + 10, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(nullptr, readData1.first);
appendDataToReadBuffer(
*stream, StreamBuffer(IOBuf::copyBuffer("I just met"), 0));
auto readData2 = readDataFromQuicStream(*stream, 19);
EXPECT_EQ(
"I just met you and ", readData2.first->moveToFbString().toStdString());
EXPECT_FALSE(readData2.second);
auto readData3 = readDataFromQuicStream(*stream, 31);
EXPECT_EQ(
"this is crazy. Here's my number",
readData3.first->moveToFbString().toStdString());
EXPECT_FALSE(readData3.second);
auto readData4 = readDataFromQuicStream(*stream);
EXPECT_EQ(
" so call me maybe", readData4.first->moveToFbString().toStdString());
EXPECT_TRUE(readData4.second);
}
TEST_F(QuicStreamFunctionsTest, TestReadOverlappingData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just met you ");
buf1->prependChain(IOBuf::copyBuffer("and this"));
auto buf2 = IOBuf::copyBuffer("met you and this is crazy. ");
buf2->prependChain(IOBuf::copyBuffer("Here's my number"));
auto buf3 = IOBuf::copyBuffer("Here's my number, ");
buf3->prependChain(IOBuf::copyBuffer("so call me maybe."));
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 34, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
auto readData1 = readDataFromQuicStream(*stream, 100);
auto str = readData1.first->moveToFbString().toStdString();
EXPECT_EQ(
"I just met you and this is crazy. Here's my number, so call me maybe.",
str);
EXPECT_TRUE(readData1.second);
}
TEST_F(QuicStreamFunctionsTest, TestCompleteOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto buf2 = IOBuf::copyBuffer("this is");
auto buf3 = IOBuf::copyBuffer("I just met you and this is crazy");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 7));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 19));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 0, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
"I just met you and this is crazy",
readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestTotalOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("met you ", readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestSubsetOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto buf2 = IOBuf::copyBuffer("you");
auto buf3 = IOBuf::copyBuffer("you ");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 4));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 4, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("met you ", readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestLeftOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto buf2 = IOBuf::copyBuffer("I just met");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 7, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just met you ", readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestLeftNoOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto buf2 = IOBuf::copyBuffer("I just");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 7, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 2);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just", readData1.first->moveToFbString().toStdString());
EXPECT_FALSE(readData1.second);
EXPECT_EQ(stream->readBuffer.size(), 1);
}
TEST_F(QuicStreamFunctionsTest, TestRightOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer(" met you ");
auto buf3 = IOBuf::copyBuffer("you and this is crazy");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 6));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 11, true));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
"I just met you and this is crazy",
readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
} // namespace test
TEST_F(QuicStreamFunctionsTest, TestRightNoOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer("met you ");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 2);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just", readData1.first->moveToFbString().toStdString());
EXPECT_FALSE(readData1.second);
EXPECT_EQ(stream->readBuffer.size(), 1);
}
TEST_F(QuicStreamFunctionsTest, TestRightLeftOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just met");
auto buf2 = IOBuf::copyBuffer("met you");
auto buf3 = IOBuf::copyBuffer("you and this is crazy");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 11, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
"I just met you and this is crazy",
readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestInsertVariations) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("met you ");
auto buf2 = IOBuf::copyBuffer("this is crazy.");
auto buf3 = IOBuf::copyBuffer(" Here's my number");
auto buf4 = IOBuf::copyBuffer("number so call");
auto buf5 = IOBuf::copyBuffer(
"just met you and this is crazy. Here's my number so call");
auto buf6 = IOBuf::copyBuffer(" me maybe");
auto buf7 = IOBuf::copyBuffer("this is crazy. Here's my number so call");
auto buf8 = IOBuf::copyBuffer("I just met you");
buf8->prependChain(IOBuf::copyBuffer(" and this"));
auto buf9 = IOBuf::copyBuffer("Here's my number so call me maybe");
auto buf10 = IOBuf::copyBuffer("I ");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 7));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 19));
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 33));
appendDataToReadBuffer(*stream, StreamBuffer(buf4->clone(), 44));
appendDataToReadBuffer(*stream, StreamBuffer(buf5->clone(), 2));
appendDataToReadBuffer(*stream, StreamBuffer(buf6->clone(), 58));
appendDataToReadBuffer(*stream, StreamBuffer(buf7->clone(), 19));
appendDataToReadBuffer(*stream, StreamBuffer(buf8->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf9->clone(), 34, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf10->clone(), 0));
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
auto readData1 = readDataFromQuicStream(*stream, 100);
auto str = readData1.first->moveToFbString().toStdString();
EXPECT_EQ(
"I just met you and this is crazy. Here's my number so call me maybe",
str);
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestAppendAlreadyReadData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just met you and this is crazy");
auto buf2 = IOBuf::copyBuffer("I just met you and this is");
auto buf3 = IOBuf::copyBuffer("I just met you and this is crazy");
auto buf4 =
IOBuf::copyBuffer("I just met you and this is crazy. Here's my number");
auto buf5 = IOBuf::copyBuffer(
"I just met you and this is crazy. Here's my number so call me");
auto buf6 = IOBuf::copyBuffer(
"I just met you and this is crazy. Here's my number so call me maybe");
auto streamLastMaxOffset = stream->maxOffsetObserved;
auto connLastMaxOffset = conn.flowControlState.sumMaxObservedOffset;
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
"I just met you and this is crazy",
readData1.first->moveToFbString().toStdString());
EXPECT_FALSE(readData1.second);
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
auto readData2 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(readData2.first, nullptr);
EXPECT_FALSE(readData2.second);
EXPECT_TRUE(stream->readBuffer.empty());
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 0));
auto readData3 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(readData3.first, nullptr);
EXPECT_FALSE(readData3.second);
EXPECT_TRUE(stream->readBuffer.empty());
appendDataToReadBuffer(*stream, StreamBuffer(buf4->clone(), 0));
auto readData4 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
". Here's my number", readData4.first->moveToFbString().toStdString());
EXPECT_FALSE(readData4.second);
EXPECT_TRUE(stream->readBuffer.empty());
appendDataToReadBuffer(*stream, StreamBuffer(buf5->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf6->clone(), 0));
auto readData5 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(
" so call me maybe", readData5.first->moveToFbString().toStdString());
EXPECT_FALSE(readData5.second);
EXPECT_TRUE(stream->readBuffer.empty());
appendDataToReadBuffer(*stream, StreamBuffer(buf6->clone(), 0, true));
auto readData6 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ(readData6.first, nullptr);
EXPECT_TRUE(readData6.second);
EXPECT_EQ(
stream->maxOffsetObserved - streamLastMaxOffset,
conn.flowControlState.sumMaxObservedOffset - connLastMaxOffset);
}
TEST_F(QuicStreamFunctionsTest, TestEmptyEOF) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer("");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7, true));
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just", readData1.first->moveToFbString().toStdString());
EXPECT_FALSE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
auto buf3 = IOBuf::copyBuffer("m");
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 6));
auto readData2 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("m", readData2.first->moveToFbString().toStdString());
EXPECT_TRUE(readData2.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestEmptyEOFOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer("");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 6, true));
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just", readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestOverlapEOF) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2, true));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
EXPECT_EQ(stream->readBuffer.size(), 1);
auto readData1 = readDataFromQuicStream(*stream, 100);
EXPECT_EQ("I just", readData1.first->moveToFbString().toStdString());
EXPECT_TRUE(readData1.second);
EXPECT_TRUE(stream->readBuffer.empty());
}
TEST_F(QuicStreamFunctionsTest, TestEmptyBuffer) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
}
TEST_F(QuicStreamFunctionsTest, TestInvalidEOFWithAlreadyReadData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer(" met you");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 6));
auto readData1 = readDataFromQuicStream(*stream, 6);
EXPECT_EQ(stream->readBuffer.size(), 1);
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidEOFWithSubsetData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I just");
auto buf2 = IOBuf::copyBuffer("I");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidEOFWithNoOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidExistingEOFWithCompleteOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I just met");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2, true));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidExistingEOFNotLastBuffer) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just met");
auto buf2 = IOBuf::copyBuffer("you");
auto buf3 = IOBuf::copyBuffer("I just");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 11));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 0, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidExistingEOFRightOverlap) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just met");
auto buf2 = IOBuf::copyBuffer("met you");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2, true));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, TestInvalidExistingEOFRightOverlapNotLast) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just met");
auto buf2 = IOBuf::copyBuffer("this is");
auto buf3 = IOBuf::copyBuffer("met you");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 16));
EXPECT_THROW(
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 7, true)),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, SetInvalidMaxStreams) {
conn.streamManager->setMaxLocalBidirectionalStreams(100, true);
conn.streamManager->setMaxLocalUnidirectionalStreams(100, true);
conn.streamManager->setMaxLocalBidirectionalStreams(0);
conn.streamManager->setMaxLocalUnidirectionalStreams(0);
EXPECT_EQ(conn.streamManager->openableLocalBidirectionalStreams(), 100);
EXPECT_EQ(conn.streamManager->openableLocalUnidirectionalStreams(), 100);
EXPECT_THROW(
conn.streamManager->setMaxLocalBidirectionalStreams(kMaxMaxStreams + 1),
QuicTransportException);
EXPECT_THROW(
conn.streamManager->setMaxLocalUnidirectionalStreams(kMaxMaxStreams + 1),
QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateClientCryptoStream) {
EXPECT_NE(conn.cryptoState, nullptr);
}
TEST_F(QuicServerStreamFunctionsTest, GetOrCreateClientOutOfOrderStream) {
StreamId outOfOrderStream = 100;
StreamId existingStream = 88;
StreamId closedStream = 84;
conn.streamManager->getStream(outOfOrderStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
// peer stream starts from 0x00
EXPECT_EQ(
conn.streamManager->openPeerStreams().size(),
((outOfOrderStream) / kStreamIncrement) + 1);
conn.streamManager->getStream(existingStream);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
EXPECT_EQ(
conn.streamManager->openPeerStreams().size(),
((outOfOrderStream) / kStreamIncrement) + 1);
conn.streamManager->openPeerStreams().erase(std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
closedStream));
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
}
TEST_F(QuicServerStreamFunctionsTest, GetOrCreateExistingClientStream) {
StreamId outOfOrderStream1 = 100;
StreamId outOfOrderStream2 = 48;
auto stream = conn.streamManager->getStream(outOfOrderStream1);
auto stream2 = conn.streamManager->getStream(outOfOrderStream1);
EXPECT_EQ(stream, stream2);
conn.streamManager->getStream(outOfOrderStream2);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateExistingServerStream) {
StreamId outOfOrderStream1 = 101;
StreamId outOfOrderStream2 = 49;
auto stream = conn.streamManager->getStream(outOfOrderStream1);
auto stream2 = conn.streamManager->getStream(outOfOrderStream1);
EXPECT_EQ(stream, stream2);
conn.streamManager->getStream(outOfOrderStream2);
}
TEST_F(QuicServerStreamFunctionsTest, GetOrCreateClosedClientStream) {
StreamId outOfOrderStream1 = 100;
StreamId closedStream = 48;
conn.streamManager->getStream(outOfOrderStream1);
conn.streamManager->openPeerStreams().erase(std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
closedStream));
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
}
TEST_F(
QuicServerStreamFunctionsTest,
GetOrCreateClientStreamAfterClosingLastStream) {
StreamId outOfOrderStream1 = 96;
StreamId outOfOrderStream2 = 100;
conn.streamManager->getStream(outOfOrderStream1);
conn.streamManager->openPeerStreams().erase(std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
outOfOrderStream1));
conn.streamManager->getStream(outOfOrderStream2);
EXPECT_EQ(
conn.streamManager->openPeerStreams().size(),
(outOfOrderStream2) / kStreamIncrement);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateServerStreamAfterClosingLastStream) {
StreamId outOfOrderStream1 = 97;
StreamId outOfOrderStream2 = 101;
conn.streamManager->getStream(outOfOrderStream1);
conn.streamManager->openPeerStreams().erase(std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
outOfOrderStream1));
conn.streamManager->getStream(outOfOrderStream2);
EXPECT_EQ(
conn.streamManager->openPeerStreams().size(),
(outOfOrderStream2 + 1) / kStreamIncrement);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateClosedServerStream) {
StreamId outOfOrderStream1 = 97;
StreamId closedStream = 49;
conn.streamManager->getStream(outOfOrderStream1);
conn.streamManager->openPeerStreams().erase(std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
closedStream));
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
}
TEST_F(QuicServerStreamFunctionsTest, GetOrCreateServerStreamOnServer) {
StreamId serverStream = 101;
EXPECT_THROW(
conn.streamManager->getStream(serverStream), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateClientStreamOnClient) {
StreamId clientStream = 100;
EXPECT_THROW(
conn.streamManager->getStream(clientStream), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, GetOrCreateNonClientOrServer) {
StreamId streamZero = 0;
EXPECT_THROW(
conn.streamManager->getStream(streamZero), QuicTransportException);
}
TEST_F(QuicServerStreamFunctionsTest, CreateQuicStreamServerOutOfOrder) {
StreamId outOfOrderStream1 = 101;
StreamId outOfOrderStream2 = 49;
conn.streamManager->createStream(outOfOrderStream1).value();
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 26);
conn.streamManager->createStream(outOfOrderStream2).value();
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 26);
}
TEST_F(QuicStreamFunctionsTest, CreateQuicStreamClientOutOfOrder) {
StreamId outOfOrderStream1 = 96;
StreamId outOfOrderStream2 = 48;
conn.streamManager->createStream(outOfOrderStream1);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 25);
conn.streamManager->createStream(outOfOrderStream2).value();
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 25);
}
TEST_F(QuicServerStreamFunctionsTest, CreateClosedServerStream) {
StreamId outOfOrderStream1 = 101;
StreamId outOfOrderStream2 = 49;
conn.streamManager->createStream(outOfOrderStream1);
conn.streamManager->openLocalStreams().erase(std::find(
conn.streamManager->openLocalStreams().begin(),
conn.streamManager->openLocalStreams().end(),
outOfOrderStream2));
EXPECT_FALSE(conn.streamManager->createStream(outOfOrderStream2));
}
TEST_F(QuicStreamFunctionsTest, CreateClosedClientStream) {
StreamId outOfOrderStream1 = 96;
StreamId outOfOrderStream2 = 48;
conn.streamManager->createStream(outOfOrderStream1).value();
conn.streamManager->openLocalStreams().erase(std::find(
conn.streamManager->openLocalStreams().begin(),
conn.streamManager->openLocalStreams().end(),
outOfOrderStream2));
EXPECT_FALSE(conn.streamManager->createStream(outOfOrderStream2));
}
TEST_F(QuicStreamFunctionsTest, CreateInvalidServerStreamOnClient) {
StreamId serverStream = 0x09;
EXPECT_THROW(
conn.streamManager->createStream(serverStream), QuicTransportException);
}
TEST_F(QuicServerStreamFunctionsTest, CreateInvalidClientStreamOnServer) {
StreamId clientStream = 0x04;
EXPECT_THROW(
conn.streamManager->createStream(clientStream), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, CreateAlreadyExistingStream) {
StreamId stream = 0x08;
conn.streamManager->createStream(stream).value();
EXPECT_THROW(
conn.streamManager->createStream(stream), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, IsClientStream) {
EXPECT_TRUE(isClientStream(0));
EXPECT_TRUE(isClientStream(0x04));
EXPECT_TRUE(isClientStream(104));
EXPECT_TRUE(isClientStream(0x08));
EXPECT_FALSE(isClientStream(0x01));
EXPECT_FALSE(isClientStream(0x07));
EXPECT_FALSE(isClientStream(0x11));
}
TEST_F(QuicStreamFunctionsTest, IsServerStream) {
EXPECT_TRUE(isServerStream(0x05));
EXPECT_TRUE(isServerStream(105));
EXPECT_TRUE(isServerStream(0x25));
EXPECT_FALSE(isServerStream(0x02));
EXPECT_FALSE(isServerStream(0x04));
EXPECT_FALSE(isServerStream(0));
}
TEST_F(QuicStreamFunctionsTest, IsUnidirectionalStream) {
EXPECT_TRUE(isUnidirectionalStream(0x02));
EXPECT_TRUE(isUnidirectionalStream(0x03));
EXPECT_TRUE(isUnidirectionalStream(0xff));
EXPECT_FALSE(isUnidirectionalStream(0x01));
EXPECT_FALSE(isUnidirectionalStream(0xf0));
EXPECT_FALSE(isUnidirectionalStream(0xf1));
}
TEST_F(QuicStreamFunctionsTest, IsBidirectionalStream) {
EXPECT_TRUE(isBidirectionalStream(0x01));
EXPECT_TRUE(isBidirectionalStream(0xf0));
EXPECT_TRUE(isBidirectionalStream(0xf1));
EXPECT_FALSE(isBidirectionalStream(0x02));
EXPECT_FALSE(isBidirectionalStream(0x03));
EXPECT_FALSE(isBidirectionalStream(0xff));
}
TEST_F(QuicStreamFunctionsTest, IsSendingStream) {
QuicClientConnectionState clientState;
QuicServerConnectionState serverState;
QuicNodeType nodeType;
StreamId id;
QuicStreamState biClientStream(0, clientState);
nodeType = biClientStream.conn.nodeType;
id = biClientStream.id;
EXPECT_FALSE(isSendingStream(nodeType, id));
QuicStreamState biServerStream(0, serverState);
nodeType = biServerStream.conn.nodeType;
id = biServerStream.id;
EXPECT_FALSE(isSendingStream(nodeType, id));
QuicStreamState uniClientSendingStream(0x2, clientState);
nodeType = uniClientSendingStream.conn.nodeType;
id = uniClientSendingStream.id;
EXPECT_TRUE(isSendingStream(nodeType, id));
QuicStreamState uniServerSendingStream(0x3, serverState);
nodeType = uniServerSendingStream.conn.nodeType;
id = uniServerSendingStream.id;
EXPECT_TRUE(isSendingStream(nodeType, id));
}
TEST_F(QuicStreamFunctionsTest, IsReceivingStream) {
QuicClientConnectionState clientState;
QuicServerConnectionState serverState;
QuicNodeType nodeType;
StreamId id;
QuicStreamState biClientStream(0, clientState);
nodeType = biClientStream.conn.nodeType;
id = biClientStream.id;
EXPECT_FALSE(isReceivingStream(nodeType, id));
QuicStreamState biServerStream(0, serverState);
nodeType = biServerStream.conn.nodeType;
id = biServerStream.id;
EXPECT_FALSE(isReceivingStream(nodeType, id));
QuicStreamState uniClientReceivingStream(0x3, clientState);
nodeType = uniClientReceivingStream.conn.nodeType;
id = uniClientReceivingStream.id;
EXPECT_TRUE(isReceivingStream(nodeType, id));
QuicStreamState uniServerReceivingStream(0x2, serverState);
nodeType = uniServerReceivingStream.conn.nodeType;
id = uniServerReceivingStream.id;
EXPECT_TRUE(isReceivingStream(nodeType, id));
}
TEST_F(QuicStreamFunctionsTest, HasReadableDataNoData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
EXPECT_FALSE(stream->hasReadableData());
}
TEST_F(QuicStreamFunctionsTest, HasReadableDataNoDataInBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
EXPECT_FALSE(stream->hasReadableData());
}
TEST_F(QuicStreamFunctionsTest, HasReadableDataEofInBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 1, true));
EXPECT_FALSE(stream->hasReadableData());
appendDataToReadBuffer(*stream, StreamBuffer(IOBuf::copyBuffer("1"), 0));
EXPECT_TRUE(stream->hasReadableData());
auto read1 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read1.second);
EXPECT_FALSE(stream->hasReadableData());
auto read2 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read2.second);
}
TEST_F(QuicStreamFunctionsTest, HasReadableDataEofInEmptyBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 0, true));
EXPECT_TRUE(stream->hasReadableData());
auto read1 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read1.second);
EXPECT_FALSE(stream->hasReadableData());
auto read2 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read2.second);
}
TEST_F(QuicStreamFunctionsTest, HasReadableDataOnlyEof) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 0, true));
EXPECT_TRUE(stream->hasReadableData());
}
TEST_F(QuicStreamFunctionsTest, HasReadableData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I ");
auto buf2 = IOBuf::copyBuffer("met");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7));
EXPECT_TRUE(stream->hasReadableData());
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->hasReadableData());
auto buf3 = IOBuf::copyBuffer("just ");
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 2));
EXPECT_TRUE(stream->hasReadableData());
readDataFromQuicStream(*stream, 5);
EXPECT_TRUE(stream->hasReadableData());
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->hasReadableData());
}
TEST_F(QuicStreamFunctionsTest, HasPeekableDataGappedData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
EXPECT_TRUE(stream->hasPeekableData());
}
TEST_F(QuicStreamFunctionsTest, HasPeekableDataNoDataInBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
EXPECT_FALSE(stream->hasPeekableData());
}
TEST_F(QuicStreamFunctionsTest, HasPeekableDataEofInBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 1, true));
EXPECT_FALSE(stream->hasPeekableData());
appendDataToReadBuffer(*stream, StreamBuffer(IOBuf::copyBuffer("1"), 0));
EXPECT_TRUE(stream->hasPeekableData());
auto read1 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read1.second);
EXPECT_FALSE(stream->hasPeekableData());
auto read2 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read2.second);
}
TEST_F(QuicStreamFunctionsTest, HasPeekableDataEofInEmptyBuf) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 0, true));
EXPECT_FALSE(stream->hasPeekableData());
auto read1 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read1.second);
EXPECT_FALSE(stream->hasPeekableData());
auto read2 = readDataFromQuicStream(*stream, 1);
EXPECT_TRUE(read2.second);
}
TEST_F(QuicStreamFunctionsTest, HasPeekableDataOnlyEof) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
appendDataToReadBuffer(*stream, StreamBuffer(nullptr, 0, true));
EXPECT_FALSE(stream->hasPeekableData());
}
TEST_F(QuicStreamFunctionsTest, HasPeekableData) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("I ");
auto buf2 = IOBuf::copyBuffer("met");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 7));
EXPECT_TRUE(stream->hasPeekableData());
readDataFromQuicStream(*stream);
EXPECT_TRUE(stream->hasPeekableData());
auto buf3 = IOBuf::copyBuffer("just ");
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 2));
EXPECT_TRUE(stream->hasPeekableData());
readDataFromQuicStream(*stream, 5);
EXPECT_TRUE(stream->hasPeekableData());
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->hasPeekableData());
}
TEST_F(QuicStreamFunctionsTest, UpdatesLastHolbTime) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
// Should not be HOL blocked before data has arrived
EXPECT_FALSE(stream->lastHolbTime);
readDataFromQuicStream(*stream);
// Should be HOL blocked
EXPECT_TRUE(stream->lastHolbTime);
}
TEST_F(QuicStreamFunctionsTest, HolbTimingUpdateReadingListIdempotentWrtHolb) {
// test that calling uRL consequtevily (without new data or readsd)
// does not affect the HOLB state
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
auto buf3 = IOBuf::copyBuffer("you");
auto buf4 = IOBuf::copyBuffer(" met ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
// Should not be HOL blocked until the readable list has been updated
EXPECT_FALSE(stream->lastHolbTime);
// uRL 0.0 - expected state transition:
// !HOLB => HOLB in progress
conn.streamManager->updateReadableStreams(*stream);
// HOLB state must be detected after the first readable list update
auto lastHolbTimeMark = stream->lastHolbTime;
EXPECT_TRUE(lastHolbTimeMark);
// No total holb time should be recorded
EXPECT_EQ(std::chrono::microseconds::zero(), stream->totalHolbTime);
EXPECT_EQ(1, stream->holbCount);
// uRL 0.1 - expected state transition: none
conn.streamManager->updateReadableStreams(*stream);
EXPECT_EQ(lastHolbTimeMark, stream->lastHolbTime);
EXPECT_EQ(std::chrono::microseconds::zero(), stream->totalHolbTime);
EXPECT_EQ(1, stream->holbCount);
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
// uRL 1.0 - expected state transition:
// HOLB in progress -> !HOLB && holbCount == 1
conn.streamManager->updateReadableStreams(*stream);
auto totalHolbTimeMark = stream->totalHolbTime;
// HOLB state must be cleared by buf2, and total time should be available
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
// uRL 1.1 - expected state transition: none
conn.streamManager->updateReadableStreams(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(totalHolbTimeMark, stream->totalHolbTime);
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 11));
// uRL 2.0 - expected state transition:
// !HOLB && holbCount == 1
// => !HOLB && totalTime == totalTimeMark
// NOTE: the stream is not HOLB since the reading cursor is not
// at the hole
conn.streamManager->updateReadableStreams(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(totalHolbTimeMark, stream->totalHolbTime);
EXPECT_EQ(1, stream->holbCount);
// uRL 2.1 - expected state transition: none
conn.streamManager->updateReadableStreams(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(totalHolbTimeMark, stream->totalHolbTime);
// uRL 3.0 - expected state transition:
// !HOLB && totalTime == totalTimeMark
// => HOLB && holbCount == 2
// && totalHolbTime == totalTimeMark
readDataFromQuicStream(*stream);
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
EXPECT_EQ(totalHolbTimeMark, stream->totalHolbTime);
auto lastHolbTimeMark2 = stream->lastHolbTime;
// uRL 3.1 - expected state transition: none
conn.streamManager->updateReadableStreams(*stream);
EXPECT_EQ(lastHolbTimeMark2, stream->lastHolbTime);
EXPECT_EQ(totalHolbTimeMark, stream->totalHolbTime);
EXPECT_EQ(2, stream->holbCount);
// uRL 4.0 - add the rest of the data to the stream.
// HOLB && holbCount == 2
// && totalTime == totalTimeMark
// => !HOLB && holbCount == 2
appendDataToReadBuffer(*stream, StreamBuffer(buf4->clone(), 6));
conn.streamManager->updateReadableStreams(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
// uRL 4.1 - read the entire stream - expected state transition:
// !HOLB && holbCount == 2
// => !HOLB && holbCount == 2
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
// uRL 4.1 - expected state change: none
conn.streamManager->updateReadableStreams(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
}
TEST_F(QuicStreamFunctionsTest, HolbTimingFirstBufferHOLBlocked) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
// Should not be HOL blocked until the readable list has been updated
EXPECT_FALSE(stream->lastHolbTime);
conn.streamManager->updateReadableStreams(*stream);
// HOLB state must be detected after the first readable list update
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
EXPECT_EQ(std::chrono::microseconds::zero(), stream->totalHolbTime);
auto lastHolbTimeMark = stream->lastHolbTime;
readDataFromQuicStream(*stream);
// Read data should fail since there is no data available at
// the reading cursor
EXPECT_EQ(lastHolbTimeMark, stream->lastHolbTime);
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
conn.streamManager->updateReadableStreams(*stream);
// HOLB state must be cleared by buf2, and total time should be available
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
}
TEST_F(QuicStreamFunctionsTest, HolbTimingReadingEntireStream) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
conn.streamManager->updateReadableStreams(*stream);
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
conn.streamManager->updateReadableStreams(*stream);
// HOLB state must be cleared by buf2, and total time should be available
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
// Consume the entire stream. This should not change the holb status
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
}
TEST_F(QuicStreamFunctionsTest, HolbTimingLockstepScenario) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
auto buf3 = IOBuf::copyBuffer("met you ");
auto buf4 = IOBuf::copyBuffer("and this is crazy");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
// Should not be HOL blocked before data has arrived
EXPECT_FALSE(stream->lastHolbTime);
readDataFromQuicStream(*stream);
// Should be HOL blocked now
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
// At this point, the stream has not been unblocked even once,
// hence the total holb time is expected to be zero
EXPECT_EQ(std::chrono::microseconds::zero(), stream->totalHolbTime);
// Data has arrived
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
appendDataToReadBuffer(*stream, StreamBuffer(buf4->clone(), 15));
// Update readable list has not been called yet, hence
// the total holb time has not been set yet
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
// Update readable list
conn.streamManager->updateReadableStreams(*stream);
// The new data should have unblocked the HOLB
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
auto snapshotHolbTime = stream->totalHolbTime;
// Consume all available data from the stream
readDataFromQuicStream(*stream);
// Should be HOL blocked at missing buf3.
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
// The total HOLB time shouldn't have changed since the last update
EXPECT_EQ(snapshotHolbTime, stream->totalHolbTime);
appendDataToReadBuffer(*stream, StreamBuffer(buf3->clone(), 6));
conn.streamManager->updateReadableStreams(*stream);
// Should be not HOLB
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(2, stream->holbCount);
}
TEST_F(QuicStreamFunctionsTest, HolbTimingReadDataCallsUpdateRL) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto buf1 = IOBuf::copyBuffer("just");
auto buf2 = IOBuf::copyBuffer("I ");
appendDataToReadBuffer(*stream, StreamBuffer(buf1->clone(), 2));
readDataFromQuicStream(*stream);
// Should be HOL blocked
EXPECT_TRUE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
appendDataToReadBuffer(*stream, StreamBuffer(buf2->clone(), 0));
readDataFromQuicStream(*stream);
EXPECT_FALSE(stream->lastHolbTime);
EXPECT_EQ(1, stream->holbCount);
}
TEST_F(QuicStreamFunctionsTest, RemovedClosedState) {
auto stream = conn.streamManager->createNextBidirectionalStream().value();
auto streamId = stream->id;
conn.streamManager->readableStreams().emplace(streamId);
conn.streamManager->peekableStreams().emplace(streamId);
conn.streamManager->addWritable(streamId);
conn.streamManager->queueBlocked(streamId, 0);
conn.streamManager->addDeliverable(streamId);
conn.streamManager->addLoss(streamId);
conn.streamManager->queueWindowUpdate(streamId);
conn.streamManager->addStopSending(
streamId, GenericApplicationErrorCode::UNKNOWN);
stream->send.state = StreamSendStates::Closed{};
stream->recv.state = StreamReceiveStates::Closed{};
conn.streamManager->removeClosedStream(streamId);
EXPECT_FALSE(conn.streamManager->streamExists(streamId));
EXPECT_TRUE(conn.streamManager->readableStreams().empty());
EXPECT_TRUE(conn.streamManager->peekableStreams().empty());
EXPECT_FALSE(conn.streamManager->writableContains(streamId));
EXPECT_FALSE(conn.streamManager->hasBlocked());
EXPECT_FALSE(conn.streamManager->deliverableContains(streamId));
EXPECT_FALSE(conn.streamManager->hasLoss());
EXPECT_FALSE(conn.streamManager->pendingWindowUpdate(streamId));
EXPECT_TRUE(conn.streamManager->stopSendingStreams().empty());
}
TEST_F(QuicServerStreamFunctionsTest, ServerGetClientQuicStream) {
StreamId clientStream = 0x10;
std::deque<StreamId> newStreams = {0x0, 0x4, 0x8, 0xc, 0x10};
EXPECT_EQ(conn.streamManager->getStream(clientStream)->id, clientStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 5);
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
StreamId clientStream2 = 0x4;
EXPECT_EQ(conn.streamManager->getStream(clientStream2)->id, clientStream2);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 5);
EXPECT_EQ(conn.streamManager->newPeerStreams().size(), 5);
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
StreamId clientStream3 = 0x6;
newStreams = {0x0, 0x2, 0x4, 0x6, 0x8, 0xc, 0x10};
EXPECT_EQ(conn.streamManager->getStream(clientStream3)->id, clientStream3);
EXPECT_EQ(conn.streamManager->streamCount(), 3);
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 7);
std::sort(
conn.streamManager->newPeerStreams().begin(),
conn.streamManager->newPeerStreams().end());
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
}
TEST_F(QuicServerStreamFunctionsTest, ServerGetServerQuicStream) {
StreamId serverStream = 0x09;
conn.streamManager->createStream(serverStream).value();
EXPECT_EQ(conn.streamManager->getStream(serverStream)->id, serverStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 3);
StreamId serverStream2 = 0x05;
EXPECT_EQ(conn.streamManager->getStream(serverStream2)->id, serverStream2);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 3);
StreamId serverStream3 = 0x0D;
EXPECT_THROW(
conn.streamManager->getStream(serverStream3), QuicTransportException);
}
TEST_F(QuicServerStreamFunctionsTest, ServerGetBothDirections) {
StreamId serverBiStream = 0x09;
conn.streamManager->createStream(serverBiStream).value();
EXPECT_EQ(conn.streamManager->getStream(serverBiStream)->id, serverBiStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 3);
StreamId serverUniStream = 0x0B;
conn.streamManager->createStream(serverUniStream).value();
EXPECT_EQ(
conn.streamManager->getStream(serverUniStream)->id, serverUniStream);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 6);
}
TEST_F(QuicServerStreamFunctionsTest, ServerGetCloseBothDirections) {
StreamId serverBiStream = 0x09;
conn.streamManager->createStream(serverBiStream).value();
EXPECT_EQ(conn.streamManager->getStream(serverBiStream)->id, serverBiStream);
StreamId serverUniStream = 0x0B;
auto stream = conn.streamManager->createStream(serverUniStream).value();
stream->send.state = StreamSendStates::Closed{};
conn.streamManager->removeClosedStream(serverUniStream);
EXPECT_TRUE(
conn.streamManager->getStream(serverUniStream - kStreamIncrement));
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_FALSE(conn.streamManager->streamExists(serverUniStream));
EXPECT_TRUE(conn.streamManager->streamExists(serverBiStream));
EXPECT_TRUE(
conn.streamManager->streamExists(serverUniStream - kStreamIncrement));
EXPECT_TRUE(
conn.streamManager->streamExists(serverBiStream - kStreamIncrement));
EXPECT_FALSE(
conn.streamManager->streamExists(serverUniStream + kStreamIncrement));
EXPECT_FALSE(
conn.streamManager->streamExists(serverBiStream + kStreamIncrement));
}
TEST_F(QuicServerStreamFunctionsTest, ServerGetServerUnidirectionalQuicStream) {
StreamId serverStream = 0x0F;
conn.streamManager->createStream(serverStream).value();
EXPECT_EQ(conn.streamManager->getStream(serverStream)->id, serverStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 4);
StreamId serverStream2 = 0x0B;
EXPECT_EQ(conn.streamManager->getStream(serverStream2)->id, serverStream2);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 4);
StreamId serverStream3 = 0x1F;
EXPECT_THROW(
conn.streamManager->getStream(serverStream3), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, ClientGetServerQuicStream) {
StreamId serverStream = 0x09;
EXPECT_EQ(conn.streamManager->getStream(serverStream)->id, serverStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 3);
StreamId serverStream2 = 0x05;
EXPECT_EQ(conn.streamManager->getStream(serverStream2)->id, serverStream2);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 3);
}
TEST_F(QuicStreamFunctionsTest, ClientGetClientQuicStream) {
StreamId clientStream = 0x0C;
conn.streamManager->createStream(clientStream).value();
EXPECT_EQ(conn.streamManager->getStream(clientStream)->id, clientStream);
EXPECT_EQ(conn.streamManager->streamCount(), 1);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 4);
StreamId clientStream2 = 0x08;
EXPECT_EQ(conn.streamManager->getStream(clientStream2)->id, clientStream2);
EXPECT_EQ(conn.streamManager->streamCount(), 2);
EXPECT_EQ(conn.streamManager->openLocalStreams().size(), 4);
StreamId clientStream3 = 0x10;
EXPECT_THROW(
conn.streamManager->getStream(clientStream3), QuicTransportException);
}
TEST_F(QuicStreamFunctionsTest, StreamExists) {
StreamId localStream = 12;
StreamId peerStream = 13;
StreamId localAutoOpened = 8;
StreamId peerAutoOpened = 5;
StreamId peerAutoOpened2 = 9;
StreamId notOpenedLocal = 16;
StreamId notOpenedPeer = 17;
conn.streamManager->createStream(localStream).value();
EXPECT_TRUE(conn.streamManager->streamExists(localStream));
EXPECT_TRUE(conn.streamManager->streamExists(localAutoOpened));
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedLocal));
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedPeer));
EXPECT_FALSE(conn.streamManager->streamExists(peerStream));
EXPECT_FALSE(conn.streamManager->streamExists(peerAutoOpened));
conn.streamManager->getStream(peerStream)->send.state =
StreamSendStates::Closed{};
conn.streamManager->getStream(peerStream)->recv.state =
StreamReceiveStates::Closed{};
EXPECT_TRUE(conn.streamManager->streamExists(localStream));
EXPECT_TRUE(conn.streamManager->streamExists(localAutoOpened));
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedLocal));
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedPeer));
EXPECT_TRUE(conn.streamManager->streamExists(peerStream));
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened));
auto it = std::find(
conn.streamManager->openPeerStreams().begin(),
conn.streamManager->openPeerStreams().end(),
peerAutoOpened);
conn.streamManager->openPeerStreams().erase(it);
conn.streamManager->removeClosedStream(peerStream);
EXPECT_FALSE(conn.streamManager->streamExists(peerAutoOpened));
EXPECT_FALSE(conn.streamManager->streamExists(peerStream));
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened2));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAcked) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.finalWriteOffset = 1;
stream.currentWriteOffset = 2;
EXPECT_TRUE(allBytesTillFinAcked(stream));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAckedFinOnly) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.finalWriteOffset = 0;
stream.currentWriteOffset = 1;
EXPECT_TRUE(allBytesTillFinAcked(stream));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAckedNewStream) {
StreamId id = 3;
QuicStreamState stream(id, conn);
EXPECT_FALSE(allBytesTillFinAcked(stream));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAckedStillLost) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.finalWriteOffset = 20;
stream.currentWriteOffset = 21;
stream.lossBuffer.emplace_back(IOBuf::create(10), 10, false);
EXPECT_FALSE(allBytesTillFinAcked(stream));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAckedStillRetransmitting) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.finalWriteOffset = 12;
stream.retransmissionBuffer.emplace_back(IOBuf::create(10), 10, false);
EXPECT_FALSE(allBytesTillFinAcked(stream));
}
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAckedStillWriting) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.finalWriteOffset = 10;
auto buf = IOBuf::create(10);
buf->append(10);
stream.writeBuffer.append(std::move(buf));
EXPECT_FALSE(allBytesTillFinAcked(stream));
}
TEST_F(QuicServerStreamFunctionsTest, TestAppendPendingStreamResetAllData) {
StreamId id = 3;
QuicStreamState stream(id, conn);
auto data = IOBuf::copyBuffer("this is data");
auto len = data->computeChainDataLength();
writeDataToQuicStream(stream, std::move(data), true);
// Simulate all bytes and EOF written on network.
stream.currentWriteOffset = len + 1;
stream.retransmissionBuffer.clear();
appendPendingStreamReset(conn, stream, GenericApplicationErrorCode::UNKNOWN);
auto rst = conn.pendingEvents.resets.at(id);
EXPECT_EQ(rst.errorCode, GenericApplicationErrorCode::UNKNOWN);
EXPECT_EQ(rst.offset, len);
}
TEST_F(
QuicServerStreamFunctionsTest,
TestAppendPendingStreamResetAllDataWithoutFin) {
StreamId id = 3;
QuicStreamState stream(id, conn);
auto data = IOBuf::copyBuffer("this is data");
auto len = data->computeChainDataLength();
writeDataToQuicStream(stream, std::move(data), true);
// Simulate all bytes except EOF written on network.
stream.currentWriteOffset = len;
stream.retransmissionBuffer.clear();
appendPendingStreamReset(conn, stream, GenericApplicationErrorCode::UNKNOWN);
auto rst = conn.pendingEvents.resets.at(id);
EXPECT_EQ(rst.errorCode, GenericApplicationErrorCode::UNKNOWN);
EXPECT_EQ(rst.offset, len);
}
TEST_F(QuicStreamFunctionsTest, LargestWriteOffsetSeenFIN) {
QuicStreamState stream(3, conn);
stream.finalWriteOffset = 100;
EXPECT_EQ(100, getLargestWriteOffsetSeen(stream));
}
TEST_F(QuicStreamFunctionsTest, LargestWriteOffsetSeenNoFIN) {
QuicStreamState stream(3, conn);
stream.currentWriteOffset = 100;
stream.writeBuffer.append(buildRandomInputData(20));
EXPECT_EQ(120, getLargestWriteOffsetSeen(stream));
}
TEST_F(QuicStreamFunctionsTest, StreamNextOffsetToDeliver) {
QuicStreamState stream(3, conn);
stream.currentWriteOffset = 100;
EXPECT_EQ(100, getStreamNextOffsetToDeliver(stream));
}
TEST_F(QuicStreamFunctionsTest, StreamNextOffsetToDeliverRetxBuffer) {
QuicStreamState stream(3, conn);
stream.currentWriteOffset = 100;
stream.retransmissionBuffer.emplace_back(buildRandomInputData(10), 50);
EXPECT_EQ(50, getStreamNextOffsetToDeliver(stream));
}
TEST_F(QuicStreamFunctionsTest, StreamNextOffsetToDeliverRetxAndLossBuffer) {
QuicStreamState stream(3, conn);
stream.currentWriteOffset = 100;
stream.lossBuffer.emplace_back(buildRandomInputData(10), 30);
stream.retransmissionBuffer.emplace_back(buildRandomInputData(10), 50);
EXPECT_EQ(30, getStreamNextOffsetToDeliver(stream));
}
TEST_F(QuicStreamFunctionsTest, LossBufferEmpty) {
StreamId id = 4;
QuicStreamState stream(id, conn);
conn.streamManager->addLoss(id);
conn.streamManager->updateLossStreams(stream);
EXPECT_FALSE(conn.streamManager->hasLoss());
}
TEST_F(QuicStreamFunctionsTest, LossBufferEmptyNoChange) {
StreamId id = 4;
QuicStreamState stream(id, conn);
conn.streamManager->updateLossStreams(stream);
EXPECT_FALSE(conn.streamManager->hasLoss());
}
TEST_F(QuicStreamFunctionsTest, LossBufferHasData) {
StreamId id = 4;
QuicStreamState stream(id, conn);
stream.lossBuffer.emplace_back(IOBuf::create(10), 10, false);
conn.streamManager->updateLossStreams(stream);
EXPECT_TRUE(conn.streamManager->hasLoss());
}
TEST_F(QuicStreamFunctionsTest, LossBufferStillHasData) {
StreamId id = 4;
QuicStreamState stream(id, conn);
conn.streamManager->addLoss(id);
stream.lossBuffer.emplace_back(IOBuf::create(10), 10, false);
conn.streamManager->updateLossStreams(stream);
EXPECT_TRUE(conn.streamManager->hasLoss());
}
TEST_F(QuicStreamFunctionsTest, WritableList) {
StreamId id = 3;
QuicStreamState stream(id, conn);
stream.currentWriteOffset = 100;
stream.flowControlState.peerAdvertisedMaxOffset = 200;
conn.streamManager->updateWritableStreams(stream);
EXPECT_FALSE(stream.conn.streamManager->writableContains(id));
auto buf = IOBuf::create(100);
buf->append(100);
writeDataToQuicStream(stream, std::move(buf), false);
conn.streamManager->updateWritableStreams(stream);
EXPECT_TRUE(stream.conn.streamManager->writableContains(id));
// Flow control
stream.flowControlState.peerAdvertisedMaxOffset = stream.currentWriteOffset;
conn.streamManager->updateWritableStreams(stream);
EXPECT_FALSE(stream.conn.streamManager->writableContains(id));
// Fin
writeDataToQuicStream(stream, nullptr, true);
stream.writeBuffer.clear();
stream.currentWriteOffset += 100;
stream.flowControlState.peerAdvertisedMaxOffset = stream.currentWriteOffset;
conn.streamManager->updateWritableStreams(stream);
EXPECT_TRUE(stream.conn.streamManager->writableContains(id));
// After Fin
stream.currentWriteOffset++;
conn.streamManager->updateWritableStreams(stream);
EXPECT_FALSE(stream.conn.streamManager->writableContains(id));
}
TEST_F(QuicStreamFunctionsTest, AckCryptoStream) {
auto chlo = IOBuf::copyBuffer("CHLO");
conn.cryptoState->handshakeStream.retransmissionBuffer.emplace_back(
StreamBuffer(chlo->clone(), 0));
processCryptoStreamAck(conn.cryptoState->handshakeStream, 0, chlo->length());
EXPECT_EQ(conn.cryptoState->handshakeStream.retransmissionBuffer.size(), 0);
}
TEST_F(QuicStreamFunctionsTest, AckCryptoStreamOffsetLengthMismatch) {
auto chlo = IOBuf::copyBuffer("CHLO");
auto& cryptoStream = conn.cryptoState->handshakeStream;
cryptoStream.retransmissionBuffer.emplace_back(
StreamBuffer(chlo->clone(), 0));
processCryptoStreamAck(cryptoStream, 1, chlo->length());
EXPECT_EQ(cryptoStream.retransmissionBuffer.size(), 1);
processCryptoStreamAck(cryptoStream, 0, chlo->length() - 2);
EXPECT_EQ(cryptoStream.retransmissionBuffer.size(), 1);
processCryptoStreamAck(cryptoStream, 20, chlo->length());
EXPECT_EQ(cryptoStream.retransmissionBuffer.size(), 1);
}
} // namespace test
} // namespace quic