blob: d36b8f3ce17157d7854b8d93ee9437b6f39c5fc7 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 23:26:271/*
2 * Copyright 2018 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 <map>
12#include <memory>
13
Anton Sukhanov7940da02018-10-10 17:34:4914#include "api/test/fake_media_transport.h"
Zhi Huange818b6e2018-02-22 23:26:2715#include "p2p/base/fakedtlstransport.h"
16#include "p2p/base/fakeicetransport.h"
17#include "p2p/base/transportfactoryinterface.h"
18#include "p2p/base/transportinfo.h"
19#include "pc/jseptransportcontroller.h"
20#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 23:26:2721#include "rtc_base/thread.h"
22#include "test/gtest.h"
23
24using cricket::FakeDtlsTransport;
25using cricket::Candidate;
26using cricket::Candidates;
27using webrtc::SdpType;
28
29static const int kTimeout = 100;
30static const char kIceUfrag1[] = "u0001";
31static const char kIcePwd1[] = "TESTICEPWD00000000000001";
32static const char kIceUfrag2[] = "u0002";
33static const char kIcePwd2[] = "TESTICEPWD00000000000002";
34static const char kIceUfrag3[] = "u0003";
35static const char kIcePwd3[] = "TESTICEPWD00000000000003";
36static const char kAudioMid1[] = "audio1";
37static const char kAudioMid2[] = "audio2";
38static const char kVideoMid1[] = "video1";
39static const char kVideoMid2[] = "video2";
40static const char kDataMid1[] = "data1";
41
42namespace webrtc {
43
44class FakeTransportFactory : public cricket::TransportFactoryInterface {
45 public:
46 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
47 const std::string& transport_name,
48 int component) override {
Karl Wiberg918f50c2018-07-05 09:40:3349 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
50 component);
Zhi Huange818b6e2018-02-22 23:26:2751 }
52
53 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
54 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 22:33:1755 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 23:26:2756 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
57 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 09:40:3358 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 23:26:2759 }
60};
61
Zhi Huang365381f2018-04-13 23:44:3462class JsepTransportControllerTest : public JsepTransportController::Observer,
63 public testing::Test,
Zhi Huange818b6e2018-02-22 23:26:2764 public sigslot::has_slots<> {
65 public:
66 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 09:40:3367 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 23:26:2768 }
69
70 void CreateJsepTransportController(
71 JsepTransportController::Config config,
72 rtc::Thread* signaling_thread = rtc::Thread::Current(),
73 rtc::Thread* network_thread = rtc::Thread::Current(),
74 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 23:44:3475 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 23:26:2776 // The tests only works with |fake_transport_factory|;
77 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 20:20:1578 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 09:40:3379 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 20:20:1580 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 23:26:2781 ConnectTransportControllerSignals();
82 }
83
84 void ConnectTransportControllerSignals() {
85 transport_controller_->SignalIceConnectionState.connect(
86 this, &JsepTransportControllerTest::OnConnectionState);
87 transport_controller_->SignalIceGatheringState.connect(
88 this, &JsepTransportControllerTest::OnGatheringState);
89 transport_controller_->SignalIceCandidatesGathered.connect(
90 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 23:26:2791 }
92
93 std::unique_ptr<cricket::SessionDescription>
94 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 09:40:3395 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:2796 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
97 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
98 nullptr);
99 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
100 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
101 nullptr);
102 return description;
103 }
104
105 std::unique_ptr<cricket::SessionDescription>
106 CreateSessionDescriptionWithBundleGroup() {
107 auto description = CreateSessionDescriptionWithoutBundle();
108 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
109 bundle_group.AddContentName(kAudioMid1);
110 bundle_group.AddContentName(kVideoMid1);
111 description->AddGroup(bundle_group);
112
113 return description;
114 }
115
116 void AddAudioSection(cricket::SessionDescription* description,
117 const std::string& mid,
118 const std::string& ufrag,
119 const std::string& pwd,
120 cricket::IceMode ice_mode,
121 cricket::ConnectionRole conn_role,
122 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
123 std::unique_ptr<cricket::AudioContentDescription> audio(
124 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 17:48:35125 // Set RTCP-mux to be true because the default policy is "mux required".
126 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27127 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
128 /*rejected=*/false, audio.release());
129 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
130 }
131
132 void AddVideoSection(cricket::SessionDescription* description,
133 const std::string& mid,
134 const std::string& ufrag,
135 const std::string& pwd,
136 cricket::IceMode ice_mode,
137 cricket::ConnectionRole conn_role,
138 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
139 std::unique_ptr<cricket::VideoContentDescription> video(
140 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 17:48:35141 // Set RTCP-mux to be true because the default policy is "mux required".
142 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27143 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
144 /*rejected=*/false, video.release());
145 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
146 }
147
148 void AddDataSection(cricket::SessionDescription* description,
149 const std::string& mid,
150 cricket::MediaProtocolType protocol_type,
151 const std::string& ufrag,
152 const std::string& pwd,
153 cricket::IceMode ice_mode,
154 cricket::ConnectionRole conn_role,
155 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
156 std::unique_ptr<cricket::DataContentDescription> data(
157 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 17:48:35158 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27159 description->AddContent(mid, protocol_type,
160 /*rejected=*/false, data.release());
161 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
162 }
163
164 void AddTransportInfo(cricket::SessionDescription* description,
165 const std::string& mid,
166 const std::string& ufrag,
167 const std::string& pwd,
168 cricket::IceMode ice_mode,
169 cricket::ConnectionRole conn_role,
170 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
171 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
172 if (cert) {
Steve Anton4905edb2018-10-16 02:27:44173 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 23:26:27174 }
175
176 cricket::TransportDescription transport_desc(std::vector<std::string>(),
177 ufrag, pwd, ice_mode,
178 conn_role, fingerprint.get());
179 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
180 }
181
182 cricket::IceConfig CreateIceConfig(
183 int receiving_timeout,
184 cricket::ContinualGatheringPolicy continual_gathering_policy) {
185 cricket::IceConfig config;
186 config.receiving_timeout = receiving_timeout;
187 config.continual_gathering_policy = continual_gathering_policy;
188 return config;
189 }
190
191 Candidate CreateCandidate(const std::string& transport_name, int component) {
192 Candidate c;
193 c.set_transport_name(transport_name);
194 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
195 c.set_component(component);
196 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
197 c.set_priority(1);
198 return c;
199 }
200
201 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
202 if (!network_thread_->IsCurrent()) {
203 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
204 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
205 });
206 return;
207 }
208
209 auto description = CreateSessionDescriptionWithBundleGroup();
210 EXPECT_TRUE(transport_controller_
211 ->SetLocalDescription(SdpType::kOffer, description.get())
212 .ok());
213
214 transport_controller_->MaybeStartGathering();
215 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
216 transport_controller_->GetDtlsTransport(kAudioMid1));
217 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
218 transport_controller_->GetDtlsTransport(kVideoMid1));
219 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
220 fake_audio_dtls->fake_ice_transport(),
221 CreateCandidate(kAudioMid1, /*component=*/1));
222 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
223 fake_video_dtls->fake_ice_transport(),
224 CreateCandidate(kVideoMid1, /*component=*/1));
225 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
226 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
227 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
228 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
229 fake_audio_dtls->SetReceiving(true);
230 fake_video_dtls->SetReceiving(true);
231 fake_audio_dtls->SetWritable(true);
232 fake_video_dtls->SetWritable(true);
233 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
234 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
235 }
236
237 protected:
238 void OnConnectionState(cricket::IceConnectionState state) {
239 if (!signaling_thread_->IsCurrent()) {
240 signaled_on_non_signaling_thread_ = true;
241 }
242 connection_state_ = state;
243 ++connection_state_signal_count_;
244 }
245
246 void OnGatheringState(cricket::IceGatheringState state) {
247 if (!signaling_thread_->IsCurrent()) {
248 signaled_on_non_signaling_thread_ = true;
249 }
250 gathering_state_ = state;
251 ++gathering_state_signal_count_;
252 }
253
254 void OnCandidatesGathered(const std::string& transport_name,
255 const Candidates& candidates) {
256 if (!signaling_thread_->IsCurrent()) {
257 signaled_on_non_signaling_thread_ = true;
258 }
259 candidates_[transport_name].insert(candidates_[transport_name].end(),
260 candidates.begin(), candidates.end());
261 ++candidates_signal_count_;
262 }
263
Zhi Huang365381f2018-04-13 23:44:34264 // JsepTransportController::Observer overrides.
Taylor Brandstettercbaa2542018-04-16 23:42:14265 bool OnTransportChanged(
Zhi Huang365381f2018-04-13 23:44:34266 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 23:42:14267 RtpTransportInternal* rtp_transport,
Zhi Huang365381f2018-04-13 23:44:34268 cricket::DtlsTransportInternal* dtls_transport) override {
Taylor Brandstettercbaa2542018-04-16 23:42:14269 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 23:26:27270 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Taylor Brandstettercbaa2542018-04-16 23:42:14271 return true;
Zhi Huange818b6e2018-02-22 23:26:27272 }
273
274 // Information received from signals from transport controller.
275 cricket::IceConnectionState connection_state_ =
276 cricket::kIceConnectionConnecting;
277 bool receiving_ = false;
278 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
279 // transport_name => candidates
280 std::map<std::string, Candidates> candidates_;
281 // Counts of each signal emitted.
282 int connection_state_signal_count_ = 0;
283 int receiving_signal_count_ = 0;
284 int gathering_state_signal_count_ = 0;
285 int candidates_signal_count_ = 0;
286
287 // |network_thread_| should be destroyed after |transport_controller_|
288 std::unique_ptr<rtc::Thread> network_thread_;
289 std::unique_ptr<JsepTransportController> transport_controller_;
290 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
291 rtc::Thread* const signaling_thread_ = nullptr;
292 bool signaled_on_non_signaling_thread_ = false;
293 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
294 // signaled correctly.
295 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
296 std::map<std::string, cricket::DtlsTransportInternal*>
297 changed_dtls_transport_by_mid_;
298};
299
300TEST_F(JsepTransportControllerTest, GetRtpTransport) {
301 CreateJsepTransportController(JsepTransportController::Config());
302 auto description = CreateSessionDescriptionWithoutBundle();
303 EXPECT_TRUE(transport_controller_
304 ->SetLocalDescription(SdpType::kOffer, description.get())
305 .ok());
306 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
307 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
308 EXPECT_NE(nullptr, audio_rtp_transport);
309 EXPECT_NE(nullptr, video_rtp_transport);
310 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
311 // Return nullptr for non-existing ones.
312 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
313}
314
315TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
316 JsepTransportController::Config config;
317 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
318 CreateJsepTransportController(config);
319 auto description = CreateSessionDescriptionWithoutBundle();
320 EXPECT_TRUE(transport_controller_
321 ->SetLocalDescription(SdpType::kOffer, description.get())
322 .ok());
323 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
324 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
325 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
326 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
327 // Return nullptr for non-existing ones.
328 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
329 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
330}
331
Zhi Huange830e682018-03-30 17:48:35332TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
333 JsepTransportController::Config config;
334 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
335 CreateJsepTransportController(config);
336 auto description = CreateSessionDescriptionWithoutBundle();
337 EXPECT_TRUE(transport_controller_
338 ->SetLocalDescription(SdpType::kOffer, description.get())
339 .ok());
340 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
341 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
342 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
343 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 17:34:49344 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
345}
346
347TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
348 FakeMediaTransportFactory fake_media_transport_factory;
349 JsepTransportController::Config config;
350
351 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
352 config.media_transport_factory = &fake_media_transport_factory;
353 CreateJsepTransportController(config);
354 auto description = CreateSessionDescriptionWithoutBundle();
355 EXPECT_TRUE(transport_controller_
356 ->SetLocalDescription(SdpType::kOffer, description.get())
357 .ok());
358
359 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
360 transport_controller_->GetMediaTransport(kAudioMid1));
361
362 ASSERT_NE(nullptr, media_transport);
363
364 // After SetLocalDescription, media transport should be created as caller.
365 EXPECT_TRUE(media_transport->is_caller());
366
367 // Return nullptr for non-existing mids.
368 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
369}
370
371TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
372 FakeMediaTransportFactory fake_media_transport_factory;
373 JsepTransportController::Config config;
374
375 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
376 config.media_transport_factory = &fake_media_transport_factory;
377 CreateJsepTransportController(config);
378 auto description = CreateSessionDescriptionWithoutBundle();
379 EXPECT_TRUE(transport_controller_
380 ->SetRemoteDescription(SdpType::kOffer, description.get())
381 .ok());
382
383 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
384 transport_controller_->GetMediaTransport(kAudioMid1));
385
386 ASSERT_NE(nullptr, media_transport);
387
388 // After SetRemoteDescription, media transport should be created as callee.
389 EXPECT_FALSE(media_transport->is_caller());
390
391 // Return nullptr for non-existing mids.
392 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 17:48:35393}
394
Zhi Huange818b6e2018-02-22 23:26:27395TEST_F(JsepTransportControllerTest, SetIceConfig) {
396 CreateJsepTransportController(JsepTransportController::Config());
397 auto description = CreateSessionDescriptionWithoutBundle();
398 EXPECT_TRUE(transport_controller_
399 ->SetLocalDescription(SdpType::kOffer, description.get())
400 .ok());
401
402 transport_controller_->SetIceConfig(
403 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
404 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
405 transport_controller_->GetDtlsTransport(kAudioMid1));
406 ASSERT_NE(nullptr, fake_audio_dtls);
407 EXPECT_EQ(kTimeout,
408 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
409 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
410
411 // Test that value stored in controller is applied to new transports.
412 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
413 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
414 nullptr);
415
416 EXPECT_TRUE(transport_controller_
417 ->SetLocalDescription(SdpType::kOffer, description.get())
418 .ok());
419 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
420 transport_controller_->GetDtlsTransport(kAudioMid2));
421 ASSERT_NE(nullptr, fake_audio_dtls);
422 EXPECT_EQ(kTimeout,
423 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
424 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
425}
426
427// Tests the getter and setter of the ICE restart flag.
428TEST_F(JsepTransportControllerTest, NeedIceRestart) {
429 CreateJsepTransportController(JsepTransportController::Config());
430 auto description = CreateSessionDescriptionWithoutBundle();
431 EXPECT_TRUE(transport_controller_
432 ->SetLocalDescription(SdpType::kOffer, description.get())
433 .ok());
434 EXPECT_TRUE(transport_controller_
435 ->SetRemoteDescription(SdpType::kAnswer, description.get())
436 .ok());
437
438 // Initially NeedsIceRestart should return false.
439 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
440 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
441 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
442 // true.
443 transport_controller_->SetNeedsIceRestartFlag();
444 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
445 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
446 // For a nonexistent transport, false should be returned.
447 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
448
449 // Reset the ice_ufrag/ice_pwd for audio.
450 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
451 audio_transport_info->description.ice_ufrag = kIceUfrag2;
452 audio_transport_info->description.ice_pwd = kIcePwd2;
453 EXPECT_TRUE(transport_controller_
454 ->SetLocalDescription(SdpType::kOffer, description.get())
455 .ok());
456 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
457 // return false for audio and true for video.
458 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
459 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
460}
461
462TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
463 CreateJsepTransportController(JsepTransportController::Config());
464 auto description = CreateSessionDescriptionWithBundleGroup();
465 EXPECT_TRUE(transport_controller_
466 ->SetLocalDescription(SdpType::kOffer, description.get())
467 .ok());
468 // After setting the local description, we should be able to start gathering
469 // candidates.
470 transport_controller_->MaybeStartGathering();
471 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
472 EXPECT_EQ(1, gathering_state_signal_count_);
473}
474
475TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
476 CreateJsepTransportController(JsepTransportController::Config());
477 auto description = CreateSessionDescriptionWithoutBundle();
478 transport_controller_->SetLocalDescription(SdpType::kOffer,
479 description.get());
480 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
481 description.get());
482 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
483 transport_controller_->GetDtlsTransport(kAudioMid1));
484 ASSERT_NE(nullptr, fake_audio_dtls);
485 Candidates candidates;
486 candidates.push_back(
487 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
488 EXPECT_TRUE(
489 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
490 EXPECT_EQ(1U,
491 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
492
493 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
494 EXPECT_EQ(0U,
495 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
496}
497
498TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
499 CreateJsepTransportController(JsepTransportController::Config());
500
501 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
502 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
503 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
504 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
505
Karl Wiberg918f50c2018-07-05 09:40:33506 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27507 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
508 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
509 certificate1);
510
511 // Apply the local certificate.
512 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
513 // Apply the local description.
514 EXPECT_TRUE(transport_controller_
515 ->SetLocalDescription(SdpType::kOffer, description.get())
516 .ok());
517 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
518 EXPECT_TRUE(returned_certificate);
519 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
520 returned_certificate->identity()->certificate().ToPEMString());
521
522 // Should fail if called for a nonexistant transport.
523 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
524
525 // Shouldn't be able to change the identity once set.
526 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
527 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
528 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
529 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
530}
531
Taylor Brandstetterc3928662018-02-23 21:04:51532TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 23:26:27533 CreateJsepTransportController(JsepTransportController::Config());
534 auto description = CreateSessionDescriptionWithBundleGroup();
535 EXPECT_TRUE(transport_controller_
536 ->SetLocalDescription(SdpType::kOffer, description.get())
537 .ok());
538 rtc::FakeSSLCertificate fake_certificate("fake_data");
539
540 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
541 transport_controller_->GetDtlsTransport(kAudioMid1));
542 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 21:04:51543 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
544 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
545 ASSERT_TRUE(returned_cert_chain);
546 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 23:26:27547 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 21:04:51548 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 23:26:27549
550 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 21:04:51551 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 23:26:27552}
553
554TEST_F(JsepTransportControllerTest, GetDtlsRole) {
555 CreateJsepTransportController(JsepTransportController::Config());
556 auto offer_certificate =
557 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
558 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
559 auto answer_certificate =
560 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
561 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
562 transport_controller_->SetLocalCertificate(offer_certificate);
563
Karl Wiberg918f50c2018-07-05 09:40:33564 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27565 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
566 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
567 offer_certificate);
Karl Wiberg918f50c2018-07-05 09:40:33568 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27569 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
570 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
571 answer_certificate);
572
573 EXPECT_TRUE(transport_controller_
574 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
575 .ok());
576
Danil Chapovalov66cadcc2018-06-19 14:47:43577 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 23:26:27578 transport_controller_->GetDtlsRole(kAudioMid1);
579 // The DTLS role is not decided yet.
580 EXPECT_FALSE(role);
581 EXPECT_TRUE(transport_controller_
582 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
583 .ok());
584 role = transport_controller_->GetDtlsRole(kAudioMid1);
585
586 ASSERT_TRUE(role);
587 EXPECT_EQ(rtc::SSL_CLIENT, *role);
588}
589
590TEST_F(JsepTransportControllerTest, GetStats) {
591 CreateJsepTransportController(JsepTransportController::Config());
592 auto description = CreateSessionDescriptionWithBundleGroup();
593 EXPECT_TRUE(transport_controller_
594 ->SetLocalDescription(SdpType::kOffer, description.get())
595 .ok());
596
597 cricket::TransportStats stats;
598 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
599 EXPECT_EQ(kAudioMid1, stats.transport_name);
600 EXPECT_EQ(1u, stats.channel_stats.size());
601 // Return false for non-existing transport.
602 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
603}
604
605TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
606 CreateJsepTransportController(JsepTransportController::Config());
607 auto description = CreateSessionDescriptionWithoutBundle();
608 EXPECT_TRUE(transport_controller_
609 ->SetLocalDescription(SdpType::kOffer, description.get())
610 .ok());
611
612 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
613 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
614 fake_ice->SetCandidatesGatheringComplete();
615 fake_ice->SetConnectionCount(1);
616 // The connection stats will be failed if there is no active connection.
617 fake_ice->SetConnectionCount(0);
618 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
619 EXPECT_EQ(1, connection_state_signal_count_);
620}
621
622TEST_F(JsepTransportControllerTest, SignalConnectionStateConnected) {
623 CreateJsepTransportController(JsepTransportController::Config());
624 auto description = CreateSessionDescriptionWithoutBundle();
625 EXPECT_TRUE(transport_controller_
626 ->SetLocalDescription(SdpType::kOffer, description.get())
627 .ok());
628
629 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
630 transport_controller_->GetDtlsTransport(kAudioMid1));
631 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
632 transport_controller_->GetDtlsTransport(kVideoMid1));
633
634 // First, have one transport connect, and another fail, to ensure that
635 // the first transport connecting didn't trigger a "connected" state signal.
636 // We should only get a signal when all are connected.
637 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
638 fake_audio_dtls->SetWritable(true);
639 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
640 // Decrease the number of the connection to trigger the signal.
641 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
642 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
643 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
644
645 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
646 EXPECT_EQ(1, connection_state_signal_count_);
647
648 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
649 // the transport state to be STATE_CONNECTING.
650 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
651 fake_video_dtls->SetWritable(true);
652 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
653 EXPECT_EQ(2, connection_state_signal_count_);
654}
655
656TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
657 CreateJsepTransportController(JsepTransportController::Config());
658 auto description = CreateSessionDescriptionWithoutBundle();
659 EXPECT_TRUE(transport_controller_
660 ->SetLocalDescription(SdpType::kOffer, description.get())
661 .ok());
662
663 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
664 transport_controller_->GetDtlsTransport(kAudioMid1));
665 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
666 transport_controller_->GetDtlsTransport(kVideoMid1));
667
668 // First, have one transport connect, and another fail, to ensure that
669 // the first transport connecting didn't trigger a "connected" state signal.
670 // We should only get a signal when all are connected.
671 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
672 fake_audio_dtls->SetWritable(true);
673 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
674 // Decrease the number of the connection to trigger the signal.
675 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
676 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
677 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
678
679 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
680 EXPECT_EQ(1, connection_state_signal_count_);
681
682 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
683 // the transport state to be STATE_COMPLETED.
684 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
685 fake_video_dtls->SetWritable(true);
686 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
687 EXPECT_EQ(2, connection_state_signal_count_);
688}
689
690TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
691 CreateJsepTransportController(JsepTransportController::Config());
692 auto description = CreateSessionDescriptionWithoutBundle();
693 EXPECT_TRUE(transport_controller_
694 ->SetLocalDescription(SdpType::kOffer, description.get())
695 .ok());
696
697 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
698 transport_controller_->GetDtlsTransport(kAudioMid1));
699 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
700 // Should be in the gathering state as soon as any transport starts gathering.
701 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
702 EXPECT_EQ(1, gathering_state_signal_count_);
703}
704
705TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
706 CreateJsepTransportController(JsepTransportController::Config());
707 auto description = CreateSessionDescriptionWithoutBundle();
708 EXPECT_TRUE(transport_controller_
709 ->SetLocalDescription(SdpType::kOffer, description.get())
710 .ok());
711
712 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
713 transport_controller_->GetDtlsTransport(kAudioMid1));
714 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
715 transport_controller_->GetDtlsTransport(kVideoMid1));
716
717 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
718 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
719 EXPECT_EQ(1, gathering_state_signal_count_);
720
721 // Have one transport finish gathering, to make sure gathering
722 // completion wasn't signalled if only one transport finished gathering.
723 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
724 EXPECT_EQ(1, gathering_state_signal_count_);
725
726 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
727 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
728 EXPECT_EQ(1, gathering_state_signal_count_);
729
730 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
731 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
732 EXPECT_EQ(2, gathering_state_signal_count_);
733}
734
735// Test that when the last transport that hasn't finished connecting and/or
736// gathering is destroyed, the aggregate state jumps to "completed". This can
737// happen if, for example, we have an audio and video transport, the audio
738// transport completes, then we start bundling video on the audio transport.
739TEST_F(JsepTransportControllerTest,
740 SignalingWhenLastIncompleteTransportDestroyed) {
741 CreateJsepTransportController(JsepTransportController::Config());
742 auto description = CreateSessionDescriptionWithBundleGroup();
743 EXPECT_TRUE(transport_controller_
744 ->SetLocalDescription(SdpType::kOffer, description.get())
745 .ok());
746
747 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
748 transport_controller_->GetDtlsTransport(kAudioMid1));
749 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
750 transport_controller_->GetDtlsTransport(kVideoMid1));
751 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
752
753 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
754 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
755 EXPECT_EQ(1, gathering_state_signal_count_);
756
757 // Let the audio transport complete.
758 fake_audio_dtls->SetWritable(true);
759 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
760 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
761 EXPECT_EQ(1, gathering_state_signal_count_);
762
763 // Set the remote description and enable the bundle.
764 EXPECT_TRUE(transport_controller_
765 ->SetRemoteDescription(SdpType::kAnswer, description.get())
766 .ok());
767 // The BUNDLE should be enabled, the incomplete video transport should be
768 // deleted and the states shoud be updated.
769 fake_video_dtls = static_cast<FakeDtlsTransport*>(
770 transport_controller_->GetDtlsTransport(kVideoMid1));
771 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
772 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
773 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
774 EXPECT_EQ(2, gathering_state_signal_count_);
775}
776
777TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
778 CreateJsepTransportController(JsepTransportController::Config());
779 auto description = CreateSessionDescriptionWithBundleGroup();
780 EXPECT_TRUE(transport_controller_
781 ->SetLocalDescription(SdpType::kOffer, description.get())
782 .ok());
783 transport_controller_->MaybeStartGathering();
784
785 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
786 transport_controller_->GetDtlsTransport(kAudioMid1));
787 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
788 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
789 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
790 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
791}
792
793TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
794 network_thread_ = rtc::Thread::CreateWithSocketServer();
795 network_thread_->Start();
796 CreateJsepTransportController(JsepTransportController::Config(),
797 signaling_thread_, network_thread_.get(),
798 /*PortAllocator=*/nullptr);
799 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
800
801 // connecting --> connected --> completed
802 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
803 EXPECT_EQ(2, connection_state_signal_count_);
804
805 // new --> gathering --> complete
806 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
807 EXPECT_EQ(2, gathering_state_signal_count_);
808
809 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
810 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
811 EXPECT_EQ(2, candidates_signal_count_);
812
813 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
814}
815
816// Older versions of Chrome expect the ICE role to be re-determined when an
817// ICE restart occurs, and also don't perform conflict resolution correctly,
818// so for now we can't safely stop doing this.
819// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
820// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
821// enough population.
822TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
823 CreateJsepTransportController(JsepTransportController::Config());
824 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 09:40:33825 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27826 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
827 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
828 nullptr);
Karl Wiberg918f50c2018-07-05 09:40:33829 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27830 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
831 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
832 nullptr);
833
834 EXPECT_TRUE(transport_controller_
835 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
836 .ok());
837 EXPECT_TRUE(transport_controller_
838 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
839 .ok());
840
841 auto fake_dtls = static_cast<FakeDtlsTransport*>(
842 transport_controller_->GetDtlsTransport(kAudioMid1));
843 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
844 fake_dtls->fake_ice_transport()->GetIceRole());
845
846 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 09:40:33847 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27848 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
849 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
850 nullptr);
851 EXPECT_TRUE(
852 transport_controller_
853 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
854 .ok());
855 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
856 fake_dtls->fake_ice_transport()->GetIceRole());
857}
858
859// Test that if the TransportController was created with the
860// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
861// redetermined on an ICE restart.
862TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
863 JsepTransportController::Config config;
864 config.redetermine_role_on_ice_restart = false;
865
866 CreateJsepTransportController(config);
867 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 09:40:33868 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27869 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
870 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
871 nullptr);
Karl Wiberg918f50c2018-07-05 09:40:33872 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27873 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
874 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
875 nullptr);
876
877 EXPECT_TRUE(transport_controller_
878 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
879 .ok());
880 EXPECT_TRUE(transport_controller_
881 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
882 .ok());
883
884 auto fake_dtls = static_cast<FakeDtlsTransport*>(
885 transport_controller_->GetDtlsTransport(kAudioMid1));
886 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
887 fake_dtls->fake_ice_transport()->GetIceRole());
888
889 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 09:40:33890 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27891 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
892 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
893 nullptr);
894 EXPECT_TRUE(
895 transport_controller_
896 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
897 .ok());
898 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
899 fake_dtls->fake_ice_transport()->GetIceRole());
900}
901
902// Tests ICE-Lite mode in remote answer.
903TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
904 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 09:40:33905 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27906 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
907 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
908 nullptr);
909 EXPECT_TRUE(transport_controller_
910 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
911 .ok());
912 auto fake_dtls = static_cast<FakeDtlsTransport*>(
913 transport_controller_->GetDtlsTransport(kAudioMid1));
914 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
915 fake_dtls->fake_ice_transport()->GetIceRole());
916 EXPECT_EQ(cricket::ICEMODE_FULL,
917 fake_dtls->fake_ice_transport()->remote_ice_mode());
918
Karl Wiberg918f50c2018-07-05 09:40:33919 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27920 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
921 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
922 nullptr);
923 EXPECT_TRUE(transport_controller_
924 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
925 .ok());
926 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
927 fake_dtls->fake_ice_transport()->GetIceRole());
928 EXPECT_EQ(cricket::ICEMODE_LITE,
929 fake_dtls->fake_ice_transport()->remote_ice_mode());
930}
931
932// Tests that the ICE role remains "controlling" if a subsequent offer that
933// does an ICE restart is received from an ICE lite endpoint. Regression test
934// for: https://crbug.com/710760
935TEST_F(JsepTransportControllerTest,
936 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
937 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 09:40:33938 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27939 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
940 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
941 nullptr);
Karl Wiberg918f50c2018-07-05 09:40:33942 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27943 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
944 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
945 nullptr);
946 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
947 // local side is the controlling.
948 EXPECT_TRUE(transport_controller_
949 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
950 .ok());
951 EXPECT_TRUE(transport_controller_
952 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
953 .ok());
954 auto fake_dtls = static_cast<FakeDtlsTransport*>(
955 transport_controller_->GetDtlsTransport(kAudioMid1));
956 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
957 fake_dtls->fake_ice_transport()->GetIceRole());
958
959 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 09:40:33960 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27961 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
962 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
963 nullptr);
Karl Wiberg918f50c2018-07-05 09:40:33964 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27965 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
966 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
967 nullptr);
968 EXPECT_TRUE(transport_controller_
969 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
970 .ok());
971 EXPECT_TRUE(transport_controller_
972 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
973 .ok());
974 fake_dtls = static_cast<FakeDtlsTransport*>(
975 transport_controller_->GetDtlsTransport(kAudioMid1));
976 // The local side is still the controlling role since the remote side is using
977 // ICE-Lite.
978 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
979 fake_dtls->fake_ice_transport()->GetIceRole());
980}
981
982// Tests that the SDP has more than one audio/video m= sections.
983TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
984 CreateJsepTransportController(JsepTransportController::Config());
985 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
986 bundle_group.AddContentName(kAudioMid1);
987 bundle_group.AddContentName(kAudioMid2);
988 bundle_group.AddContentName(kVideoMid1);
989 bundle_group.AddContentName(kDataMid1);
990
Karl Wiberg918f50c2018-07-05 09:40:33991 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27992 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
993 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
994 nullptr);
995 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
996 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
997 nullptr);
998 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
999 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1000 nullptr);
1001 AddDataSection(local_offer.get(), kDataMid1,
1002 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1003 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1004 nullptr);
1005
Karl Wiberg918f50c2018-07-05 09:40:331006 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271007 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1008 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1009 nullptr);
1010 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1011 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1012 nullptr);
1013 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1014 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1015 nullptr);
1016 AddDataSection(remote_answer.get(), kDataMid1,
1017 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1018 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1019 nullptr);
1020
1021 local_offer->AddGroup(bundle_group);
1022 remote_answer->AddGroup(bundle_group);
1023
1024 EXPECT_TRUE(transport_controller_
1025 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1026 .ok());
1027 EXPECT_TRUE(transport_controller_
1028 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1029 .ok());
1030 // Verify that all the sections are bundled on kAudio1.
1031 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1032 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1033 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1034 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1035 EXPECT_EQ(transport1, transport2);
1036 EXPECT_EQ(transport1, transport3);
1037 EXPECT_EQ(transport1, transport4);
1038
1039 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1040 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1041 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1042 EXPECT_EQ(transport1, it->second);
1043 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1044 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1045 EXPECT_EQ(transport1, it->second);
1046 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1047 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1048 EXPECT_EQ(transport1, it->second);
1049 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1050 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1051 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1052 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1053}
1054
1055// Tests that only a subset of all the m= sections are bundled.
1056TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1057 CreateJsepTransportController(JsepTransportController::Config());
1058 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1059 bundle_group.AddContentName(kAudioMid1);
1060 bundle_group.AddContentName(kVideoMid1);
1061
Karl Wiberg918f50c2018-07-05 09:40:331062 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271063 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1064 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1065 nullptr);
1066 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1067 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1068 nullptr);
1069 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1070 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1071 nullptr);
1072
Karl Wiberg918f50c2018-07-05 09:40:331073 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271074 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1075 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1076 nullptr);
1077 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1078 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1079 nullptr);
1080 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1081 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1082 nullptr);
1083
1084 local_offer->AddGroup(bundle_group);
1085 remote_answer->AddGroup(bundle_group);
1086 EXPECT_TRUE(transport_controller_
1087 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1088 .ok());
1089 EXPECT_TRUE(transport_controller_
1090 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1091 .ok());
1092
1093 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1094 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1095 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1096 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1097 EXPECT_NE(transport1, transport2);
1098 EXPECT_EQ(transport1, transport3);
1099
1100 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1101 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1102 EXPECT_EQ(transport1, it->second);
1103 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 21:41:031104 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 23:26:271105}
1106
1107// Tests that the initial offer/answer only have data section and audio/video
1108// sections are added in the subsequent offer.
1109TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1110 CreateJsepTransportController(JsepTransportController::Config());
1111 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1112 bundle_group.AddContentName(kDataMid1);
1113
Karl Wiberg918f50c2018-07-05 09:40:331114 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271115 AddDataSection(local_offer.get(), kDataMid1,
1116 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1117 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1118 nullptr);
Karl Wiberg918f50c2018-07-05 09:40:331119 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271120 AddDataSection(remote_answer.get(), kDataMid1,
1121 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1122 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1123 nullptr);
1124 local_offer->AddGroup(bundle_group);
1125 remote_answer->AddGroup(bundle_group);
1126
1127 EXPECT_TRUE(transport_controller_
1128 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1129 .ok());
1130 EXPECT_TRUE(transport_controller_
1131 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1132 .ok());
1133 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1134
1135 // Add audio/video sections in subsequent offer.
1136 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1137 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1138 nullptr);
1139 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1140 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1141 nullptr);
1142 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1143 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1144 nullptr);
1145 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1146 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1147 nullptr);
1148
1149 // Reset the bundle group and do another offer/answer exchange.
1150 bundle_group.AddContentName(kAudioMid1);
1151 bundle_group.AddContentName(kVideoMid1);
1152 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1153 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1154 local_offer->AddGroup(bundle_group);
1155 remote_answer->AddGroup(bundle_group);
1156
1157 EXPECT_TRUE(transport_controller_
1158 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1159 .ok());
1160 EXPECT_TRUE(transport_controller_
1161 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1162 .ok());
1163
1164 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1165 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1166 EXPECT_EQ(data_transport, audio_transport);
1167 EXPECT_EQ(data_transport, video_transport);
1168}
1169
1170TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1171 CreateJsepTransportController(JsepTransportController::Config());
1172 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1173 bundle_group.AddContentName(kAudioMid1);
1174 bundle_group.AddContentName(kVideoMid1);
1175 bundle_group.AddContentName(kDataMid1);
1176
Karl Wiberg918f50c2018-07-05 09:40:331177 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271178 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1179 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1180 nullptr);
1181 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1182 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1183 nullptr);
1184 AddDataSection(local_offer.get(), kDataMid1,
1185 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1186 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1187 nullptr);
1188
Karl Wiberg918f50c2018-07-05 09:40:331189 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271190 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1191 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1192 nullptr);
1193 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1194 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1195 nullptr);
1196 AddDataSection(remote_answer.get(), kDataMid1,
1197 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1198 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1199 nullptr);
1200 // Reject video and data section.
1201 remote_answer->contents()[1].rejected = true;
1202 remote_answer->contents()[2].rejected = true;
1203
1204 local_offer->AddGroup(bundle_group);
1205 remote_answer->AddGroup(bundle_group);
1206
1207 EXPECT_TRUE(transport_controller_
1208 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1209 .ok());
1210 EXPECT_TRUE(transport_controller_
1211 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1212 .ok());
1213
1214 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1215 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1216 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1217 // Verify the signals are fired correctly.
1218 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1219 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1220 EXPECT_EQ(nullptr, it->second);
1221 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1222 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1223 EXPECT_EQ(nullptr, it2->second);
1224}
1225
1226// Tests that changing the bundled MID in subsequent offer/answer exchange is
1227// not supported.
1228// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1229// fixed
1230TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1231 CreateJsepTransportController(JsepTransportController::Config());
1232 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1233 bundle_group.AddContentName(kAudioMid1);
1234 bundle_group.AddContentName(kVideoMid1);
1235
Karl Wiberg918f50c2018-07-05 09:40:331236 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271237 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1238 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1239 nullptr);
1240 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1241 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1242 nullptr);
1243
Karl Wiberg918f50c2018-07-05 09:40:331244 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271245 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1246 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1247 nullptr);
1248 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1249 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1250 nullptr);
1251
1252 local_offer->AddGroup(bundle_group);
1253 remote_answer->AddGroup(bundle_group);
1254 EXPECT_TRUE(transport_controller_
1255 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1256 .ok());
1257 EXPECT_TRUE(transport_controller_
1258 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1259 .ok());
1260 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1261 transport_controller_->GetRtpTransport(kVideoMid1));
1262
1263 // Reorder the bundle group.
1264 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1265 bundle_group.AddContentName(kAudioMid1);
1266 // The answerer uses the new bundle group and now the bundle mid is changed to
1267 // |kVideo1|.
1268 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1269 remote_answer->AddGroup(bundle_group);
1270 EXPECT_TRUE(transport_controller_
1271 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1272 .ok());
1273 EXPECT_FALSE(transport_controller_
1274 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1275 .ok());
1276}
Zhi Huange830e682018-03-30 17:48:351277// Test that rejecting only the first m= section of a BUNDLE group is treated as
1278// an error, but rejecting all of them works as expected.
1279TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1280 CreateJsepTransportController(JsepTransportController::Config());
1281 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1282 bundle_group.AddContentName(kAudioMid1);
1283 bundle_group.AddContentName(kVideoMid1);
1284 bundle_group.AddContentName(kDataMid1);
1285
Karl Wiberg918f50c2018-07-05 09:40:331286 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351287 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1288 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1289 nullptr);
1290 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1291 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1292 nullptr);
1293 AddDataSection(local_offer.get(), kDataMid1,
1294 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1295 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1296 nullptr);
1297
Karl Wiberg918f50c2018-07-05 09:40:331298 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351299 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1300 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1301 nullptr);
1302 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1303 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1304 nullptr);
1305 AddDataSection(remote_answer.get(), kDataMid1,
1306 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1307 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1308 nullptr);
1309 // Reject audio content in answer.
1310 remote_answer->contents()[0].rejected = true;
1311
1312 local_offer->AddGroup(bundle_group);
1313 remote_answer->AddGroup(bundle_group);
1314
1315 EXPECT_TRUE(transport_controller_
1316 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1317 .ok());
1318 EXPECT_FALSE(transport_controller_
1319 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1320 .ok());
1321
1322 // Reject all the contents.
1323 remote_answer->contents()[1].rejected = true;
1324 remote_answer->contents()[2].rejected = true;
1325 EXPECT_TRUE(transport_controller_
1326 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1327 .ok());
1328 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1329 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1330 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1331}
1332
1333// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1334// is used.
1335TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1336 JsepTransportController::Config config;
1337 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1338 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 09:40:331339 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351340 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1341 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1342 nullptr);
1343
1344 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1345 // Applying a non-RTCP-mux offer is expected to fail.
1346 EXPECT_FALSE(transport_controller_
1347 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1348 .ok());
1349}
1350
1351// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1352// is used.
1353TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1354 JsepTransportController::Config config;
1355 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1356 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 09:40:331357 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351358 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1359 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1360 nullptr);
1361 EXPECT_TRUE(transport_controller_
1362 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1363 .ok());
1364
Karl Wiberg918f50c2018-07-05 09:40:331365 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351366 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1367 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1368 nullptr);
1369 // Applying a non-RTCP-mux answer is expected to fail.
1370 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1371 EXPECT_FALSE(transport_controller_
1372 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1373 .ok());
1374}
Zhi Huange818b6e2018-02-22 23:26:271375
Zhi Huangd2248f82018-04-10 21:41:031376// This tests that the BUNDLE group in answer should be a subset of the offered
1377// group.
1378TEST_F(JsepTransportControllerTest,
1379 AddContentToBundleGroupInAnswerNotSupported) {
1380 CreateJsepTransportController(JsepTransportController::Config());
1381 auto local_offer = CreateSessionDescriptionWithoutBundle();
1382 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1383
1384 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1385 offer_bundle_group.AddContentName(kAudioMid1);
1386 local_offer->AddGroup(offer_bundle_group);
1387
1388 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1389 answer_bundle_group.AddContentName(kAudioMid1);
1390 answer_bundle_group.AddContentName(kVideoMid1);
1391 remote_answer->AddGroup(answer_bundle_group);
1392 EXPECT_TRUE(transport_controller_
1393 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1394 .ok());
1395 EXPECT_FALSE(transport_controller_
1396 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1397 .ok());
1398}
1399
1400// This tests that the BUNDLE group with non-existing MID should be rejectd.
1401TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1402 CreateJsepTransportController(JsepTransportController::Config());
1403 auto local_offer = CreateSessionDescriptionWithoutBundle();
1404 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1405
1406 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1407 // The BUNDLE group is invalid because there is no data section in the
1408 // description.
1409 invalid_bundle_group.AddContentName(kDataMid1);
1410 local_offer->AddGroup(invalid_bundle_group);
1411 remote_answer->AddGroup(invalid_bundle_group);
1412
1413 EXPECT_FALSE(transport_controller_
1414 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1415 .ok());
1416 EXPECT_FALSE(transport_controller_
1417 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1418 .ok());
1419}
1420
1421// This tests that an answer shouldn't be able to remove an m= section from an
1422// established group without rejecting it.
1423TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1424 CreateJsepTransportController(JsepTransportController::Config());
1425
1426 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1427 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1428 EXPECT_TRUE(transport_controller_
1429 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1430 .ok());
1431 EXPECT_TRUE(transport_controller_
1432 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1433 .ok());
1434
1435 // Do an re-offer/answer.
1436 EXPECT_TRUE(transport_controller_
1437 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1438 .ok());
1439 auto new_answer = CreateSessionDescriptionWithoutBundle();
1440 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1441 // The answer removes video from the BUNDLE group without rejecting it is
1442 // invalid.
1443 new_bundle_group.AddContentName(kAudioMid1);
1444 new_answer->AddGroup(new_bundle_group);
1445
1446 // Applying invalid answer is expected to fail.
1447 EXPECT_FALSE(transport_controller_
1448 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1449 .ok());
1450
1451 // Rejected the video content.
1452 auto video_content = new_answer->GetContentByName(kVideoMid1);
1453 ASSERT_TRUE(video_content);
1454 video_content->rejected = true;
1455 EXPECT_TRUE(transport_controller_
1456 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1457 .ok());
1458}
1459
Zhi Huange818b6e2018-02-22 23:26:271460} // namespace webrtc