| // Copyright (c) 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" |
| |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" |
| #include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" |
| #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" |
| #include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" |
| |
| namespace quic { |
| namespace simulator { |
| namespace { |
| |
| using ::testing::ElementsAre; |
| |
| const QuicBandwidth kDefaultBandwidth = |
| QuicBandwidth::FromKBitsPerSecond(10 * 1000); |
| const QuicTime::Delta kDefaultPropagationDelay = |
| QuicTime::Delta::FromMilliseconds(20); |
| const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay; |
| const QuicByteCount kDefaultPacketSize = 1200; |
| const QuicPacketCount kDefaultQueueLength = 10; |
| |
| class FakeDelegate : public QuartcPacketTransport::Delegate { |
| public: |
| explicit FakeDelegate(QuartcPacketTransport* transport) |
| : transport_(transport) { |
| transport_->SetDelegate(this); |
| } |
| |
| ~FakeDelegate() { transport_->SetDelegate(nullptr); } |
| |
| void OnTransportCanWrite() override { |
| while (!packets_to_send_.empty()) { |
| const QuicString& packet = packets_to_send_.front(); |
| if (transport_->Write(packet.data(), packet.size(), |
| QuartcPacketTransport::PacketInfo()) < |
| static_cast<int>(packet.size())) { |
| ++write_blocked_count_; |
| return; |
| } |
| packets_to_send_.pop(); |
| } |
| } |
| |
| void OnTransportReceived(const char* data, size_t data_len) override { |
| packets_received_.emplace_back(data, data_len); |
| } |
| |
| void AddPacketToSend(const QuicString& packet) { |
| packets_to_send_.push(packet); |
| } |
| |
| size_t packets_to_send() { return packets_to_send_.size(); } |
| const std::vector<QuicString>& packets_received() { |
| return packets_received_; |
| } |
| int write_blocked_count() { return write_blocked_count_; } |
| |
| private: |
| QuartcPacketTransport* const transport_ = nullptr; |
| std::queue<QuicString> packets_to_send_; |
| std::vector<QuicString> packets_received_; |
| int write_blocked_count_ = 0; |
| }; |
| |
| class SimulatedPacketTransportTest : public QuicTest { |
| protected: |
| SimulatedPacketTransportTest() |
| : switch_(&simulator_, "Switch", /*port_count=*/8, 2 * kDefaultBdp), |
| client_(&simulator_, |
| "sender", |
| "receiver", |
| kDefaultQueueLength * kDefaultPacketSize), |
| server_(&simulator_, |
| "receiver", |
| "sender", |
| kDefaultQueueLength * kDefaultPacketSize), |
| client_link_(&client_, |
| switch_.port(1), |
| kDefaultBandwidth, |
| kDefaultPropagationDelay), |
| server_link_(&server_, |
| switch_.port(2), |
| kDefaultBandwidth, |
| kDefaultPropagationDelay), |
| client_delegate_(&client_), |
| server_delegate_(&server_) {} |
| |
| Simulator simulator_; |
| Switch switch_; |
| |
| SimulatedQuartcPacketTransport client_; |
| SimulatedQuartcPacketTransport server_; |
| |
| SymmetricLink client_link_; |
| SymmetricLink server_link_; |
| |
| FakeDelegate client_delegate_; |
| FakeDelegate server_delegate_; |
| }; |
| |
| TEST_F(SimulatedPacketTransportTest, OneWayTransmission) { |
| QuicString packet_1(kDefaultPacketSize, 'a'); |
| QuicString packet_2(kDefaultPacketSize, 'b'); |
| client_delegate_.AddPacketToSend(packet_1); |
| client_delegate_.AddPacketToSend(packet_2); |
| |
| simulator_.RunUntil( |
| [this] { return client_delegate_.packets_to_send() == 0; }); |
| simulator_.RunFor(3 * kDefaultPropagationDelay); |
| |
| EXPECT_THAT(server_delegate_.packets_received(), |
| ElementsAre(packet_1, packet_2)); |
| EXPECT_THAT(client_delegate_.packets_received(), ElementsAre()); |
| } |
| |
| TEST_F(SimulatedPacketTransportTest, TwoWayTransmission) { |
| QuicString packet_1(kDefaultPacketSize, 'a'); |
| QuicString packet_2(kDefaultPacketSize, 'b'); |
| QuicString packet_3(kDefaultPacketSize, 'c'); |
| QuicString packet_4(kDefaultPacketSize, 'd'); |
| |
| client_delegate_.AddPacketToSend(packet_1); |
| client_delegate_.AddPacketToSend(packet_2); |
| server_delegate_.AddPacketToSend(packet_3); |
| server_delegate_.AddPacketToSend(packet_4); |
| |
| simulator_.RunUntil( |
| [this] { return client_delegate_.packets_to_send() == 0; }); |
| simulator_.RunUntil( |
| [this] { return server_delegate_.packets_to_send() == 0; }); |
| simulator_.RunFor(3 * kDefaultPropagationDelay); |
| |
| EXPECT_THAT(server_delegate_.packets_received(), |
| ElementsAre(packet_1, packet_2)); |
| EXPECT_THAT(client_delegate_.packets_received(), |
| ElementsAre(packet_3, packet_4)); |
| } |
| |
| TEST_F(SimulatedPacketTransportTest, TestWriteBlocked) { |
| // Add 10 packets beyond what fits in the egress queue. |
| std::vector<QuicString> packets; |
| for (unsigned int i = 0; i < kDefaultQueueLength + 10; ++i) { |
| packets.push_back(QuicString(kDefaultPacketSize, 'a' + i)); |
| client_delegate_.AddPacketToSend(packets.back()); |
| } |
| |
| simulator_.RunUntil( |
| [this] { return client_delegate_.packets_to_send() == 0; }); |
| simulator_.RunFor(3 * kDefaultPropagationDelay); |
| |
| // Each of the 10 packets in excess of the sender's egress queue length will |
| // block the first time |client_delegate_| tries to write them. |
| EXPECT_EQ(client_delegate_.write_blocked_count(), 10); |
| EXPECT_EQ(server_delegate_.packets_received(), packets); |
| } |
| |
| } // namespace |
| } // namespace simulator |
| } // namespace quic |