blob: 0ba80538d7c53b9e444bd92e6522ce1ec38eaf79 [file] [log] [blame]
// Copyright 2024 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/core/quic_connection_alarms.h"
#include <string>
#include "quiche/quic/core/quic_one_block_arena.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/test_tools/mock_clock.h"
#include "quiche/quic/test_tools/mock_quic_connection_alarms.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
#include "quiche/common/platform/api/quiche_expect_bug.h"
#include "quiche/common/platform/api/quiche_test.h"
namespace quic::test {
class QuicAlarmMultiplexerPeer {
public:
static MockAlarmFactory::TestAlarm* GetNowAlarm(
QuicAlarmMultiplexer& multiplexer) {
return static_cast<MockAlarmFactory::TestAlarm*>(
multiplexer.now_alarm_.get());
}
static MockAlarmFactory::TestAlarm* GetLaterAlarm(
QuicAlarmMultiplexer& multiplexer) {
return static_cast<MockAlarmFactory::TestAlarm*>(
multiplexer.later_alarm_.get());
}
};
namespace {
using ::testing::HasSubstr;
using ::testing::Not;
class QuicAlarmMultiplexerTest : public quiche::test::QuicheTest {
public:
QuicAlarmMultiplexerTest()
: clock_(delegate_.clock()),
multiplexer_(&delegate_, arena_, alarm_factory_),
now_alarm_(QuicAlarmMultiplexerPeer::GetNowAlarm(multiplexer_)),
later_alarm_(QuicAlarmMultiplexerPeer::GetLaterAlarm(multiplexer_)) {
clock_->AdvanceTime(QuicTimeDelta::FromSeconds(1234));
}
protected:
MockConnectionAlarmsDelegate delegate_;
MockClock* clock_;
QuicConnectionArena arena_;
MockAlarmFactory alarm_factory_;
QuicAlarmMultiplexer multiplexer_;
MockAlarmFactory::TestAlarm* now_alarm_;
MockAlarmFactory::TestAlarm* later_alarm_;
};
TEST_F(QuicAlarmMultiplexerTest, SetUpdateCancel) {
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_FALSE(multiplexer_.IsPermanentlyCancelled());
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), QuicTime::Zero());
const QuicTime time1 = clock_->Now();
const QuicTime time2 = time1 + QuicTimeDelta::FromMilliseconds(10);
multiplexer_.Set(QuicAlarmSlot::kSend, time1);
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), time1);
multiplexer_.Update(QuicAlarmSlot::kSend, time2, QuicTimeDelta::Zero());
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), time2);
multiplexer_.Cancel(QuicAlarmSlot::kSend);
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_FALSE(multiplexer_.IsPermanentlyCancelled());
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), QuicTime::Zero());
// Test set-via-update.
multiplexer_.Update(QuicAlarmSlot::kSend, time1, QuicTimeDelta::Zero());
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), time1);
// Test granularity.
multiplexer_.Update(QuicAlarmSlot::kSend, time2,
QuicTimeDelta::FromSeconds(1000));
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_EQ(multiplexer_.GetDeadline(QuicAlarmSlot::kSend), time1);
// Test cancel-via-update.
multiplexer_.Update(QuicAlarmSlot::kSend, QuicTime::Zero(),
QuicTimeDelta::Zero());
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
}
TEST_F(QuicAlarmMultiplexerTest, PermanentlyCancel) {
const QuicTime time = clock_->Now();
multiplexer_.Set(QuicAlarmSlot::kSend, time);
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_FALSE(multiplexer_.IsPermanentlyCancelled());
EXPECT_TRUE(now_alarm_->IsSet());
multiplexer_.CancelAllAlarms();
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kSend));
EXPECT_TRUE(multiplexer_.IsPermanentlyCancelled());
EXPECT_FALSE(now_alarm_->IsSet());
EXPECT_TRUE(now_alarm_->IsPermanentlyCancelled());
EXPECT_QUICHE_BUG(multiplexer_.Set(QuicAlarmSlot::kSend, time),
"permanently cancelled");
EXPECT_QUICHE_BUG(
multiplexer_.Update(QuicAlarmSlot::kSend, time, QuicTimeDelta::Zero()),
"permanently cancelled");
}
TEST_F(QuicAlarmMultiplexerTest, SingleAlarmScheduledForNow) {
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery, clock_->Now());
EXPECT_EQ(now_alarm_->deadline(), clock_->Now());
EXPECT_FALSE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, SingleAlarmScheduledForPast) {
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery,
clock_->Now() - QuicTimeDelta::FromMilliseconds(100));
EXPECT_EQ(now_alarm_->deadline(), clock_->Now());
EXPECT_FALSE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, SingleAlarmScheduledForFuture) {
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery,
clock_->Now() + QuicTimeDelta::FromMilliseconds(100));
EXPECT_FALSE(now_alarm_->IsSet());
EXPECT_EQ(later_alarm_->deadline(),
clock_->Now() + QuicTimeDelta::FromMilliseconds(100));
}
TEST_F(QuicAlarmMultiplexerTest, MultipleAlarmsNowAndFuture) {
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery, clock_->Now());
multiplexer_.Set(QuicAlarmSlot::kAck,
clock_->Now() + QuicTimeDelta::FromMilliseconds(100));
EXPECT_TRUE(now_alarm_->IsSet());
EXPECT_EQ(later_alarm_->deadline(),
clock_->Now() + QuicTimeDelta::FromMilliseconds(100));
}
TEST_F(QuicAlarmMultiplexerTest, FireSingleAlarmNow) {
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now());
ASSERT_TRUE(now_alarm_->IsSet());
EXPECT_CALL(delegate_, OnPingAlarm());
now_alarm_->Fire();
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kPing));
EXPECT_FALSE(now_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, FireSingleAlarmFuture) {
const QuicTime start = clock_->Now();
const QuicTime end = start + QuicTimeDelta::FromMilliseconds(100);
multiplexer_.Set(QuicAlarmSlot::kPing, end);
ASSERT_TRUE(later_alarm_->IsSet());
// Ensure that even if we fire the platform alarm prematurely, this works
// correctly.
EXPECT_CALL(delegate_, OnPingAlarm()).Times(0);
later_alarm_->Fire();
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kPing));
EXPECT_TRUE(later_alarm_->IsSet());
clock_->AdvanceTime(end - start);
ASSERT_EQ(later_alarm_->deadline(), end);
EXPECT_CALL(delegate_, OnPingAlarm()).Times(1);
later_alarm_->Fire();
EXPECT_FALSE(multiplexer_.IsSet(QuicAlarmSlot::kPing));
EXPECT_FALSE(now_alarm_->IsSet());
EXPECT_FALSE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, AlarmReschedulesItself) {
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now());
ASSERT_TRUE(now_alarm_->IsSet());
EXPECT_CALL(delegate_, OnPingAlarm()).Times(1).WillRepeatedly([&] {
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now());
});
now_alarm_->Fire();
EXPECT_TRUE(multiplexer_.IsSet(QuicAlarmSlot::kPing));
}
TEST_F(QuicAlarmMultiplexerTest, FireMultipleAlarmsNow) {
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now());
multiplexer_.Set(QuicAlarmSlot::kRetransmission, clock_->Now());
ASSERT_TRUE(now_alarm_->IsSet());
EXPECT_CALL(delegate_, OnPingAlarm());
EXPECT_CALL(delegate_, OnRetransmissionAlarm());
now_alarm_->Fire();
}
TEST_F(QuicAlarmMultiplexerTest, FireMultipleAlarmsLater) {
QuicTimeDelta delay = QuicTimeDelta::FromMilliseconds(10);
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now() + delay);
multiplexer_.Set(QuicAlarmSlot::kRetransmission, clock_->Now() + delay);
ASSERT_TRUE(later_alarm_->IsSet());
later_alarm_->Fire();
ASSERT_TRUE(later_alarm_->IsSet());
clock_->AdvanceTime(delay);
EXPECT_CALL(delegate_, OnPingAlarm());
EXPECT_CALL(delegate_, OnRetransmissionAlarm());
later_alarm_->Fire();
}
TEST_F(QuicAlarmMultiplexerTest, FireMultipleAlarmsLaterDifferentDelays) {
QuicTimeDelta delay = QuicTimeDelta::FromMilliseconds(10);
multiplexer_.Set(QuicAlarmSlot::kPing, clock_->Now() + delay);
multiplexer_.Set(QuicAlarmSlot::kRetransmission, clock_->Now() + 2 * delay);
ASSERT_TRUE(later_alarm_->IsSet());
EXPECT_CALL(delegate_, OnPingAlarm()).Times(0);
EXPECT_CALL(delegate_, OnRetransmissionAlarm()).Times(0);
later_alarm_->Fire();
ASSERT_TRUE(later_alarm_->IsSet());
clock_->AdvanceTime(delay);
EXPECT_CALL(delegate_, OnPingAlarm()).Times(1);
EXPECT_CALL(delegate_, OnRetransmissionAlarm()).Times(0);
later_alarm_->Fire();
ASSERT_TRUE(later_alarm_->IsSet());
clock_->AdvanceTime(delay);
EXPECT_CALL(delegate_, OnPingAlarm()).Times(0);
EXPECT_CALL(delegate_, OnRetransmissionAlarm()).Times(1);
later_alarm_->Fire();
EXPECT_FALSE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, FireMultipleAlarmsLaterDifferentDelaysAtOnce) {
QuicTimeDelta delay = QuicTimeDelta::FromMilliseconds(10);
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery, clock_->Now() + delay);
multiplexer_.Set(QuicAlarmSlot::kAck, clock_->Now() + 2 * delay);
ASSERT_TRUE(later_alarm_->IsSet());
clock_->AdvanceTime(2 * delay);
testing::Sequence seq;
EXPECT_CALL(delegate_, OnMtuDiscoveryAlarm()).InSequence(seq);
EXPECT_CALL(delegate_, OnAckAlarm()).InSequence(seq);
later_alarm_->Fire();
EXPECT_FALSE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, DeferUpdates) {
QuicTimeDelta delay = QuicTimeDelta::FromMilliseconds(10);
multiplexer_.DeferUnderlyingAlarmScheduling();
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery, clock_->Now());
multiplexer_.Set(QuicAlarmSlot::kAck, clock_->Now() + delay);
EXPECT_FALSE(now_alarm_->IsSet());
EXPECT_FALSE(later_alarm_->IsSet());
multiplexer_.ResumeUnderlyingAlarmScheduling();
EXPECT_TRUE(now_alarm_->IsSet());
EXPECT_TRUE(later_alarm_->IsSet());
}
TEST_F(QuicAlarmMultiplexerTest, DeferUpdatesAlreadySet) {
QuicTime deadline1 = clock_->Now() + QuicTimeDelta::FromMilliseconds(50);
QuicTime deadline2 = clock_->Now() + QuicTimeDelta::FromMilliseconds(10);
multiplexer_.Set(QuicAlarmSlot::kAck, deadline1);
EXPECT_EQ(later_alarm_->deadline(), deadline1);
multiplexer_.DeferUnderlyingAlarmScheduling();
multiplexer_.Set(QuicAlarmSlot::kSend, deadline2);
EXPECT_EQ(later_alarm_->deadline(), deadline1);
multiplexer_.ResumeUnderlyingAlarmScheduling();
EXPECT_EQ(later_alarm_->deadline(), deadline2);
}
TEST_F(QuicAlarmMultiplexerTest, DebugString) {
multiplexer_.Set(QuicAlarmSlot::kMtuDiscovery, clock_->Now());
multiplexer_.Set(QuicAlarmSlot::kPing,
clock_->Now() + QuicTimeDelta::FromMilliseconds(123));
std::string debug_view = multiplexer_.DebugString();
EXPECT_THAT(debug_view, HasSubstr("MtuDiscovery"));
EXPECT_THAT(debug_view, HasSubstr("Ping"));
EXPECT_THAT(debug_view, Not(HasSubstr("Ack")));
}
} // namespace
} // namespace quic::test