/* * 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. * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace quic { namespace test { class MockClock { public: using time_point = quic::Clock::time_point; using duration = quic::Clock::duration; static std::function mockNow; static time_point now() { return mockNow(); } }; constexpr QuicVersion MVFST1 = static_cast(0xfaceb00d); constexpr QuicVersion MVFST2 = static_cast(0xfaceb00e); constexpr folly::StringPiece kTestHost = "host"; const RegularQuicWritePacket& writeQuicPacket( QuicServerConnectionState& conn, ConnectionId srcConnId, ConnectionId dstConnId, folly::test::MockAsyncUDPSocket& sock, QuicStreamState& stream, const folly::IOBuf& data, bool eof = false); RegularQuicPacketBuilder::Packet createAckPacket( QuicConnectionStateBase& dstConn, PacketNum pn, AckBlocks& acks, PacketNumberSpace pnSpace, const Aead* aead = nullptr); PacketNum rstStreamAndSendPacket( QuicServerConnectionState& conn, folly::AsyncUDPSocket& sock, QuicStreamState& stream, ApplicationErrorCode errorCode); // TODO: this is a really horrible API. User can easily pass srcConnId and // destConnId wrong and won't realize it. All the other createXXXPacket are also // horrible. RegularQuicPacketBuilder::Packet createStreamPacket( ConnectionId srcConnId, ConnectionId dstConnId, PacketNum packetNum, StreamId streamId, folly::IOBuf& data, uint8_t cipherOverhead, PacketNum largestAcked, folly::Optional> longHeaderOverride = folly::none, bool eof = true, folly::Optional shortHeaderOverride = folly::none, uint64_t offset = 0, uint64_t packetSizeLimit = kDefaultUDPSendPacketLen); RegularQuicPacketBuilder::Packet createInitialCryptoPacket( ConnectionId srcConnId, ConnectionId dstConnId, PacketNum packetNum, QuicVersion version, folly::IOBuf& data, const Aead& aead, PacketNum largestAcked, uint64_t offset = 0); RegularQuicPacketBuilder::Packet createCryptoPacket( ConnectionId srcConnId, ConnectionId dstConnId, PacketNum packetNum, QuicVersion version, ProtectionType protectionType, folly::IOBuf& data, const Aead& aead, PacketNum largestAcked, uint64_t offset = 0, uint64_t packetSizeLimit = kDefaultUDPSendPacketLen); Buf packetToBuf(const RegularQuicPacketBuilder::Packet& packet); Buf packetToBufCleartext( const RegularQuicPacketBuilder::Packet& packet, const Aead& cleartextCipher, const PacketNumberCipher& headerCipher, PacketNum packetNum); template bool isState(const S& s) { return folly::variant_match( s.state, [](const T&) { return true; }, [](const auto&) { return false; }); } std::shared_ptr createServerCtx(); void setupCtxWithTestCert(fizz::server::FizzServerContext& ctx); void setupZeroRttOnServerCtx( fizz::server::FizzServerContext& serverCtx, const QuicCachedPsk& cachedPsk); QuicCachedPsk setupZeroRttOnClientCtx( fizz::client::FizzClientContext& clientCtx, std::string hostname); std::unique_ptr createNoOpAead(); std::unique_ptr createNoOpHeaderCipher(); uint64_t computeExpectedDelay( std::chrono::microseconds ackDelay, uint8_t ackDelayExponent); std::unique_ptr createTestCertificateVerifier(); // match error functions bool matchError( std::pair> errorCode, LocalErrorCode error); bool matchError( std::pair> errorCode, TransportErrorCode error); bool matchError( std::pair> errorCode, ApplicationErrorCode error); bool matchError( std::pair errorCode, ApplicationErrorCode error); bool matchError( std::pair errorCode, TransportErrorCode error); ConnectionId getTestConnectionId(uint16_t hostId = 0); ProtectionType encryptionLevelToProtectionType( fizz::EncryptionLevel encryptionLevel); MATCHER_P(IsError, error, "") { return matchError(arg, error); } MATCHER_P(IsAppError, error, "") { return matchError(arg, error); } void updateAckState( QuicConnectionStateBase& conn, PacketNumberSpace pnSpace, PacketNum packetNum, bool pkHasRetransmittableData, bool pkHasCryptoData, TimePoint receivedTime); template OutstandingPacket* findOutstandingPacket( QuicConnectionStateBase& conn, Match match) { auto helper = [&](std::deque& packets) -> OutstandingPacket* { for (auto& packet : packets) { if (match(packet)) { return &packet; } } return nullptr; }; return helper(conn.outstandingPackets); } // Helper function to generate a buffer containing random data of given length std::unique_ptr buildRandomInputData(size_t length); void addAckStatesWithCurrentTimestamps( AckState& ackState, PacketNum start, PacketNum end); OutstandingPacket makeTestingWritePacket( PacketNum desiredPacketSeqNum, size_t desiredSize, uint64_t totalBytesSent, TimePoint sentTime = Clock::now()); // TODO: The way we setup packet sent, ack, loss in test cases can use some // major refactor. CongestionController::AckEvent makeAck( PacketNum seq, uint64_t ackedSize, TimePoint ackedTime, TimePoint sendTime); BufQueue bufToQueue(Buf buf); StatelessResetToken generateStatelessResetToken(); std::array getRandSecret(); RegularQuicWritePacket createNewPacket( PacketNum packetNum, PacketNumberSpace pnSpace); std::vector versionList( std::initializer_list types); RegularQuicWritePacket createRegularQuicWritePacket( StreamId streamId, uint64_t offset, uint64_t len, bool fin); VersionNegotiationPacket createVersionNegotiationPacket(); RegularQuicWritePacket createPacketWithAckFrames(); RegularQuicWritePacket createPacketWithPaddingFrames(); // Helper function which takes in a specific event type and fetches all the // instances of that type in QLogger std::vector getQLogEventIndices( QLogEventType type, const std::shared_ptr& q); template auto findFrameInPacketFunc() { return [&](auto& p) { return std::find_if( p.packet.frames.begin(), p.packet.frames.end(), [&](auto& f) { QuicSimpleFrame* simpleFrame = f.asQuicSimpleFrame(); if (!simpleFrame) { return false; } return simpleFrame->type() == Type; }) != p.packet.frames.end(); }; } CongestionController::AckEvent::AckPacket makeAckPacketFromOutstandingPacket( OutstandingPacket outstandingPacket); } // namespace test } // namespace quic