xref: /aosp_15_r20/external/webrtc/p2p/base/wrapping_active_ice_controller_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "p2p/base/wrapping_active_ice_controller.h"
12 
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #include "p2p/base/connection.h"
18 #include "p2p/base/mock_ice_agent.h"
19 #include "p2p/base/mock_ice_controller.h"
20 #include "rtc_base/fake_clock.h"
21 #include "rtc_base/gunit.h"
22 #include "rtc_base/thread.h"
23 
24 namespace {
25 
26 using ::cricket::Connection;
27 using ::cricket::IceConfig;
28 using ::cricket::IceControllerFactoryArgs;
29 using ::cricket::IceControllerInterface;
30 using ::cricket::IceMode;
31 using ::cricket::IceRecheckEvent;
32 using ::cricket::IceSwitchReason;
33 using ::cricket::MockIceAgent;
34 using ::cricket::MockIceController;
35 using ::cricket::MockIceControllerFactory;
36 using ::cricket::NominationMode;
37 using ::cricket::WrappingActiveIceController;
38 
39 using ::testing::_;
40 using ::testing::ElementsAreArray;
41 using ::testing::IsEmpty;
42 using ::testing::NiceMock;
43 using ::testing::Ref;
44 using ::testing::Return;
45 using ::testing::Sequence;
46 
47 using ::rtc::AutoThread;
48 using ::rtc::Event;
49 using ::rtc::ScopedFakeClock;
50 using ::webrtc::TimeDelta;
51 
52 using NiceMockIceController = NiceMock<MockIceController>;
53 
54 static const Connection* kConnection =
55     reinterpret_cast<const Connection*>(0xabcd);
56 static const Connection* kConnectionTwo =
57     reinterpret_cast<const Connection*>(0xbcde);
58 static const Connection* kConnectionThree =
59     reinterpret_cast<const Connection*>(0xcdef);
60 
61 static const std::vector<const Connection*> kEmptyConnsList =
62     std::vector<const Connection*>();
63 
64 static const TimeDelta kTick = TimeDelta::Millis(1);
65 
TEST(WrappingActiveIceControllerTest,CreateLegacyIceControllerFromFactory)66 TEST(WrappingActiveIceControllerTest, CreateLegacyIceControllerFromFactory) {
67   AutoThread main;
68   MockIceAgent agent;
69   IceControllerFactoryArgs args;
70   MockIceControllerFactory legacy_controller_factory;
71   EXPECT_CALL(legacy_controller_factory, RecordIceControllerCreated()).Times(1);
72   WrappingActiveIceController controller(&agent, &legacy_controller_factory,
73                                          args);
74 }
75 
TEST(WrappingActiveIceControllerTest,PassthroughIceControllerInterface)76 TEST(WrappingActiveIceControllerTest, PassthroughIceControllerInterface) {
77   AutoThread main;
78   MockIceAgent agent;
79   std::unique_ptr<MockIceController> will_move =
80       std::make_unique<MockIceController>(IceControllerFactoryArgs{});
81   MockIceController* wrapped = will_move.get();
82   WrappingActiveIceController controller(&agent, std::move(will_move));
83 
84   IceConfig config{};
85   EXPECT_CALL(*wrapped, SetIceConfig(Ref(config)));
86   controller.SetIceConfig(config);
87 
88   EXPECT_CALL(*wrapped,
89               GetUseCandidateAttr(kConnection, NominationMode::AGGRESSIVE,
90                                   IceMode::ICEMODE_LITE))
91       .WillOnce(Return(true));
92   EXPECT_TRUE(controller.GetUseCandidateAttribute(
93       kConnection, NominationMode::AGGRESSIVE, IceMode::ICEMODE_LITE));
94 
95   EXPECT_CALL(*wrapped, AddConnection(kConnection));
96   controller.OnConnectionAdded(kConnection);
97 
98   EXPECT_CALL(*wrapped, OnConnectionDestroyed(kConnection));
99   controller.OnConnectionDestroyed(kConnection);
100 
101   EXPECT_CALL(*wrapped, SetSelectedConnection(kConnection));
102   controller.OnConnectionSwitched(kConnection);
103 
104   EXPECT_CALL(*wrapped, MarkConnectionPinged(kConnection));
105   controller.OnConnectionPinged(kConnection);
106 
107   EXPECT_CALL(*wrapped, FindNextPingableConnection())
108       .WillOnce(Return(kConnection));
109   EXPECT_EQ(controller.FindNextPingableConnection(), kConnection);
110 }
111 
TEST(WrappingActiveIceControllerTest,HandlesImmediateSwitchRequest)112 TEST(WrappingActiveIceControllerTest, HandlesImmediateSwitchRequest) {
113   AutoThread main;
114   ScopedFakeClock clock;
115   NiceMock<MockIceAgent> agent;
116   std::unique_ptr<NiceMockIceController> will_move =
117       std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
118   NiceMockIceController* wrapped = will_move.get();
119   WrappingActiveIceController controller(&agent, std::move(will_move));
120 
121   IceSwitchReason reason = IceSwitchReason::NOMINATION_ON_CONTROLLED_SIDE;
122   std::vector<const Connection*> conns_to_forget{kConnectionTwo};
123   int recheck_delay_ms = 10;
124   IceControllerInterface::SwitchResult switch_result{
125       kConnection,
126       IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK,
127                       recheck_delay_ms),
128       conns_to_forget};
129 
130   // ICE controller should switch to given connection immediately.
131   Sequence check_then_switch;
132   EXPECT_CALL(*wrapped, ShouldSwitchConnection(reason, kConnection))
133       .InSequence(check_then_switch)
134       .WillOnce(Return(switch_result));
135   EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason))
136       .InSequence(check_then_switch);
137   EXPECT_CALL(agent, ForgetLearnedStateForConnections(
138                          ElementsAreArray(conns_to_forget)));
139 
140   EXPECT_TRUE(controller.OnImmediateSwitchRequest(reason, kConnection));
141 
142   // No rechecks before recheck delay.
143   clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms - 1));
144 
145   // ICE controller should recheck for best connection after the recheck delay.
146   Sequence recheck_sort;
147   EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(recheck_sort);
148   EXPECT_CALL(*wrapped,
149               SortAndSwitchConnection(IceSwitchReason::ICE_CONTROLLER_RECHECK))
150       .InSequence(recheck_sort)
151       .WillOnce(Return(IceControllerInterface::SwitchResult{}));
152   EXPECT_CALL(agent, ForgetLearnedStateForConnections(IsEmpty()));
153 
154   clock.AdvanceTime(kTick);
155 }
156 
TEST(WrappingActiveIceControllerTest,HandlesImmediateSortAndSwitchRequest)157 TEST(WrappingActiveIceControllerTest, HandlesImmediateSortAndSwitchRequest) {
158   AutoThread main;
159   ScopedFakeClock clock;
160   NiceMock<MockIceAgent> agent;
161   std::unique_ptr<NiceMockIceController> will_move =
162       std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
163   NiceMockIceController* wrapped = will_move.get();
164   WrappingActiveIceController controller(&agent, std::move(will_move));
165 
166   IceSwitchReason reason = IceSwitchReason::NEW_CONNECTION_FROM_LOCAL_CANDIDATE;
167   std::vector<const Connection*> conns_to_forget{kConnectionTwo};
168   std::vector<const Connection*> conns_to_prune{kConnectionThree};
169   int recheck_delay_ms = 10;
170   IceControllerInterface::SwitchResult switch_result{
171       kConnection,
172       IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK,
173                       recheck_delay_ms),
174       conns_to_forget};
175 
176   Sequence sort_and_switch;
177   EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(sort_and_switch);
178   EXPECT_CALL(*wrapped, SortAndSwitchConnection(reason))
179       .InSequence(sort_and_switch)
180       .WillOnce(Return(switch_result));
181   EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason))
182       .InSequence(sort_and_switch);
183   EXPECT_CALL(*wrapped, PruneConnections())
184       .InSequence(sort_and_switch)
185       .WillOnce(Return(conns_to_prune));
186   EXPECT_CALL(agent, PruneConnections(ElementsAreArray(conns_to_prune)))
187       .InSequence(sort_and_switch);
188 
189   controller.OnImmediateSortAndSwitchRequest(reason);
190 
191   // No rechecks before recheck delay.
192   clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms - 1));
193 
194   // ICE controller should recheck for best connection after the recheck delay.
195   Sequence recheck_sort;
196   EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(recheck_sort);
197   EXPECT_CALL(*wrapped,
198               SortAndSwitchConnection(IceSwitchReason::ICE_CONTROLLER_RECHECK))
199       .InSequence(recheck_sort)
200       .WillOnce(Return(IceControllerInterface::SwitchResult{}));
201   EXPECT_CALL(*wrapped, PruneConnections())
202       .InSequence(recheck_sort)
203       .WillOnce(Return(kEmptyConnsList));
204   EXPECT_CALL(agent, PruneConnections(IsEmpty())).InSequence(recheck_sort);
205 
206   clock.AdvanceTime(kTick);
207 }
208 
TEST(WrappingActiveIceControllerTest,HandlesSortAndSwitchRequest)209 TEST(WrappingActiveIceControllerTest, HandlesSortAndSwitchRequest) {
210   AutoThread main;
211   ScopedFakeClock clock;
212 
213   // Block the main task queue until ready.
214   Event init;
215   TimeDelta init_delay = TimeDelta::Millis(10);
216   main.PostTask([&init, &init_delay] { init.Wait(init_delay); });
217 
218   NiceMock<MockIceAgent> agent;
219   std::unique_ptr<NiceMockIceController> will_move =
220       std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
221   NiceMockIceController* wrapped = will_move.get();
222   WrappingActiveIceController controller(&agent, std::move(will_move));
223 
224   IceSwitchReason reason = IceSwitchReason::NETWORK_PREFERENCE_CHANGE;
225 
226   // No action should occur immediately
227   EXPECT_CALL(agent, UpdateConnectionStates()).Times(0);
228   EXPECT_CALL(*wrapped, SortAndSwitchConnection(_)).Times(0);
229   EXPECT_CALL(agent, SwitchSelectedConnection(_, _)).Times(0);
230 
231   controller.OnSortAndSwitchRequest(reason);
232 
233   std::vector<const Connection*> conns_to_forget{kConnectionTwo};
234   int recheck_delay_ms = 10;
235   IceControllerInterface::SwitchResult switch_result{
236       kConnection,
237       IceRecheckEvent(IceSwitchReason::ICE_CONTROLLER_RECHECK,
238                       recheck_delay_ms),
239       conns_to_forget};
240 
241   // Sort and switch should take place as the subsequent task.
242   Sequence sort_and_switch;
243   EXPECT_CALL(agent, UpdateConnectionStates()).InSequence(sort_and_switch);
244   EXPECT_CALL(*wrapped, SortAndSwitchConnection(reason))
245       .InSequence(sort_and_switch)
246       .WillOnce(Return(switch_result));
247   EXPECT_CALL(agent, SwitchSelectedConnection(kConnection, reason))
248       .InSequence(sort_and_switch);
249 
250   // Unblock the init task.
251   clock.AdvanceTime(init_delay);
252 }
253 
TEST(WrappingActiveIceControllerTest,StartPingingAfterSortAndSwitch)254 TEST(WrappingActiveIceControllerTest, StartPingingAfterSortAndSwitch) {
255   AutoThread main;
256   ScopedFakeClock clock;
257 
258   // Block the main task queue until ready.
259   Event init;
260   TimeDelta init_delay = TimeDelta::Millis(10);
261   main.PostTask([&init, &init_delay] { init.Wait(init_delay); });
262 
263   NiceMock<MockIceAgent> agent;
264   std::unique_ptr<NiceMockIceController> will_move =
265       std::make_unique<NiceMockIceController>(IceControllerFactoryArgs{});
266   NiceMockIceController* wrapped = will_move.get();
267   WrappingActiveIceController controller(&agent, std::move(will_move));
268 
269   // Pinging does not start automatically, unless triggered through a sort.
270   EXPECT_CALL(*wrapped, HasPingableConnection()).Times(0);
271   EXPECT_CALL(*wrapped, SelectConnectionToPing(_)).Times(0);
272   EXPECT_CALL(agent, OnStartedPinging()).Times(0);
273 
274   controller.OnSortAndSwitchRequest(IceSwitchReason::DATA_RECEIVED);
275 
276   // Pinging does not start if no pingable connection.
277   EXPECT_CALL(*wrapped, HasPingableConnection()).WillOnce(Return(false));
278   EXPECT_CALL(*wrapped, SelectConnectionToPing(_)).Times(0);
279   EXPECT_CALL(agent, OnStartedPinging()).Times(0);
280 
281   // Unblock the init task.
282   clock.AdvanceTime(init_delay);
283 
284   int recheck_delay_ms = 10;
285   IceControllerInterface::PingResult ping_result(kConnection, recheck_delay_ms);
286 
287   // Pinging starts when there is a pingable connection.
288   Sequence start_pinging;
289   EXPECT_CALL(*wrapped, HasPingableConnection())
290       .InSequence(start_pinging)
291       .WillOnce(Return(true));
292   EXPECT_CALL(agent, OnStartedPinging()).InSequence(start_pinging);
293   EXPECT_CALL(agent, GetLastPingSentMs())
294       .InSequence(start_pinging)
295       .WillOnce(Return(123));
296   EXPECT_CALL(*wrapped, SelectConnectionToPing(123))
297       .InSequence(start_pinging)
298       .WillOnce(Return(ping_result));
299   EXPECT_CALL(agent, SendPingRequest(kConnection)).InSequence(start_pinging);
300 
301   controller.OnSortAndSwitchRequest(IceSwitchReason::DATA_RECEIVED);
302   clock.AdvanceTime(kTick);
303 
304   // ICE controller should recheck and ping after the recheck delay.
305   // No ping should be sent if no connection selected to ping.
306   EXPECT_CALL(agent, GetLastPingSentMs()).WillOnce(Return(456));
307   EXPECT_CALL(*wrapped, SelectConnectionToPing(456))
308       .WillOnce(Return(IceControllerInterface::PingResult(
309           /* connection= */ nullptr, recheck_delay_ms)));
310   EXPECT_CALL(agent, SendPingRequest(kConnection)).Times(0);
311 
312   clock.AdvanceTime(TimeDelta::Millis(recheck_delay_ms));
313 }
314 
315 }  // namespace
316