|  | // Copyright (c) 2017 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/test/quartc_data_source.h" | 
|  |  | 
|  | #include <vector> | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | class FakeDelegate : public QuartcDataSource::Delegate { | 
|  | public: | 
|  | void OnDataProduced(const char* data, size_t length) override; | 
|  |  | 
|  | const std::vector<ParsedQuartcDataFrame>& frames() { return frames_; } | 
|  |  | 
|  | private: | 
|  | std::vector<ParsedQuartcDataFrame> frames_; | 
|  | }; | 
|  |  | 
|  | void FakeDelegate::OnDataProduced(const char* data, size_t length) { | 
|  | ParsedQuartcDataFrame frame; | 
|  | QuicStringPiece message(data, length); | 
|  | if (ParsedQuartcDataFrame::Parse(message, &frame)) { | 
|  | frames_.push_back(frame); | 
|  | } else { | 
|  | QUIC_LOG(FATAL) << "Data source produced a frame it can't parse: " | 
|  | << message; | 
|  | } | 
|  | } | 
|  |  | 
|  | class QuartcDataSourceTest : public QuicTest { | 
|  | protected: | 
|  | QuartcDataSourceTest() : simulator_() {} | 
|  |  | 
|  | simulator::Simulator simulator_; | 
|  | FakeDelegate delegate_; | 
|  |  | 
|  | std::unique_ptr<QuartcDataSource> source_; | 
|  | }; | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesFrameEveryInterval) { | 
|  | QuartcDataSource::Config config; | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(20); | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval); | 
|  | EXPECT_EQ(delegate_.frames().size(), 1u); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval); | 
|  | EXPECT_EQ(delegate_.frames().size(), 2u); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  | EXPECT_EQ(delegate_.frames().size(), 22u); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, DoesNotProduceFramesUntilEnabled) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  | EXPECT_EQ(delegate_.frames().size(), 0u); | 
|  |  | 
|  | // The first frame is produced immediately (but asynchronously) upon enabling | 
|  | // the source. | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(QuicTime::Delta::FromMicroseconds(1)); | 
|  | EXPECT_EQ(delegate_.frames().size(), 1u); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, DisableAndEnable) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  |  | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  | EXPECT_EQ(delegate_.frames().size(), 20u); | 
|  |  | 
|  | // No new frames while the source is disabled. | 
|  | source_->SetEnabled(false); | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  | EXPECT_EQ(delegate_.frames().size(), 20u); | 
|  |  | 
|  | // The first frame is produced immediately (but asynchronously) upon enabling | 
|  | // the source. | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(QuicTime::Delta::FromMicroseconds(1)); | 
|  | ASSERT_EQ(delegate_.frames().size(), 21u); | 
|  |  | 
|  | // The first frame after a pause should be no larger than previous frames. | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), | 
|  | delegate_.frames()[20].payload.size()); | 
|  |  | 
|  | // The first frame after the pause should have a much later timestamp. | 
|  | // Note that the previous frame (19) happens at the *start* of the 20th | 
|  | // interval.  Frame 20 would normally happen one interval later, but we've | 
|  | // delayed it by an extra 20 intervals (for a total of 21 intervals later). | 
|  | EXPECT_EQ(delegate_.frames()[20].send_time - delegate_.frames()[19].send_time, | 
|  | 21 * config.frame_interval); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, EnablingTwiceDoesNotChangeSchedule) { | 
|  | QuartcDataSource::Config config; | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(20); | 
|  |  | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  |  | 
|  | // The first frame is produced immediately (but asynchronously) upon enabling | 
|  | // the source. | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(QuicTime::Delta::FromMicroseconds(1)); | 
|  | EXPECT_EQ(delegate_.frames().size(), 1u); | 
|  |  | 
|  | // Enabling the source again does not re-schedule the alarm. | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(QuicTime::Delta::FromMicroseconds(1)); | 
|  | EXPECT_EQ(delegate_.frames().size(), 1u); | 
|  |  | 
|  | // The second frame is sent at the expected interval after the first. | 
|  | ASSERT_TRUE( | 
|  | simulator_.RunUntil([this] { return delegate_.frames().size() == 2; })); | 
|  |  | 
|  | EXPECT_EQ(delegate_.frames()[1].send_time - delegate_.frames()[0].send_time, | 
|  | config.frame_interval); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesFramesWithConfiguredSourceId) { | 
|  | QuartcDataSource::Config config; | 
|  | config.id = 7; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].source_id, config.id); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesFramesAtAllocatedBandwidth) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | constexpr QuicByteCount bytes_per_frame = 1000; | 
|  | source_->AllocateBandwidth(QuicBandwidth::FromBytesAndTimeDelta( | 
|  | bytes_per_frame, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), | 
|  | bytes_per_frame - kDataFrameHeaderSize); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, bytes_per_frame); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesParseableHeaderWhenNotEnoughBandwidth) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | // Allocate less bandwidth than the source requires for its header. | 
|  | source_->AllocateBandwidth(QuicBandwidth::FromBytesAndTimeDelta( | 
|  | kDataFrameHeaderSize - 10, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), 0u); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, kDataFrameHeaderSize); | 
|  |  | 
|  | // Header fields are still present and parseable. | 
|  | EXPECT_EQ(delegate_.frames()[0].source_id, 0); | 
|  | EXPECT_EQ(delegate_.frames()[0].sequence_number, 0); | 
|  | EXPECT_EQ(delegate_.frames()[0].send_time, start_time); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesSequenceNumbers) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 20u); | 
|  | for (int i = 0; i < 20; ++i) { | 
|  | EXPECT_EQ(delegate_.frames()[i].sequence_number, i); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesSendTimes) { | 
|  | QuartcDataSource::Config config; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(1000, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | simulator_.RunFor(config.frame_interval * 20); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 20u); | 
|  | QuicTime first_send_time = delegate_.frames()[0].send_time; | 
|  | for (int i = 1; i < 20; ++i) { | 
|  | EXPECT_EQ(delegate_.frames()[i].send_time, | 
|  | first_send_time + i * config.frame_interval); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, AllocateClampsToMin) { | 
|  | QuartcDataSource::Config config; | 
|  | config.min_bandwidth = QuicBandwidth::FromBitsPerSecond(8000); | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(100); | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | // When allocating less than the minimum, there is nothing left over. | 
|  | EXPECT_EQ(source_->AllocateBandwidth(QuicBandwidth::FromBitsPerSecond(6000)), | 
|  | QuicBandwidth::Zero()); | 
|  |  | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | // The frames produced use min_bandwidth instead of the lower allocation. | 
|  | QuicByteCount bytes_per_frame = | 
|  | config.min_bandwidth.ToBytesPerPeriod(config.frame_interval); | 
|  | ASSERT_EQ(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), | 
|  | bytes_per_frame - kDataFrameHeaderSize); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, bytes_per_frame); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, AllocateClampsToMax) { | 
|  | QuartcDataSource::Config config; | 
|  | config.max_bandwidth = QuicBandwidth::FromBitsPerSecond(8000); | 
|  | config.frame_interval = QuicTime::Delta::FromMilliseconds(100); | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | // When allocating more than the maximum, the excess is returned. | 
|  | EXPECT_EQ(source_->AllocateBandwidth(QuicBandwidth::FromBitsPerSecond(10000)), | 
|  | QuicBandwidth::FromBitsPerSecond(2000)); | 
|  |  | 
|  | source_->SetEnabled(true); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | // The frames produced use max_bandwidth instead of the higher allocation. | 
|  | QuicByteCount bytes_per_frame = | 
|  | config.max_bandwidth.ToBytesPerPeriod(config.frame_interval); | 
|  | ASSERT_EQ(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), | 
|  | bytes_per_frame - kDataFrameHeaderSize); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, bytes_per_frame); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, MaxFrameSize) { | 
|  | constexpr QuicByteCount bytes_per_frame = 1000; | 
|  | QuartcDataSource::Config config; | 
|  | config.max_frame_size = bytes_per_frame; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | // Allocate enough bandwidth for more than one frame per interval. | 
|  | source_->AllocateBandwidth(QuicBandwidth::FromBytesAndTimeDelta( | 
|  | 3 * bytes_per_frame, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | // Since there's enough bandwidth for three frames per interval, that's what | 
|  | // the source should generate. | 
|  | EXPECT_EQ(delegate_.frames().size(), 3u); | 
|  | int i = 0; | 
|  | for (const auto& frame : delegate_.frames()) { | 
|  | // Each of the frames should start with a header that can be parsed. | 
|  | // Each gets the same timestamp, but a different sequence number. | 
|  | EXPECT_EQ(frame.source_id, config.id); | 
|  | EXPECT_EQ(frame.sequence_number, i++); | 
|  | EXPECT_EQ(frame.send_time, start_time); | 
|  |  | 
|  | // Each of the frames should have the configured maximum size. | 
|  | EXPECT_EQ(frame.payload.size(), bytes_per_frame - kDataFrameHeaderSize); | 
|  | EXPECT_EQ(frame.size, bytes_per_frame); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesParseableHeaderWhenMaxFrameSizeTooSmall) { | 
|  | QuartcDataSource::Config config; | 
|  | config.max_frame_size = kDataFrameHeaderSize - 1; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(200, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | ASSERT_GE(delegate_.frames().size(), 1u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), 0u); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, kDataFrameHeaderSize); | 
|  |  | 
|  | // Header fields are still present and parseable. | 
|  | EXPECT_EQ(delegate_.frames()[0].source_id, 0); | 
|  | EXPECT_EQ(delegate_.frames()[0].sequence_number, 0); | 
|  | EXPECT_EQ(delegate_.frames()[0].send_time, start_time); | 
|  | } | 
|  |  | 
|  | TEST_F(QuartcDataSourceTest, ProducesParseableHeaderWhenLeftoverSizeTooSmall) { | 
|  | QuartcDataSource::Config config; | 
|  | config.max_frame_size = 200; | 
|  | source_ = QuicMakeUnique<QuartcDataSource>( | 
|  | simulator_.GetClock(), simulator_.GetAlarmFactory(), | 
|  | simulator_.GetRandomGenerator(), config, &delegate_); | 
|  |  | 
|  | // Allocate enough bandwidth to send a 200-byte frame and a 1-byte frame. | 
|  | source_->AllocateBandwidth( | 
|  | QuicBandwidth::FromBytesAndTimeDelta(201, config.frame_interval)); | 
|  | source_->SetEnabled(true); | 
|  |  | 
|  | QuicTime start_time = simulator_.GetClock()->Now(); | 
|  | simulator_.RunFor(config.frame_interval); | 
|  |  | 
|  | ASSERT_EQ(delegate_.frames().size(), 2u); | 
|  | EXPECT_EQ(delegate_.frames()[0].payload.size(), 200u - kDataFrameHeaderSize); | 
|  | EXPECT_EQ(delegate_.frames()[0].size, 200u); | 
|  |  | 
|  | // The second frame, using the 1 leftover byte from the first, rounds up to | 
|  | // the minimum frame size (just the header and no payload). | 
|  | EXPECT_EQ(delegate_.frames()[1].payload.size(), 0u); | 
|  | EXPECT_EQ(delegate_.frames()[1].size, kDataFrameHeaderSize); | 
|  |  | 
|  | // Header fields are still present and parseable. | 
|  | EXPECT_EQ(delegate_.frames()[1].source_id, 0); | 
|  | EXPECT_EQ(delegate_.frames()[1].sequence_number, 1); | 
|  | EXPECT_EQ(delegate_.frames()[1].send_time, start_time); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace quic |