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