chromium/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_test.cc

// Copyright (c) 2012 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 "quiche/quic/test_tools/simulator/quic_endpoint.h"

#include <memory>
#include <utility>

#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/quic/test_tools/quic_connection_peer.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
#include "quiche/quic/test_tools/simulator/simulator.h"
#include "quiche/quic/test_tools/simulator/switch.h"

using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;

namespace quic {
namespace simulator {

const QuicBandwidth kDefaultBandwidth =;
const QuicTime::Delta kDefaultPropagationDelay =;
const QuicByteCount kDefaultBdp =;

// A simple test harness where all hosts are connected to a switch with
// identical links.
class QuicEndpointTest : public quic::test::QuicTest {};

// Test transmission from one host to another.
TEST_F() {
  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
                          Perspective::IS_CLIENT, test::TestConnectionId(42));
  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
                          Perspective::IS_SERVER, test::TestConnectionId(42));
  auto link_a = Link(&endpoint_a, switch_.port(1));
  auto link_b = Link(&endpoint_b, switch_.port(2));

  // First transmit a small, packet-size chunk of data.
  endpoint_a.AddBytesToTransfer(600);
  QuicTime end_time =
      simulator_.GetClock()->Now() + QuicTime::Delta::FromMilliseconds(1000);
  simulator_.RunUntil(
      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });

  EXPECT_EQ();
  ASSERT_EQ();
  EXPECT_FALSE();
  EXPECT_FALSE();

  // After a small chunk succeeds, try to transfer 2 MiB.
  endpoint_a.AddBytesToTransfer(2 * 1024 * 1024);
  end_time = simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
  simulator_.RunUntil(
      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });

  const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024;
  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_FALSE();
  EXPECT_FALSE();
}

// Test the situation in which the writer becomes write-blocked.
TEST_F() {
  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
                          Perspective::IS_CLIENT, test::TestConnectionId(42));
  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
                          Perspective::IS_SERVER, test::TestConnectionId(42));
  auto link_a = Link(&endpoint_a, switch_.port(1));
  auto link_b = Link(&endpoint_b, switch_.port(2));

  // Will be owned by the sent packet manager.
  auto* sender = new NiceMock<test::MockSendAlgorithm>();
  EXPECT_CALL().WillRepeatedly(Return(true));
  EXPECT_CALL()
      .WillRepeatedly(Return(10 * kDefaultBandwidth));
  EXPECT_CALL()
      .WillRepeatedly(Return(10 * kDefaultBandwidth));
  EXPECT_CALL()
      .WillRepeatedly(Return(kMaxOutgoingPacketSize *
                             GetQuicFlag()));
  test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(), sender);

  // First transmit a small, packet-size chunk of data.
  QuicByteCount bytes_to_transfer = 3 * 1024 * 1024;
  endpoint_a.AddBytesToTransfer(bytes_to_transfer);
  QuicTime end_time =
      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30);
  simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() {
    return endpoint_b.bytes_received() == bytes_to_transfer ||
           simulator_.GetClock()->Now() >= end_time;
  });

  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_GT();
  EXPECT_FALSE();
  EXPECT_FALSE();
}

// Test transmission of 1 MiB of data between two hosts simultaneously in both
// directions.
TEST_F() {
  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
                          Perspective::IS_CLIENT, test::TestConnectionId(42));
  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
                          Perspective::IS_SERVER, test::TestConnectionId(42));
  auto link_a = Link(&endpoint_a, switch_.port(1));
  auto link_b = Link(&endpoint_b, switch_.port(2));

  endpoint_a.RecordTrace();
  endpoint_b.RecordTrace();

  endpoint_a.AddBytesToTransfer(1024 * 1024);
  endpoint_b.AddBytesToTransfer(1024 * 1024);
  QuicTime end_time =
      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
  simulator_.RunUntil(
      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });

  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_EQ();
  EXPECT_FALSE();
  EXPECT_FALSE();
}

// Simulate three hosts trying to send data to a fourth one simultaneously.
TEST_F() {
  auto endpoint_a = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT,
      test::TestConnectionId(42));
  auto endpoint_b = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint B", "Endpoint D (B)", Perspective::IS_CLIENT,
      test::TestConnectionId(43));
  auto endpoint_c = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint C", "Endpoint D (C)", Perspective::IS_CLIENT,
      test::TestConnectionId(44));
  auto endpoint_d_a = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint D (A)", "Endpoint A", Perspective::IS_SERVER,
      test::TestConnectionId(42));
  auto endpoint_d_b = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint D (B)", "Endpoint B", Perspective::IS_SERVER,
      test::TestConnectionId(43));
  auto endpoint_d_c = std::make_unique<QuicEndpoint>(
      &simulator_, "Endpoint D (C)", "Endpoint C", Perspective::IS_SERVER,
      test::TestConnectionId(44));
  QuicEndpointMultiplexer endpoint_d(
      "Endpoint D",
      {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()});

  // Create links with slightly different RTTs in order to avoid pathological
  // side-effects of packets entering the queue at the exactly same time.
  auto link_a = CustomLink(endpoint_a.get(), switch_.port(1), 0);
  auto link_b = CustomLink(endpoint_b.get(), switch_.port(2), 1);
  auto link_c = CustomLink(endpoint_c.get(), switch_.port(3), 2);
  auto link_d = Link(&endpoint_d, switch_.port(4));

  endpoint_a->AddBytesToTransfer(2 * 1024 * 1024);
  endpoint_b->AddBytesToTransfer(2 * 1024 * 1024);
  endpoint_c->AddBytesToTransfer(2 * 1024 * 1024);
  QuicTime end_time =
      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(12);
  simulator_.RunUntil(
      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });

  for (QuicEndpoint* endpoint :
       {endpoint_a.get(), endpoint_b.get(), endpoint_c.get()}) {
    EXPECT_EQ();
    EXPECT_GE();
  }
  for (QuicEndpoint* endpoint :
       {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}) {
    EXPECT_EQ();
    EXPECT_FALSE();
  }
}

}  // namespace simulator
}  // namespace quic