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