| // Copyright (c) 2015 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/spdy/priority_write_scheduler.h" |
| |
| #include "net/test/gtest_util.h" |
| |
| namespace net { |
| namespace test { |
| namespace { |
| |
| class PriorityWriteSchedulerTest : public ::testing::Test { |
| public: |
| PriorityWriteScheduler<int> scheduler_; |
| }; |
| |
| TEST_F(PriorityWriteSchedulerTest, RegisterUnregisterStreams) { |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| scheduler_.RegisterStream(1, 1); |
| |
| // Try redundant registrations. |
| EXPECT_DFATAL(scheduler_.RegisterStream(1, 1), "Stream 1 already registered"); |
| EXPECT_DFATAL(scheduler_.RegisterStream(1, 2), "Stream 1 already registered"); |
| |
| scheduler_.RegisterStream(2, 3); |
| |
| // Verify registration != ready. |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| |
| scheduler_.UnregisterStream(1); |
| scheduler_.UnregisterStream(2); |
| |
| // Try redundant unregistration. |
| EXPECT_DFATAL(scheduler_.UnregisterStream(1), "Stream 1 not registered"); |
| EXPECT_DFATAL(scheduler_.UnregisterStream(2), "Stream 2 not registered"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, GetStreamPriority) { |
| EXPECT_DFATAL(EXPECT_EQ(kV3LowestPriority, scheduler_.GetStreamPriority(1)), |
| "Stream 1 not registered"); |
| |
| scheduler_.RegisterStream(1, 3); |
| EXPECT_EQ(3, scheduler_.GetStreamPriority(1)); |
| |
| // Redundant registration shouldn't change stream priority. |
| EXPECT_DFATAL(scheduler_.RegisterStream(1, 4), "Stream 1 already registered"); |
| EXPECT_EQ(3, scheduler_.GetStreamPriority(1)); |
| |
| scheduler_.UpdateStreamPriority(1, 5); |
| EXPECT_EQ(5, scheduler_.GetStreamPriority(1)); |
| |
| // Toggling ready state shouldn't change stream priority. |
| scheduler_.MarkStreamReady(1, true); |
| EXPECT_EQ(5, scheduler_.GetStreamPriority(1)); |
| |
| // Test changing priority of ready stream. |
| EXPECT_EQ(1u, scheduler_.NumReadyStreams(5)); |
| scheduler_.UpdateStreamPriority(1, 6); |
| EXPECT_EQ(6, scheduler_.GetStreamPriority(1)); |
| EXPECT_EQ(0u, scheduler_.NumReadyStreams(5)); |
| EXPECT_EQ(1u, scheduler_.NumReadyStreams(6)); |
| |
| EXPECT_EQ(1, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(6, scheduler_.GetStreamPriority(1)); |
| |
| scheduler_.UnregisterStream(1); |
| EXPECT_DFATAL(EXPECT_EQ(kV3LowestPriority, scheduler_.GetStreamPriority(1)), |
| "Stream 1 not registered"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, UpdateStreamPriority) { |
| // Updating priority of unregistered stream should have no effect. |
| EXPECT_DFATAL(EXPECT_EQ(kV3LowestPriority, scheduler_.GetStreamPriority(3)), |
| "Stream 3 not registered"); |
| EXPECT_DFATAL(scheduler_.UpdateStreamPriority(3, 1), |
| "Stream 3 not registered"); |
| EXPECT_DFATAL(EXPECT_EQ(kV3LowestPriority, scheduler_.GetStreamPriority(3)), |
| "Stream 3 not registered"); |
| |
| scheduler_.RegisterStream(3, 1); |
| EXPECT_EQ(1, scheduler_.GetStreamPriority(3)); |
| scheduler_.UpdateStreamPriority(3, 2); |
| EXPECT_EQ(2, scheduler_.GetStreamPriority(3)); |
| |
| // Updating priority of stream to current priority value is valid, but has no |
| // effect. |
| scheduler_.UpdateStreamPriority(3, 2); |
| EXPECT_EQ(2, scheduler_.GetStreamPriority(3)); |
| |
| // Even though stream 4 is marked ready after stream 5, it should be returned |
| // first by PopNextReadyStream() since it has higher priority. |
| scheduler_.RegisterStream(4, 1); |
| scheduler_.MarkStreamReady(3, false); // priority 2 |
| scheduler_.MarkStreamReady(4, false); // priority 1 |
| EXPECT_EQ(4, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(3, scheduler_.PopNextReadyStream()); |
| |
| // Verify that lowering priority of stream 4 causes it to be returned later |
| // by PopNextReadyStream(). |
| scheduler_.MarkStreamReady(3, false); // priority 2 |
| scheduler_.MarkStreamReady(4, false); // priority 1 |
| scheduler_.UpdateStreamPriority(4, 3); |
| EXPECT_EQ(3, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(4, scheduler_.PopNextReadyStream()); |
| |
| scheduler_.UnregisterStream(3); |
| EXPECT_DFATAL(scheduler_.UpdateStreamPriority(3, 1), |
| "Stream 3 not registered"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, HasHigherPriorityReadyStream) { |
| EXPECT_DFATAL(EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)), |
| "Stream 1 not registered"); |
| |
| // Add ready streams of lower and equal priority. |
| scheduler_.RegisterStream(1, 4); |
| EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)); |
| scheduler_.RegisterStream(2, 5); |
| scheduler_.MarkStreamReady(2, false); |
| EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)); |
| scheduler_.RegisterStream(3, 4); |
| scheduler_.MarkStreamReady(3, false); |
| EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)); |
| |
| // Verify that registration of a stream with higher priority isn't |
| // sufficient--it needs to be marked ready. |
| scheduler_.RegisterStream(4, 3); |
| EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)); |
| scheduler_.MarkStreamReady(4, false); |
| EXPECT_TRUE(scheduler_.HasHigherPriorityReadyStream(1)); |
| |
| // Verify method is responsive to changes in priority. |
| scheduler_.UpdateStreamPriority(1, 2); |
| EXPECT_FALSE(scheduler_.HasHigherPriorityReadyStream(1)); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBack) { |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| EXPECT_DFATAL(scheduler_.MarkStreamReady(1, false), |
| "Stream 1 not registered"); |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| |
| // Add a bunch of ready streams to tail of per-priority lists. |
| // Expected order: (P2) 4, (P3) 1, 2, 3, (P5) 5. |
| scheduler_.RegisterStream(1, 3); |
| scheduler_.MarkStreamReady(1, false); |
| EXPECT_TRUE(scheduler_.HasReadyStreams()); |
| scheduler_.RegisterStream(2, 3); |
| scheduler_.MarkStreamReady(2, false); |
| scheduler_.RegisterStream(3, 3); |
| scheduler_.MarkStreamReady(3, false); |
| scheduler_.RegisterStream(4, 2); |
| scheduler_.MarkStreamReady(4, false); |
| scheduler_.RegisterStream(5, 5); |
| scheduler_.MarkStreamReady(5, false); |
| |
| EXPECT_EQ(4, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(1, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(2, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(3, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(5, scheduler_.PopNextReadyStream()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyFront) { |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| EXPECT_DFATAL(scheduler_.MarkStreamReady(1, true), "Stream 1 not registered"); |
| EXPECT_FALSE(scheduler_.HasReadyStreams()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| |
| // Add a bunch of ready streams to head of per-priority lists. |
| // Expected order: (P2) 4, (P3) 3, 2, 1, (P5) 5 |
| scheduler_.RegisterStream(1, 3); |
| scheduler_.MarkStreamReady(1, true); |
| EXPECT_TRUE(scheduler_.HasReadyStreams()); |
| scheduler_.RegisterStream(2, 3); |
| scheduler_.MarkStreamReady(2, true); |
| scheduler_.RegisterStream(3, 3); |
| scheduler_.MarkStreamReady(3, true); |
| scheduler_.RegisterStream(4, 2); |
| scheduler_.MarkStreamReady(4, true); |
| scheduler_.RegisterStream(5, 5); |
| scheduler_.MarkStreamReady(5, true); |
| |
| EXPECT_EQ(4, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(3, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(2, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(1, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(5, scheduler_.PopNextReadyStream()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBackAndFront) { |
| scheduler_.RegisterStream(1, 4); |
| scheduler_.RegisterStream(2, 3); |
| scheduler_.RegisterStream(3, 3); |
| scheduler_.RegisterStream(4, 3); |
| scheduler_.RegisterStream(5, 4); |
| scheduler_.RegisterStream(6, 1); |
| |
| // Add a bunch of ready streams to per-priority lists, with variety of adding |
| // at head and tail. |
| // Expected order: (P1) 6, (P3) 4, 2, 3, (P4) 1, 5 |
| scheduler_.MarkStreamReady(1, true); |
| scheduler_.MarkStreamReady(2, true); |
| scheduler_.MarkStreamReady(3, false); |
| scheduler_.MarkStreamReady(4, true); |
| scheduler_.MarkStreamReady(5, false); |
| scheduler_.MarkStreamReady(6, true); |
| |
| EXPECT_EQ(6, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(4, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(2, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(3, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(1, scheduler_.PopNextReadyStream()); |
| EXPECT_EQ(5, scheduler_.PopNextReadyStream()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, MarkStreamNotReady) { |
| // Verify ready state reflected in NumReadyStreams(). |
| scheduler_.RegisterStream(1, 1); |
| EXPECT_EQ(0u, scheduler_.NumReadyStreams()); |
| scheduler_.MarkStreamReady(1, false); |
| EXPECT_EQ(1u, scheduler_.NumReadyStreams()); |
| scheduler_.MarkStreamNotReady(1); |
| EXPECT_EQ(0u, scheduler_.NumReadyStreams()); |
| |
| // Empty pop should fail. |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| |
| // Tolerate redundant marking of a stream as not ready. |
| scheduler_.MarkStreamNotReady(1); |
| EXPECT_EQ(0u, scheduler_.NumReadyStreams()); |
| |
| // Should only be able to mark registered streams. |
| EXPECT_DFATAL(scheduler_.MarkStreamNotReady(3), "Stream 3 not registered"); |
| } |
| |
| TEST_F(PriorityWriteSchedulerTest, UnregisterRemovesStream) { |
| scheduler_.RegisterStream(3, 4); |
| scheduler_.MarkStreamReady(3, false); |
| EXPECT_EQ(1u, scheduler_.NumReadyStreams()); |
| |
| // Unregistering a stream should remove it from set of ready streams. |
| scheduler_.UnregisterStream(3); |
| EXPECT_EQ(0u, scheduler_.NumReadyStreams()); |
| EXPECT_DFATAL(EXPECT_EQ(0, scheduler_.PopNextReadyStream()), |
| "No ready streams available"); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace net |