blob: c7305e7dac1e1fc81e7f57ad7991971bcac5701e [file] [log] [blame]
// Copyright (c) 2019 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 "spdy/core/lifo_write_scheduler.h"
#include "common/platform/api/quiche_test.h"
#include "spdy/core/spdy_protocol.h"
#include "spdy/core/spdy_test_utils.h"
#include "spdy/platform/api/spdy_test_helpers.h"
namespace spdy {
namespace test {
template <typename StreamIdType>
class LifoWriteSchedulerPeer {
public:
explicit LifoWriteSchedulerPeer(LifoWriteScheduler<StreamIdType>* scheduler)
: scheduler_(scheduler) {}
size_t NumRegisteredListStreams() const {
return scheduler_->registered_streams_.size();
}
std::set<StreamIdType>* GetReadyList() const {
return &scheduler_->ready_streams_;
}
private:
LifoWriteScheduler<StreamIdType>* scheduler_;
};
// Test add and remove from ready list.
TEST(LifoWriteSchedulerTest, ReadyListTest) {
LifoWriteScheduler<SpdyStreamId> lifo;
LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
EXPECT_SPDY_BUG(
EXPECT_EQ(0u, std::get<0>(lifo.PopNextReadyStreamAndPrecedence())),
"No ready streams available");
EXPECT_SPDY_BUG(EXPECT_EQ(0u, lifo.PopNextReadyStream()),
"No ready streams available");
EXPECT_FALSE(lifo.HasReadyStreams());
EXPECT_SPDY_BUG(lifo.MarkStreamReady(9, true), "Stream 9 is not registered");
EXPECT_SPDY_BUG(lifo.IsStreamReady(9), "Stream 9 is not registered");
SpdyStreamPrecedence precedence(1);
lifo.RegisterStream(3, precedence);
EXPECT_FALSE(lifo.IsStreamReady(3));
lifo.RegisterStream(7, precedence);
lifo.RegisterStream(9, precedence);
lifo.RegisterStream(11, precedence);
lifo.RegisterStream(13, precedence);
lifo.RegisterStream(15, precedence);
lifo.RegisterStream(17, precedence);
lifo.MarkStreamReady(9, true);
lifo.MarkStreamReady(15, true);
lifo.MarkStreamReady(7, true);
lifo.MarkStreamReady(13, true);
lifo.MarkStreamReady(11, true);
lifo.MarkStreamReady(3, true);
EXPECT_TRUE(lifo.IsStreamReady(3));
lifo.MarkStreamReady(17, true);
EXPECT_TRUE(lifo.HasReadyStreams());
EXPECT_EQ(7u, lifo.NumReadyStreams());
// Verify MarkStream(Not)Ready() can be called multiple times for the same
// stream.
lifo.MarkStreamReady(11, true);
lifo.MarkStreamNotReady(5);
lifo.MarkStreamNotReady(21);
EXPECT_EQ(17u, lifo.PopNextReadyStream());
EXPECT_EQ(15u, std::get<0>(lifo.PopNextReadyStreamAndPrecedence()));
EXPECT_TRUE(lifo.ShouldYield(9));
EXPECT_FALSE(lifo.ShouldYield(13));
EXPECT_FALSE(lifo.ShouldYield(15));
lifo.MarkStreamNotReady(3);
EXPECT_TRUE(peer.GetReadyList()->find(3) == peer.GetReadyList()->end());
lifo.MarkStreamNotReady(13);
EXPECT_TRUE(peer.GetReadyList()->find(13) == peer.GetReadyList()->end());
lifo.MarkStreamNotReady(7);
EXPECT_TRUE(peer.GetReadyList()->find(7) == peer.GetReadyList()->end());
EXPECT_EQ(2u, lifo.NumReadyStreams());
lifo.MarkStreamNotReady(9);
lifo.MarkStreamNotReady(11);
EXPECT_FALSE(lifo.ShouldYield(1));
}
// Test add and remove from registered list.
TEST(LifoWriteSchedulerTest, RegisterListTest) {
LifoWriteScheduler<SpdyStreamId> lifo;
LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
SpdyStreamPrecedence precedence(1);
EXPECT_EQ(0u, lifo.NumRegisteredStreams());
lifo.RegisterStream(3, precedence);
lifo.RegisterStream(5, precedence);
lifo.RegisterStream(7, precedence);
lifo.RegisterStream(9, precedence);
lifo.RegisterStream(11, precedence);
EXPECT_EQ(5u, lifo.NumRegisteredStreams());
EXPECT_TRUE(lifo.StreamRegistered(3));
EXPECT_TRUE(lifo.StreamRegistered(5));
EXPECT_TRUE(lifo.StreamRegistered(7));
EXPECT_TRUE(lifo.StreamRegistered(9));
EXPECT_TRUE(lifo.StreamRegistered(11));
EXPECT_SPDY_BUG(lifo.RegisterStream(11, precedence),
"Stream 11 already registered");
EXPECT_EQ(5u, peer.NumRegisteredListStreams());
lifo.UnregisterStream(3);
EXPECT_EQ(4u, lifo.NumRegisteredStreams());
EXPECT_FALSE(lifo.StreamRegistered(3));
EXPECT_SPDY_BUG(lifo.UnregisterStream(3), "Stream 3 is not registered");
EXPECT_SPDY_BUG(lifo.UnregisterStream(13), "Stream 13 is not registered");
lifo.UnregisterStream(11);
EXPECT_FALSE(lifo.StreamRegistered(11));
lifo.UnregisterStream(7);
EXPECT_EQ(2u, lifo.NumRegisteredStreams());
EXPECT_FALSE(lifo.StreamRegistered(7));
EXPECT_TRUE(lifo.StreamRegistered(5));
EXPECT_TRUE(lifo.StreamRegistered(9));
}
// Test mark latest event time.
TEST(LifoWriteSchedulerTest, GetLatestEventTest) {
LifoWriteScheduler<SpdyStreamId> lifo;
LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
SpdyStreamPrecedence precedence(1);
lifo.RegisterStream(1, precedence);
lifo.RegisterStream(3, precedence);
lifo.RegisterStream(5, precedence);
lifo.RegisterStream(7, precedence);
lifo.RegisterStream(9, precedence);
lifo.RecordStreamEventTime(1, 1);
lifo.RecordStreamEventTime(3, 8);
lifo.RecordStreamEventTime(5, 4);
lifo.RecordStreamEventTime(7, 2);
lifo.RecordStreamEventTime(9, 3);
EXPECT_SPDY_BUG(lifo.RecordStreamEventTime(11, 1),
"Stream 11 is not registered");
EXPECT_EQ(0, lifo.GetLatestEventWithPrecedence(9));
EXPECT_EQ(3, lifo.GetLatestEventWithPrecedence(7));
EXPECT_EQ(3, lifo.GetLatestEventWithPrecedence(5));
EXPECT_EQ(4, lifo.GetLatestEventWithPrecedence(3));
EXPECT_EQ(8, lifo.GetLatestEventWithPrecedence(1));
EXPECT_SPDY_BUG(lifo.GetLatestEventWithPrecedence(11),
"Stream 11 is not registered");
}
TEST(LifoWriteSchedulerTest, GetStreamPrecedence) {
LifoWriteScheduler<SpdyStreamId> lifo;
// Return lowest priority for unknown stream.
EXPECT_EQ(kV3LowestPriority, lifo.GetStreamPrecedence(1).spdy3_priority());
lifo.RegisterStream(1, SpdyStreamPrecedence(3));
EXPECT_TRUE(lifo.GetStreamPrecedence(1).is_spdy3_priority());
EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
// Redundant registration shouldn't change stream priority.
EXPECT_SPDY_BUG(lifo.RegisterStream(1, SpdyStreamPrecedence(4)),
"Stream 1 already registered");
EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
lifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5));
EXPECT_EQ(5, lifo.GetStreamPrecedence(1).spdy3_priority());
}
} // namespace test
} // namespace spdy