summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/p2p/base/wrapping_active_ice_controller_unittest.cc315
1 files changed, 315 insertions, 0 deletions
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 <memory>
+#include <utility>
+#include <vector>
+
+#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<MockIceController>;
+
+static const Connection* kConnection =
+ reinterpret_cast<const Connection*>(0xabcd);
+static const Connection* kConnectionTwo =
+ reinterpret_cast<const Connection*>(0xbcde);
+static const Connection* kConnectionThree =
+ reinterpret_cast<const Connection*>(0xcdef);
+
+static const std::vector<const Connection*> kEmptyConnsList =
+ std::vector<const Connection*>();
+
+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<MockIceController> will_move =
+ std::make_unique<MockIceController>(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<MockIceAgent> agent;
+ std::unique_ptr<NiceMockIceController> will_move =
+ std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
+ NiceMockIceController* wrapped = will_move.get();
+ WrappingActiveIceController controller(&agent, std::move(will_move));
+
+ IceSwitchReason reason = IceSwitchReason::NOMINATION_ON_CONTROLLED_SIDE;
+ std::vector<const Connection*> 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<MockIceAgent> agent;
+ std::unique_ptr<NiceMockIceController> will_move =
+ std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
+ NiceMockIceController* wrapped = will_move.get();
+ WrappingActiveIceController controller(&agent, std::move(will_move));
+
+ IceSwitchReason reason = IceSwitchReason::NEW_CONNECTION_FROM_LOCAL_CANDIDATE;
+ std::vector<const Connection*> conns_to_forget{kConnectionTwo};
+ std::vector<const Connection*> 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<MockIceAgent> agent;
+ std::unique_ptr<NiceMockIceController> will_move =
+ std::make_unique<NiceMockIceController>(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<const Connection*> 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<MockIceAgent> agent;
+ std::unique_ptr<NiceMockIceController> will_move =
+ std::make_unique<NiceMockIceController>(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