From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../wrapping_active_ice_controller_unittest.cc | 315 +++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc (limited to 'third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc') diff --git a/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc b/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc new file mode 100644 index 0000000000..b4811bd297 --- /dev/null +++ b/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc @@ -0,0 +1,315 @@ +/* + * Copyright 2009 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "p2p/base/wrapping_active_ice_controller.h" + +#include +#include +#include + +#include "p2p/base/connection.h" +#include "p2p/base/mock_ice_agent.h" +#include "p2p/base/mock_ice_controller.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" + +namespace { + +using ::cricket::Connection; +using ::cricket::IceConfig; +using ::cricket::IceControllerFactoryArgs; +using ::cricket::IceControllerInterface; +using ::cricket::IceMode; +using ::cricket::IceRecheckEvent; +using ::cricket::IceSwitchReason; +using ::cricket::MockIceAgent; +using ::cricket::MockIceController; +using ::cricket::MockIceControllerFactory; +using ::cricket::NominationMode; +using ::cricket::WrappingActiveIceController; + +using ::testing::_; +using ::testing::ElementsAreArray; +using ::testing::IsEmpty; +using ::testing::NiceMock; +using ::testing::Ref; +using ::testing::Return; +using ::testing::Sequence; + +using ::rtc::AutoThread; +using ::rtc::Event; +using ::rtc::ScopedFakeClock; +using ::webrtc::TimeDelta; + +using NiceMockIceController = NiceMock; + +static const Connection* kConnection = + reinterpret_cast(0xabcd); +static const Connection* kConnectionTwo = + reinterpret_cast(0xbcde); +static const Connection* kConnectionThree = + reinterpret_cast(0xcdef); + +static const std::vector kEmptyConnsList = + std::vector(); + +static const TimeDelta kTick = TimeDelta::Millis(1); + +TEST(WrappingActiveIceControllerTest, CreateLegacyIceControllerFromFactory) { + AutoThread main; + MockIceAgent agent; + IceControllerFactoryArgs args; + MockIceControllerFactory legacy_controller_factory; + EXPECT_CALL(legacy_controller_factory, RecordIceControllerCreated()).Times(1); + WrappingActiveIceController controller(&agent, &legacy_controller_factory, + args); +} + +TEST(WrappingActiveIceControllerTest, PassthroughIceControllerInterface) { + AutoThread main; + MockIceAgent agent; + std::unique_ptr will_move = + std::make_unique(IceControllerFactoryArgs{}); + MockIceController* wrapped = will_move.get(); + WrappingActiveIceController controller(&agent, std::move(will_move)); + + IceConfig config{}; + EXPECT_CALL(*wrapped, SetIceConfig(Ref(config))); + controller.SetIceConfig(config); + + EXPECT_CALL(*wrapped, + GetUseCandidateAttr(kConnection, NominationMode::AGGRESSIVE, + IceMode::ICEMODE_LITE)) + .WillOnce(Return(true)); + EXPECT_TRUE(controller.GetUseCandidateAttribute( + kConnection, NominationMode::AGGRESSIVE, IceMode::ICEMODE_LITE)); + + EXPECT_CALL(*wrapped, AddConnection(kConnection)); + controller.OnConnectionAdded(kConnection); + + EXPECT_CALL(*wrapped, OnConnectionDestroyed(kConnection)); + controller.OnConnectionDestroyed(kConnection); + + EXPECT_CALL(*wrapped, SetSelectedConnection(kConnection)); + controller.OnConnectionSwitched(kConnection); + + EXPECT_CALL(*wrapped, MarkConnectionPinged(kConnection)); + controller.OnConnectionPinged(kConnection); + + EXPECT_CALL(*wrapped, FindNextPingableConnection()) + .WillOnce(Return(kConnection)); + EXPECT_EQ(controller.FindNextPingableConnection(), kConnection); +} + +TEST(WrappingActiveIceControllerTest, HandlesImmediateSwitchRequest) { + AutoThread main; + ScopedFakeClock clock; + NiceMock agent; + std::unique_ptr will_move = + std::make_unique(IceControllerFactoryArgs{}); + NiceMockIceController* wrapped = will_move.get(); + WrappingActiveIceController controller(&agent, std::move(will_move)); + + IceSwitchReason reason = IceSwitchReason::NOMINATION_ON_CONTROLLED_SIDE; + std::vector conns_to_forget{kConnectionTwo}; + int recheck_delay_ms = 10; + IceControllerInterface::SwitchResult switch_result{ + kConnection, + IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK, + recheck_delay_ms), + conns_to_forget}; + + // ICE controller should switch to given connection immediately. + Sequence check_then_switch; + EXPECT_CALL(*wrapped, ShouldSwitchConnection(reason, kConnection)) + .InSequence(check_then_switch) + .WillOnce(Return(switch_result)); + EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason)) + .InSequence(check_then_switch); + EXPECT_CALL(agent, ForgetLearnedStateForConnections( + ElementsAreArray(conns_to_forget))); + + EXPECT_TRUE(controller.OnImmediateSwitchRequest(reason, kConnection)); + + // No rechecks before recheck delay. + clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms - 1)); + + // ICE controller should recheck for best connection after the recheck delay. + Sequence recheck_sort; + EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(recheck_sort); + EXPECT_CALL(*wrapped, + SortAndSwitchConnection(IceSwitchReason::ICE_CONTROLLER_RECHECK)) + .InSequence(recheck_sort) + .WillOnce(Return(IceControllerInterface::SwitchResult{})); + EXPECT_CALL(agent, ForgetLearnedStateForConnections(IsEmpty())); + + clock.AdvanceTime(kTick); +} + +TEST(WrappingActiveIceControllerTest, HandlesImmediateSortAndSwitchRequest) { + AutoThread main; + ScopedFakeClock clock; + NiceMock agent; + std::unique_ptr will_move = + std::make_unique(IceControllerFactoryArgs{}); + NiceMockIceController* wrapped = will_move.get(); + WrappingActiveIceController controller(&agent, std::move(will_move)); + + IceSwitchReason reason = IceSwitchReason::NEW_CONNECTION_FROM_LOCAL_CANDIDATE; + std::vector conns_to_forget{kConnectionTwo}; + std::vector conns_to_prune{kConnectionThree}; + int recheck_delay_ms = 10; + IceControllerInterface::SwitchResult switch_result{ + kConnection, + IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK, + recheck_delay_ms), + conns_to_forget}; + + Sequence sort_and_switch; + EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(sort_and_switch); + EXPECT_CALL(*wrapped, SortAndSwitchConnection(reason)) + .InSequence(sort_and_switch) + .WillOnce(Return(switch_result)); + EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason)) + .InSequence(sort_and_switch); + EXPECT_CALL(*wrapped, PruneConnections()) + .InSequence(sort_and_switch) + .WillOnce(Return(conns_to_prune)); + EXPECT_CALL(agent, PruneConnections(ElementsAreArray(conns_to_prune))) + .InSequence(sort_and_switch); + + controller.OnImmediateSortAndSwitchRequest(reason); + + // No rechecks before recheck delay. + clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms - 1)); + + // ICE controller should recheck for best connection after the recheck delay. + Sequence recheck_sort; + EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(recheck_sort); + EXPECT_CALL(*wrapped, + SortAndSwitchConnection(IceSwitchReason::ICE_CONTROLLER_RECHECK)) + .InSequence(recheck_sort) + .WillOnce(Return(IceControllerInterface::SwitchResult{})); + EXPECT_CALL(*wrapped, PruneConnections()) + .InSequence(recheck_sort) + .WillOnce(Return(kEmptyConnsList)); + EXPECT_CALL(agent, PruneConnections(IsEmpty())).InSequence(recheck_sort); + + clock.AdvanceTime(kTick); +} + +TEST(WrappingActiveIceControllerTest, HandlesSortAndSwitchRequest) { + AutoThread main; + ScopedFakeClock clock; + + // Block the main task queue until ready. + Event init; + TimeDelta init_delay = TimeDelta::Millis(10); + main.PostTask([&init, &init_delay] { init.Wait(init_delay); }); + + NiceMock agent; + std::unique_ptr will_move = + std::make_unique(IceControllerFactoryArgs{}); + NiceMockIceController* wrapped = will_move.get(); + WrappingActiveIceController controller(&agent, std::move(will_move)); + + IceSwitchReason reason = IceSwitchReason::NETWORK_PREFERENCE_CHANGE; + + // No action should occur immediately + EXPECT_CALL(agent, UpdateConnectionStates()).Times(0); + EXPECT_CALL(*wrapped, SortAndSwitchConnection(_)).Times(0); + EXPECT_CALL(agent, SwitchSelectedConnection(_, _)).Times(0); + + controller.OnSortAndSwitchRequest(reason); + + std::vector conns_to_forget{kConnectionTwo}; + int recheck_delay_ms = 10; + IceControllerInterface::SwitchResult switch_result{ + kConnection, + IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK, + recheck_delay_ms), + conns_to_forget}; + + // Sort and switch should take place as the subsequent task. + Sequence sort_and_switch; + EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(sort_and_switch); + EXPECT_CALL(*wrapped, SortAndSwitchConnection(reason)) + .InSequence(sort_and_switch) + .WillOnce(Return(switch_result)); + EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason)) + .InSequence(sort_and_switch); + + // Unblock the init task. + clock.AdvanceTime(init_delay); +} + +TEST(WrappingActiveIceControllerTest, StartPingingAfterSortAndSwitch) { + AutoThread main; + ScopedFakeClock clock; + + // Block the main task queue until ready. + Event init; + TimeDelta init_delay = TimeDelta::Millis(10); + main.PostTask([&init, &init_delay] { init.Wait(init_delay); }); + + NiceMock agent; + std::unique_ptr will_move = + std::make_unique(IceControllerFactoryArgs{}); + NiceMockIceController* wrapped = will_move.get(); + WrappingActiveIceController controller(&agent, std::move(will_move)); + + // Pinging does not start automatically, unless triggered through a sort. + EXPECT_CALL(*wrapped, HasPingableConnection()).Times(0); + EXPECT_CALL(*wrapped, SelectConnectionToPing(_)).Times(0); + EXPECT_CALL(agent, OnStartedPinging()).Times(0); + + controller.OnSortAndSwitchRequest(IceSwitchReason::DATA_RECEIVED); + + // Pinging does not start if no pingable connection. + EXPECT_CALL(*wrapped, HasPingableConnection()).WillOnce(Return(false)); + EXPECT_CALL(*wrapped, SelectConnectionToPing(_)).Times(0); + EXPECT_CALL(agent, OnStartedPinging()).Times(0); + + // Unblock the init task. + clock.AdvanceTime(init_delay); + + int recheck_delay_ms = 10; + IceControllerInterface::PingResult ping_result(kConnection, recheck_delay_ms); + + // Pinging starts when there is a pingable connection. + Sequence start_pinging; + EXPECT_CALL(*wrapped, HasPingableConnection()) + .InSequence(start_pinging) + .WillOnce(Return(true)); + EXPECT_CALL(agent, OnStartedPinging()).InSequence(start_pinging); + EXPECT_CALL(agent, GetLastPingSentMs()) + .InSequence(start_pinging) + .WillOnce(Return(123)); + EXPECT_CALL(*wrapped, SelectConnectionToPing(123)) + .InSequence(start_pinging) + .WillOnce(Return(ping_result)); + EXPECT_CALL(agent, SendPingRequest(kConnection)).InSequence(start_pinging); + + controller.OnSortAndSwitchRequest(IceSwitchReason::DATA_RECEIVED); + clock.AdvanceTime(kTick); + + // ICE controller should recheck and ping after the recheck delay. + // No ping should be sent if no connection selected to ping. + EXPECT_CALL(agent, GetLastPingSentMs()).WillOnce(Return(456)); + EXPECT_CALL(*wrapped, SelectConnectionToPing(456)) + .WillOnce(Return(IceControllerInterface::PingResult( + /* connection= */ nullptr, recheck_delay_ms))); + EXPECT_CALL(agent, SendPingRequest(kConnection)).Times(0); + + clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms)); +} + +} // namespace -- cgit v1.2.3