1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file tests the RTCIceTransport Blink bindings, IceTransportProxy and
6 // IceTransportHost by mocking out the underlying IceTransportAdapter.
7 // Everything is run on a single thread but with separate TestSimpleTaskRunners
8 // for the main thread / worker thread.
9
10 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h"
11
12 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
13 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_candidate_init.h"
14 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_gather_options.h"
15 #include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h"
16 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
17 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
18 #include "third_party/webrtc/pc/webrtc_sdp.h"
19
20 namespace blink {
21 namespace {
22
23 using testing::_;
24 using testing::Assign;
25 using testing::AllOf;
26 using testing::DoDefault;
27 using testing::ElementsAre;
28 using testing::Field;
29 using testing::InSequence;
30 using testing::InvokeWithoutArgs;
31 using testing::Mock;
32 using testing::StrEq;
33 using testing::StrNe;
34
35 constexpr char kRemoteUsernameFragment1[] = "user";
36 constexpr char kRemotePassword1[] = "passwordpasswordpassword";
37 constexpr char kRemoteUsernameFragment2[] = "second+user";
38 constexpr char kRemotePassword2[] = "password2password2password2";
39
CreateRemoteRTCIceParameters2()40 RTCIceParameters* CreateRemoteRTCIceParameters2() {
41 RTCIceParameters* ice_parameters = RTCIceParameters::Create();
42 ice_parameters->setUsernameFragment(kRemoteUsernameFragment2);
43 ice_parameters->setPassword(kRemotePassword2);
44 return ice_parameters;
45 }
46
47 constexpr char kLocalIceCandidateStr1[] =
48 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
49 constexpr char kRemoteIceCandidateStr1[] =
50 "candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host generation 2";
51 constexpr char kRemoteIceCandidateStr2[] =
52 "candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx raddr "
53 "192.168.1.5 rport 2346 generation 2";
54
RTCIceCandidateFromString(V8TestingScope & scope,const String & candidate_str)55 RTCIceCandidate* RTCIceCandidateFromString(V8TestingScope& scope,
56 const String& candidate_str) {
57 RTCIceCandidateInit* init = RTCIceCandidateInit::Create();
58 init->setCandidate(candidate_str);
59 init->setSdpMid(String(""));
60 return RTCIceCandidate::Create(scope.GetExecutionContext(), init,
61 ASSERT_NO_EXCEPTION);
62 }
63
CricketCandidateFromString(const std::string & candidate_str)64 cricket::Candidate CricketCandidateFromString(
65 const std::string& candidate_str) {
66 cricket::Candidate candidate;
67 bool success =
68 webrtc::SdpDeserializeCandidate("", candidate_str, &candidate, nullptr);
69 DCHECK(success);
70 return candidate;
71 }
72
73 } // namespace
74
75 // static
CreateRemoteRTCIceParameters1()76 RTCIceParameters* RTCIceTransportTest::CreateRemoteRTCIceParameters1() {
77 RTCIceParameters* ice_parameters = RTCIceParameters::Create();
78 ice_parameters->setUsernameFragment(kRemoteUsernameFragment1);
79 ice_parameters->setPassword(kRemotePassword1);
80 return ice_parameters;
81 }
82
RTCIceTransportTest()83 RTCIceTransportTest::RTCIceTransportTest()
84 : main_thread_(new base::TestSimpleTaskRunner()),
85 worker_thread_(new base::TestSimpleTaskRunner()) {}
86
~RTCIceTransportTest()87 RTCIceTransportTest::~RTCIceTransportTest() {
88 // When the V8TestingScope is destroyed at the end of a test, it will call
89 // ContextDestroyed on the RTCIceTransport which will queue a task to delete
90 // the IceTransportAdapter. RunUntilIdle() here ensures that the task will
91 // be executed and the IceTransportAdapter deleted before finishing the
92 // test.
93 RunUntilIdle();
94
95 // Explicitly verify expectations of garbage collected mock objects.
96 for (auto mock : mock_event_listeners_) {
97 Mock::VerifyAndClear(mock);
98 }
99 }
100
RunUntilIdle()101 void RTCIceTransportTest::RunUntilIdle() {
102 while (worker_thread_->HasPendingTask() || main_thread_->HasPendingTask()) {
103 worker_thread_->RunPendingTasks();
104 main_thread_->RunPendingTasks();
105 }
106 }
107
CreateIceTransport(V8TestingScope & scope)108 RTCIceTransport* RTCIceTransportTest::CreateIceTransport(
109 V8TestingScope& scope) {
110 return CreateIceTransport(scope, std::make_unique<MockIceTransportAdapter>());
111 }
112
CreateIceTransport(V8TestingScope & scope,IceTransportAdapter::Delegate ** delegate_out)113 RTCIceTransport* RTCIceTransportTest::CreateIceTransport(
114 V8TestingScope& scope,
115 IceTransportAdapter::Delegate** delegate_out) {
116 return CreateIceTransport(scope, std::make_unique<MockIceTransportAdapter>(),
117 delegate_out);
118 }
119
CreateIceTransport(V8TestingScope & scope,std::unique_ptr<MockIceTransportAdapter> mock,IceTransportAdapter::Delegate ** delegate_out)120 RTCIceTransport* RTCIceTransportTest::CreateIceTransport(
121 V8TestingScope& scope,
122 std::unique_ptr<MockIceTransportAdapter> mock,
123 IceTransportAdapter::Delegate** delegate_out) {
124 if (delegate_out) {
125 // Ensure the caller has not left the delegate_out value floating.
126 DCHECK_EQ(nullptr, *delegate_out);
127 }
128 return RTCIceTransport::Create(
129 scope.GetExecutionContext(), main_thread_, worker_thread_,
130 std::make_unique<MockIceTransportAdapterCrossThreadFactory>(
131 std::move(mock), delegate_out));
132 }
133
CreateMockEventListener()134 MockEventListener* RTCIceTransportTest::CreateMockEventListener() {
135 MockEventListener* event_listener = MakeGarbageCollected<MockEventListener>();
136 mock_event_listeners_.push_back(event_listener);
137 return event_listener;
138 }
139
140 // Test that calling gather({}) calls StartGathering with non-empty local
141 // parameters.
TEST_F(RTCIceTransportTest,GatherStartsGatheringWithNonEmptyLocalParameters)142 TEST_F(RTCIceTransportTest, GatherStartsGatheringWithNonEmptyLocalParameters) {
143 V8TestingScope scope;
144
145 auto mock = std::make_unique<MockIceTransportAdapter>();
146 auto ice_parameters_not_empty =
147 AllOf(Field(&cricket::IceParameters::ufrag, StrNe("")),
148 Field(&cricket::IceParameters::pwd, StrNe("")));
149 EXPECT_CALL(*mock, StartGathering(ice_parameters_not_empty, _, _, _))
150 .Times(1);
151
152 Persistent<RTCIceTransport> ice_transport =
153 CreateIceTransport(scope, std::move(mock));
154 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
155 options->setGatherPolicy("all");
156 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
157 }
158
159 // Test that calling gather({ gatherPolicy: 'all' }) calls StartGathering with
160 // IceTransportPolicy::kAll.
TEST_F(RTCIceTransportTest,GatherIceTransportPolicyAll)161 TEST_F(RTCIceTransportTest, GatherIceTransportPolicyAll) {
162 V8TestingScope scope;
163
164 auto mock = std::make_unique<MockIceTransportAdapter>();
165 EXPECT_CALL(*mock, StartGathering(_, _, _, IceTransportPolicy::kAll))
166 .Times(1);
167
168 Persistent<RTCIceTransport> ice_transport =
169 CreateIceTransport(scope, std::move(mock));
170 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
171 options->setGatherPolicy("all");
172 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
173 }
174
175 // Test that calling gather({ gatherPolicy: 'relay' }) calls StartGathering with
176 // IceTransportPolicy::kRelay.
TEST_F(RTCIceTransportTest,GatherIceTransportPolicyRelay)177 TEST_F(RTCIceTransportTest, GatherIceTransportPolicyRelay) {
178 V8TestingScope scope;
179
180 auto mock = std::make_unique<MockIceTransportAdapter>();
181 EXPECT_CALL(*mock, StartGathering(_, _, _, IceTransportPolicy::kRelay))
182 .Times(1);
183
184 Persistent<RTCIceTransport> ice_transport =
185 CreateIceTransport(scope, std::move(mock));
186 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
187 options->setGatherPolicy("relay");
188 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
189 }
190
191 // Test that calling stop() deletes the underlying IceTransportAdapter.
TEST_F(RTCIceTransportTest,StopDeletesIceTransportAdapter)192 TEST_F(RTCIceTransportTest, StopDeletesIceTransportAdapter) {
193 V8TestingScope scope;
194
195 bool mock_deleted = false;
196 auto mock = std::make_unique<MockIceTransportAdapter>();
197 EXPECT_CALL(*mock, Die()).WillOnce(Assign(&mock_deleted, true));
198
199 Persistent<RTCIceTransport> ice_transport =
200 CreateIceTransport(scope, std::move(mock));
201 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
202 options->setGatherPolicy("all");
203 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
204
205 ice_transport->stop();
206 RunUntilIdle();
207
208 EXPECT_TRUE(mock_deleted);
209 }
210
211 // Test that the IceTransportAdapter is deleted on ContextDestroyed.
TEST_F(RTCIceTransportTest,ContextDestroyedDeletesIceTransportAdapter)212 TEST_F(RTCIceTransportTest, ContextDestroyedDeletesIceTransportAdapter) {
213 bool mock_deleted = false;
214 {
215 V8TestingScope scope;
216
217 auto mock = std::make_unique<MockIceTransportAdapter>();
218 EXPECT_CALL(*mock, Die()).WillOnce(Assign(&mock_deleted, true));
219
220 Persistent<RTCIceTransport> ice_transport =
221 CreateIceTransport(scope, std::move(mock));
222 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
223 options->setGatherPolicy("all");
224 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
225 } // ContextDestroyed when V8TestingScope goes out of scope.
226
227 RunUntilIdle();
228
229 EXPECT_TRUE(mock_deleted);
230 }
231
232 // Test that calling OnGatheringStateChanged(complete) on the delegate fires a
233 // null icecandidate event and a gatheringstatechange event.
TEST_F(RTCIceTransportTest,OnGatheringStateChangedCompleteFiresEvents)234 TEST_F(RTCIceTransportTest, OnGatheringStateChangedCompleteFiresEvents) {
235 V8TestingScope scope;
236
237 IceTransportAdapter::Delegate* delegate = nullptr;
238 Persistent<RTCIceTransport> ice_transport =
239 CreateIceTransport(scope, &delegate);
240 RTCIceGatherOptions* options = RTCIceGatherOptions::Create();
241 options->setGatherPolicy("all");
242 ice_transport->gather(options, ASSERT_NO_EXCEPTION);
243 RunUntilIdle();
244 ASSERT_TRUE(delegate);
245
246 Persistent<MockEventListener> ice_candidate_listener =
247 CreateMockEventListener();
248 Persistent<MockEventListener> gathering_state_change_listener =
249 CreateMockEventListener();
250 {
251 InSequence dummy;
252 EXPECT_CALL(*ice_candidate_listener, Invoke(_, _))
253 .WillOnce(
254 testing::Invoke([ice_transport](ExecutionContext*, Event* event) {
255 auto* ice_event = static_cast<RTCPeerConnectionIceEvent*>(event);
256 EXPECT_EQ(nullptr, ice_event->candidate());
257 }));
258 EXPECT_CALL(*gathering_state_change_listener, Invoke(_, _))
259 .WillOnce(InvokeWithoutArgs([ice_transport] {
260 EXPECT_EQ("complete", ice_transport->gatheringState());
261 }));
262 }
263 ice_transport->addEventListener(event_type_names::kIcecandidate,
264 ice_candidate_listener);
265 ice_transport->addEventListener(event_type_names::kGatheringstatechange,
266 gathering_state_change_listener);
267 delegate->OnGatheringStateChanged(cricket::kIceGatheringComplete);
268
269 RunUntilIdle();
270 }
271
272 // Test that calling start() calls Start on the IceTransportAdapter with the
273 // correct arguments when no remote candidates had previously been added.
TEST_F(RTCIceTransportTest,StartPassesRemoteParametersAndRoleAndInitialRemoteCandidates)274 TEST_F(RTCIceTransportTest,
275 StartPassesRemoteParametersAndRoleAndInitialRemoteCandidates) {
276 V8TestingScope scope;
277
278 auto mock = std::make_unique<MockIceTransportAdapter>();
279 auto ice_parameters_equal = AllOf(
280 Field(&cricket::IceParameters::ufrag, StrEq(kRemoteUsernameFragment1)),
281 Field(&cricket::IceParameters::pwd, StrEq(kRemotePassword1)));
282 EXPECT_CALL(*mock, Start(ice_parameters_equal, cricket::ICEROLE_CONTROLLING,
283 ElementsAre()))
284 .Times(1);
285
286 Persistent<RTCIceTransport> ice_transport =
287 CreateIceTransport(scope, std::move(mock));
288 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
289 ASSERT_NO_EXCEPTION);
290 }
291
292 MATCHER_P(SerializedIceCandidateEq, candidate_str, "") {
293 std::string arg_str = webrtc::SdpSerializeCandidate(arg);
294 *result_listener << "Expected ICE candidate that serializes to: "
295 << candidate_str << "; got: " << arg_str;
296 return arg_str == candidate_str;
297 }
298
299 // Test that remote candidates are not passed to the IceTransportAdapter until
300 // start() is called.
TEST_F(RTCIceTransportTest,RemoteCandidatesNotPassedUntilStartCalled)301 TEST_F(RTCIceTransportTest, RemoteCandidatesNotPassedUntilStartCalled) {
302 V8TestingScope scope;
303
304 auto mock = std::make_unique<MockIceTransportAdapter>();
305 EXPECT_CALL(
306 *mock,
307 Start(_, _,
308 ElementsAre(SerializedIceCandidateEq(kRemoteIceCandidateStr1))))
309 .Times(1);
310 EXPECT_CALL(*mock, AddRemoteCandidate(_)).Times(0);
311
312 Persistent<RTCIceTransport> ice_transport =
313 CreateIceTransport(scope, std::move(mock));
314 ice_transport->addRemoteCandidate(
315 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
316 ASSERT_NO_EXCEPTION);
317 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
318 ASSERT_NO_EXCEPTION);
319 }
320
321 // Test that receiving an OnStateChanged callback with the connected state
322 // updates the RTCIceTransport state to 'connected' and fires a statechange
323 // event.
TEST_F(RTCIceTransportTest,OnStateChangedConnectedUpdatesStateAndFiresEvent)324 TEST_F(RTCIceTransportTest, OnStateChangedConnectedUpdatesStateAndFiresEvent) {
325 V8TestingScope scope;
326
327 IceTransportAdapter::Delegate* delegate = nullptr;
328 Persistent<RTCIceTransport> ice_transport =
329 CreateIceTransport(scope, &delegate);
330 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
331 ASSERT_NO_EXCEPTION);
332 RunUntilIdle();
333 ASSERT_TRUE(delegate);
334
335 Persistent<MockEventListener> event_listener = CreateMockEventListener();
336 EXPECT_CALL(*event_listener, Invoke(_, _))
337 .WillOnce(InvokeWithoutArgs(
338 [ice_transport] { EXPECT_EQ("connected", ice_transport->state()); }));
339 ice_transport->addEventListener(event_type_names::kStatechange,
340 event_listener);
341
342 ice_transport->addRemoteCandidate(
343 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
344 ASSERT_NO_EXCEPTION);
345 delegate->OnCandidateGathered(
346 CricketCandidateFromString(kLocalIceCandidateStr1));
347
348 delegate->OnStateChanged(webrtc::IceTransportState::kConnected);
349
350 RunUntilIdle();
351 }
352
353 // Test that receiving an OnStateChanged callback with the completed state
354 // updates the RTCIceTransport state to 'completed' and fires a statechange
355 // event.
TEST_F(RTCIceTransportTest,OnStateChangedCompletedUpdatesStateAndFiresEvent)356 TEST_F(RTCIceTransportTest, OnStateChangedCompletedUpdatesStateAndFiresEvent) {
357 V8TestingScope scope;
358
359 IceTransportAdapter::Delegate* delegate = nullptr;
360 Persistent<RTCIceTransport> ice_transport =
361 CreateIceTransport(scope, &delegate);
362 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
363 ASSERT_NO_EXCEPTION);
364 RunUntilIdle();
365 ASSERT_TRUE(delegate);
366
367 Persistent<MockEventListener> event_listener = CreateMockEventListener();
368 EXPECT_CALL(*event_listener, Invoke(_, _))
369 .WillOnce(InvokeWithoutArgs(
370 [ice_transport] { EXPECT_EQ("completed", ice_transport->state()); }));
371 ice_transport->addEventListener(event_type_names::kStatechange,
372 event_listener);
373
374 ice_transport->addRemoteCandidate(
375 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
376 ASSERT_NO_EXCEPTION);
377 delegate->OnCandidateGathered(
378 CricketCandidateFromString(kLocalIceCandidateStr1));
379
380 delegate->OnStateChanged(webrtc::IceTransportState::kCompleted);
381
382 RunUntilIdle();
383 }
384
385 // Test that receiving an OnStateChanged callback with the disconnected state
386 // updates the RTCIceTransport state to 'disconnected' and fires a statechange
387 // event.
TEST_F(RTCIceTransportTest,OnStateChangedDisconnectedUpdatesStateAndFiresEvent)388 TEST_F(RTCIceTransportTest,
389 OnStateChangedDisconnectedUpdatesStateAndFiresEvent) {
390 V8TestingScope scope;
391
392 IceTransportAdapter::Delegate* delegate = nullptr;
393 Persistent<RTCIceTransport> ice_transport =
394 CreateIceTransport(scope, &delegate);
395 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
396 ASSERT_NO_EXCEPTION);
397 RunUntilIdle();
398 ASSERT_TRUE(delegate);
399
400 Persistent<MockEventListener> event_listener = CreateMockEventListener();
401 EXPECT_CALL(*event_listener, Invoke(_, _))
402 .WillOnce(InvokeWithoutArgs([ice_transport] {
403 EXPECT_EQ("disconnected", ice_transport->state());
404 }));
405 ice_transport->addEventListener(event_type_names::kStatechange,
406 event_listener);
407
408 ice_transport->addRemoteCandidate(
409 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
410 ASSERT_NO_EXCEPTION);
411 delegate->OnCandidateGathered(
412 CricketCandidateFromString(kLocalIceCandidateStr1));
413
414 delegate->OnStateChanged(webrtc::IceTransportState::kDisconnected);
415
416 RunUntilIdle();
417 }
418 // Test that receiving an OnStateChanged callback with the failed state updates
419 // the RTCIceTransport state to 'failed' and fires a statechange event.
TEST_F(RTCIceTransportTest,OnStateChangedFailedUpdatesStateAndFiresEvent)420 TEST_F(RTCIceTransportTest, OnStateChangedFailedUpdatesStateAndFiresEvent) {
421 V8TestingScope scope;
422
423 IceTransportAdapter::Delegate* delegate = nullptr;
424 Persistent<RTCIceTransport> ice_transport =
425 CreateIceTransport(scope, &delegate);
426 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
427 ASSERT_NO_EXCEPTION);
428 RunUntilIdle();
429 ASSERT_TRUE(delegate);
430
431 Persistent<MockEventListener> event_listener = CreateMockEventListener();
432 // Due to the quick fix for crbug.com/957487 (should go to "disconnected"
433 // state when end-of-candidates is signalled), this is accepting
434 // that the end state is 'disconnected' rather than 'failed'.
435 EXPECT_CALL(*event_listener, Invoke(_, _))
436 .WillOnce(InvokeWithoutArgs([ice_transport] {
437 EXPECT_EQ("disconnected", ice_transport->state());
438 }));
439 ice_transport->addEventListener(event_type_names::kStatechange,
440 event_listener);
441
442 ice_transport->addRemoteCandidate(
443 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
444 ASSERT_NO_EXCEPTION);
445 delegate->OnCandidateGathered(
446 CricketCandidateFromString(kLocalIceCandidateStr1));
447
448 delegate->OnStateChanged(webrtc::IceTransportState::kFailed);
449
450 RunUntilIdle();
451 }
452
453 // Test that calling OnSelectedCandidatePairChanged the first time fires the
454 // selectedcandidatepairchange event and sets the selected candidate pair.
TEST_F(RTCIceTransportTest,InitialOnSelectedCandidatePairChangedFiresEvent)455 TEST_F(RTCIceTransportTest, InitialOnSelectedCandidatePairChangedFiresEvent) {
456 V8TestingScope scope;
457
458 IceTransportAdapter::Delegate* delegate = nullptr;
459 Persistent<RTCIceTransport> ice_transport =
460 CreateIceTransport(scope, &delegate);
461 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
462 ASSERT_NO_EXCEPTION);
463 RunUntilIdle();
464 ASSERT_TRUE(delegate);
465
466 Persistent<MockEventListener> event_listener = CreateMockEventListener();
467 EXPECT_CALL(*event_listener, Invoke(_, _))
468 .WillOnce(InvokeWithoutArgs([ice_transport] {
469 RTCIceCandidatePair* selected_candidate_pair =
470 ice_transport->getSelectedCandidatePair();
471 ASSERT_TRUE(selected_candidate_pair);
472 EXPECT_EQ(ice_transport->getLocalCandidates()[0]->candidate(),
473 selected_candidate_pair->local()->candidate());
474 EXPECT_EQ(ice_transport->getRemoteCandidates()[0]->candidate(),
475 selected_candidate_pair->remote()->candidate());
476 }));
477 ice_transport->addEventListener(
478 event_type_names::kSelectedcandidatepairchange, event_listener);
479
480 ice_transport->addRemoteCandidate(
481 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
482 ASSERT_NO_EXCEPTION);
483 delegate->OnCandidateGathered(
484 CricketCandidateFromString(kLocalIceCandidateStr1));
485 delegate->OnSelectedCandidatePairChanged(
486 std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1),
487 CricketCandidateFromString(kRemoteIceCandidateStr1)));
488
489 RunUntilIdle();
490 }
491
492 // Test that calling OnSelectedCandidatePairChanged with a different remote
493 // candidate fires the event and updates the selected candidate pair.
TEST_F(RTCIceTransportTest,OnSelectedCandidatePairChangedWithDifferentRemoteCandidateFiresEvent)494 TEST_F(RTCIceTransportTest,
495 OnSelectedCandidatePairChangedWithDifferentRemoteCandidateFiresEvent) {
496 V8TestingScope scope;
497
498 IceTransportAdapter::Delegate* delegate = nullptr;
499 Persistent<RTCIceTransport> ice_transport =
500 CreateIceTransport(scope, &delegate);
501 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
502 ASSERT_NO_EXCEPTION);
503 RunUntilIdle();
504 ASSERT_TRUE(delegate);
505
506 Persistent<MockEventListener> event_listener = CreateMockEventListener();
507 EXPECT_CALL(*event_listener, Invoke(_, _))
508 .WillOnce(DoDefault()) // First event is already tested above.
509 .WillOnce(InvokeWithoutArgs([ice_transport] {
510 RTCIceCandidatePair* selected_candidate_pair =
511 ice_transport->getSelectedCandidatePair();
512 ASSERT_TRUE(selected_candidate_pair);
513 EXPECT_EQ(ice_transport->getLocalCandidates()[0]->candidate(),
514 selected_candidate_pair->local()->candidate());
515 EXPECT_EQ(ice_transport->getRemoteCandidates()[1]->candidate(),
516 selected_candidate_pair->remote()->candidate());
517 }));
518 ice_transport->addEventListener(
519 event_type_names::kSelectedcandidatepairchange, event_listener);
520
521 ice_transport->addRemoteCandidate(
522 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
523 ASSERT_NO_EXCEPTION);
524 delegate->OnCandidateGathered(
525 CricketCandidateFromString(kLocalIceCandidateStr1));
526
527 delegate->OnSelectedCandidatePairChanged(
528 std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1),
529 CricketCandidateFromString(kRemoteIceCandidateStr1)));
530
531 ice_transport->addRemoteCandidate(
532 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr2),
533 ASSERT_NO_EXCEPTION);
534 delegate->OnSelectedCandidatePairChanged(
535 std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1),
536 CricketCandidateFromString(kRemoteIceCandidateStr2)));
537
538 RunUntilIdle();
539 }
540
541 // Test that receiving an OnStateChange callback to the failed state once a
542 // connection has been established clears the selected candidate pair without
543 // firing the selectedcandidatepairchange event.
544 // Disabled while sorting out the use of "failed" vs "disconnected"
545 // (crbug.com/957847).
TEST_F(RTCIceTransportTest,DISABLED_OnStateChangeFailedAfterConnectedClearsSelectedCandidatePair)546 TEST_F(RTCIceTransportTest,
547 DISABLED_OnStateChangeFailedAfterConnectedClearsSelectedCandidatePair) {
548 V8TestingScope scope;
549
550 IceTransportAdapter::Delegate* delegate = nullptr;
551 Persistent<RTCIceTransport> ice_transport =
552 CreateIceTransport(scope, &delegate);
553 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
554 ASSERT_NO_EXCEPTION);
555 RunUntilIdle();
556 ASSERT_TRUE(delegate);
557
558 Persistent<MockEventListener> state_change_event_listener =
559 CreateMockEventListener();
560 EXPECT_CALL(*state_change_event_listener, Invoke(_, _))
561 .WillOnce(DoDefault()) // First event is for 'connected'.
562 .WillOnce(InvokeWithoutArgs([ice_transport] {
563 EXPECT_EQ("failed", ice_transport->state());
564 RTCIceCandidatePair* selected_candidate_pair =
565 ice_transport->getSelectedCandidatePair();
566 EXPECT_EQ(nullptr, selected_candidate_pair);
567 }));
568 ice_transport->addEventListener(event_type_names::kStatechange,
569 state_change_event_listener);
570
571 Persistent<MockEventListener> selected_candidate_pair_change_event_listener =
572 CreateMockEventListener();
573 EXPECT_CALL(*selected_candidate_pair_change_event_listener, Invoke(_, _))
574 .Times(1); // First event is for the connected pair.
575 ice_transport->addEventListener(
576 event_type_names::kSelectedcandidatepairchange,
577 selected_candidate_pair_change_event_listener);
578
579 // Establish the connection
580 ice_transport->addRemoteCandidate(
581 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
582 ASSERT_NO_EXCEPTION);
583 delegate->OnCandidateGathered(
584 CricketCandidateFromString(kLocalIceCandidateStr1));
585 delegate->OnStateChanged(webrtc::IceTransportState::kConnected);
586 delegate->OnSelectedCandidatePairChanged(
587 std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1),
588 CricketCandidateFromString(kRemoteIceCandidateStr1)));
589
590 // Transition to failed.
591 delegate->OnStateChanged(webrtc::IceTransportState::kFailed);
592
593 RunUntilIdle();
594 }
595
596 // Test that receiving an OnSelectedCandidatePairChange callback after a remote
597 // ICE restart still updates the selected candidate pair.
TEST_F(RTCIceTransportTest,RemoteIceRestartRaceWithSelectedCandidatePairChange)598 TEST_F(RTCIceTransportTest,
599 RemoteIceRestartRaceWithSelectedCandidatePairChange) {
600 V8TestingScope scope;
601
602 IceTransportAdapter::Delegate* delegate = nullptr;
603 Persistent<RTCIceTransport> ice_transport =
604 CreateIceTransport(scope, &delegate);
605 ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
606 ASSERT_NO_EXCEPTION);
607 RunUntilIdle();
608 ASSERT_TRUE(delegate);
609
610 Persistent<MockEventListener> event_listener = CreateMockEventListener();
611 EXPECT_CALL(*event_listener, Invoke(_, _))
612 .WillOnce(InvokeWithoutArgs([ice_transport] {
613 RTCIceCandidatePair* selected_candidate_pair =
614 ice_transport->getSelectedCandidatePair();
615 ASSERT_TRUE(selected_candidate_pair);
616 EXPECT_EQ(kLocalIceCandidateStr1,
617 selected_candidate_pair->local()->candidate());
618 EXPECT_EQ(kRemoteIceCandidateStr1,
619 selected_candidate_pair->remote()->candidate());
620 }));
621 ice_transport->addEventListener(
622 event_type_names::kSelectedcandidatepairchange, event_listener);
623
624 ice_transport->addRemoteCandidate(
625 RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1),
626 ASSERT_NO_EXCEPTION);
627
628 // Changing remote ICE parameters indicate a remote ICE restart. This clears
629 // the stored list of remote candidates.
630 ice_transport->start(CreateRemoteRTCIceParameters2(), "controlling",
631 ASSERT_NO_EXCEPTION);
632
633 // These callbacks are part of the previous generation but should still take
634 // effect.
635 delegate->OnCandidateGathered(
636 CricketCandidateFromString(kLocalIceCandidateStr1));
637 delegate->OnStateChanged(webrtc::IceTransportState::kConnected);
638 delegate->OnSelectedCandidatePairChanged(
639 std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1),
640 CricketCandidateFromString(kRemoteIceCandidateStr1)));
641
642 RunUntilIdle();
643 }
644
645 } // namespace blink
646