blob: 6f78d87bd546c7a4b773bc3956bfa20d1be03edc [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 "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
namespace quic {
namespace test {
namespace {
class QpackBlockingManagerTest : public QuicTest {
protected:
QpackBlockingManagerTest() = default;
~QpackBlockingManagerTest() override = default;
QpackBlockingManager manager_;
};
TEST_F(QpackBlockingManagerTest, Empty) {
EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
EXPECT_FALSE(manager_.OnHeaderAcknowledgement(0));
EXPECT_FALSE(manager_.OnHeaderAcknowledgement(1));
}
TEST_F(QpackBlockingManagerTest, NotBlockedByInsertCountIncrement) {
manager_.OnInsertCountIncrement(2);
// Stream 0 is not blocked, because it only references entries that are
// already acknowledged by an Insert Count Increment instruction.
manager_.OnHeaderBlockSent(0, {1, 0});
EXPECT_EQ(0u, manager_.blocked_stream_count());
}
TEST_F(QpackBlockingManagerTest, UnblockedByInsertCountIncrement) {
manager_.OnHeaderBlockSent(0, {1, 0});
EXPECT_EQ(1u, manager_.blocked_stream_count());
manager_.OnInsertCountIncrement(2);
EXPECT_EQ(0u, manager_.blocked_stream_count());
}
TEST_F(QpackBlockingManagerTest, NotBlockedByHeaderAcknowledgement) {
manager_.OnHeaderBlockSent(0, {2, 1, 1});
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(0u, manager_.blocked_stream_count());
// Stream 1 is not blocked, because it only references entries that are
// already acknowledged by a Header Acknowledgement instruction.
manager_.OnHeaderBlockSent(1, {2, 2});
EXPECT_EQ(0u, manager_.blocked_stream_count());
}
TEST_F(QpackBlockingManagerTest, UnblockedByHeaderAcknowledgement) {
manager_.OnHeaderBlockSent(0, {2, 1, 1});
manager_.OnHeaderBlockSent(1, {2, 2});
EXPECT_EQ(2u, manager_.blocked_stream_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(0u, manager_.blocked_stream_count());
}
TEST_F(QpackBlockingManagerTest, KnownReceivedCount) {
EXPECT_EQ(0u, manager_.known_received_count());
// Sending a header block does not change Known Received Count.
manager_.OnHeaderBlockSent(0, {0});
EXPECT_EQ(0u, manager_.known_received_count());
manager_.OnHeaderBlockSent(1, {1});
EXPECT_EQ(0u, manager_.known_received_count());
// Header Acknowledgement might increase Known Received Count.
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(1u, manager_.known_received_count());
manager_.OnHeaderBlockSent(2, {5});
EXPECT_EQ(1u, manager_.known_received_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
EXPECT_EQ(2u, manager_.known_received_count());
// Insert Count Increment increases Known Received Count.
manager_.OnInsertCountIncrement(2);
EXPECT_EQ(4u, manager_.known_received_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(2));
EXPECT_EQ(6u, manager_.known_received_count());
// Stream Cancellation does not change Known Received Count.
manager_.OnStreamCancellation(0);
EXPECT_EQ(6u, manager_.known_received_count());
// Header Acknowledgement of a block with smaller Required Insert Count does
// not increase Known Received Count.
manager_.OnHeaderBlockSent(0, {3});
EXPECT_EQ(6u, manager_.known_received_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(6u, manager_.known_received_count());
// Header Acknowledgement of a block with equal Required Insert Count does not
// increase Known Received Count.
manager_.OnHeaderBlockSent(1, {5});
EXPECT_EQ(6u, manager_.known_received_count());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
EXPECT_EQ(6u, manager_.known_received_count());
}
TEST_F(QpackBlockingManagerTest, SmallestBlockingIndex) {
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {0});
EXPECT_EQ(0u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(1, {2});
EXPECT_EQ(0u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(2u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(1, {1});
EXPECT_EQ(1u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
EXPECT_EQ(1u, manager_.smallest_blocking_index());
// Insert Count Increment does not change smallest blocking index.
manager_.OnInsertCountIncrement(2);
EXPECT_EQ(1u, manager_.smallest_blocking_index());
manager_.OnStreamCancellation(1);
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
}
TEST_F(QpackBlockingManagerTest, HeaderAcknowledgementsOnSingleStream) {
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {2, 1, 1});
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(1u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {1, 0});
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(3u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {3});
EXPECT_EQ(3u, manager_.known_received_count());
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(3u, manager_.known_received_count());
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(3u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(4u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
EXPECT_FALSE(manager_.OnHeaderAcknowledgement(0));
}
TEST_F(QpackBlockingManagerTest, CancelStream) {
manager_.OnHeaderBlockSent(0, {3});
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(3u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {2});
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(2u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(1, {4});
EXPECT_EQ(2u, manager_.blocked_stream_count());
EXPECT_EQ(2u, manager_.smallest_blocking_index());
manager_.OnStreamCancellation(0);
EXPECT_EQ(1u, manager_.blocked_stream_count());
EXPECT_EQ(4u, manager_.smallest_blocking_index());
manager_.OnStreamCancellation(1);
EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
}
TEST_F(QpackBlockingManagerTest,
ReferenceOnEncoderStreamUnblockedByInsertCountIncrement) {
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
// Entry 1 refers to entry 0.
manager_.OnReferenceSentOnEncoderStream(1, 0);
// Entry 2 also refers to entry 0.
manager_.OnReferenceSentOnEncoderStream(2, 0);
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
// Acknowledging entry 1 still leaves one unacknowledged reference to entry 0.
manager_.OnInsertCountIncrement(2);
EXPECT_EQ(2u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
// Entry 3 also refers to entry 2.
manager_.OnReferenceSentOnEncoderStream(3, 2);
EXPECT_EQ(2u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
// Acknowledging entry 2 removes last reference to entry 0.
manager_.OnInsertCountIncrement(1);
EXPECT_EQ(3u, manager_.known_received_count());
EXPECT_EQ(2u, manager_.smallest_blocking_index());
// Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
manager_.OnInsertCountIncrement(2);
EXPECT_EQ(5u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
}
TEST_F(QpackBlockingManagerTest,
ReferenceOnEncoderStreamUnblockedByHeaderAcknowledgement) {
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
// Entry 1 refers to entry 0.
manager_.OnReferenceSentOnEncoderStream(1, 0);
// Entry 2 also refers to entry 0.
manager_.OnReferenceSentOnEncoderStream(2, 0);
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
// Acknowledging a header block with entries up to 1 still leave one
// unacknowledged reference to entry 0.
manager_.OnHeaderBlockSent(/* stream_id = */ 0, {0, 1});
manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
EXPECT_EQ(2u, manager_.known_received_count());
EXPECT_EQ(0u, manager_.smallest_blocking_index());
// Entry 3 also refers to entry 2.
manager_.OnReferenceSentOnEncoderStream(3, 2);
// Acknowledging a header block with entries up to 2 removes last reference to
// entry 0.
manager_.OnHeaderBlockSent(/* stream_id = */ 0, {2, 0, 2});
manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
EXPECT_EQ(3u, manager_.known_received_count());
EXPECT_EQ(2u, manager_.smallest_blocking_index());
// Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
manager_.OnHeaderBlockSent(/* stream_id = */ 0, {1, 4, 2, 0});
manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
EXPECT_EQ(5u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
}
} // namespace
} // namespace test
} // namespace quic