blob: cb2023f0e291fe55f652b79c45901edfd9129741 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
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 10:34:49 -070014#include "api/test/fake_media_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080015#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 15:26:27 -080021#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
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070044namespace {
45
46// Media transport factory requires crypto settings to be present in order to
47// create media transport.
48void AddCryptoSettings(cricket::SessionDescription* description) {
49 for (auto& content : description->contents()) {
50 content.media_description()->AddCrypto(cricket::CryptoParams(
51 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
52 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
53 }
54}
55
56} // namespace
57
Zhi Huange818b6e2018-02-22 15:26:27 -080058class FakeTransportFactory : public cricket::TransportFactoryInterface {
59 public:
60 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
61 const std::string& transport_name,
62 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020063 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
64 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080065 }
66
67 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
68 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070069 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 15:26:27 -080070 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
71 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 11:40:33 +020072 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080073 }
74};
75
Zhi Huang365381f2018-04-13 16:44:34 -070076class JsepTransportControllerTest : public JsepTransportController::Observer,
77 public testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080078 public sigslot::has_slots<> {
79 public:
80 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020081 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080082 }
83
84 void CreateJsepTransportController(
85 JsepTransportController::Config config,
86 rtc::Thread* signaling_thread = rtc::Thread::Current(),
87 rtc::Thread* network_thread = rtc::Thread::Current(),
88 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070089 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 15:26:27 -080090 // The tests only works with |fake_transport_factory|;
91 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070092 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 11:40:33 +020093 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070094 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080095 ConnectTransportControllerSignals();
96 }
97
98 void ConnectTransportControllerSignals() {
99 transport_controller_->SignalIceConnectionState.connect(
100 this, &JsepTransportControllerTest::OnConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200101 transport_controller_->SignalStandardizedIceConnectionState.connect(
102 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
103 transport_controller_->SignalConnectionState.connect(
104 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800105 transport_controller_->SignalIceGatheringState.connect(
106 this, &JsepTransportControllerTest::OnGatheringState);
107 transport_controller_->SignalIceCandidatesGathered.connect(
108 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800109 }
110
111 std::unique_ptr<cricket::SessionDescription>
112 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200113 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800114 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
115 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
116 nullptr);
117 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
118 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
119 nullptr);
120 return description;
121 }
122
123 std::unique_ptr<cricket::SessionDescription>
124 CreateSessionDescriptionWithBundleGroup() {
125 auto description = CreateSessionDescriptionWithoutBundle();
126 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
127 bundle_group.AddContentName(kAudioMid1);
128 bundle_group.AddContentName(kVideoMid1);
129 description->AddGroup(bundle_group);
130
131 return description;
132 }
133
134 void AddAudioSection(cricket::SessionDescription* description,
135 const std::string& mid,
136 const std::string& ufrag,
137 const std::string& pwd,
138 cricket::IceMode ice_mode,
139 cricket::ConnectionRole conn_role,
140 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
141 std::unique_ptr<cricket::AudioContentDescription> audio(
142 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700143 // Set RTCP-mux to be true because the default policy is "mux required".
144 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800145 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
146 /*rejected=*/false, audio.release());
147 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
148 }
149
150 void AddVideoSection(cricket::SessionDescription* description,
151 const std::string& mid,
152 const std::string& ufrag,
153 const std::string& pwd,
154 cricket::IceMode ice_mode,
155 cricket::ConnectionRole conn_role,
156 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
157 std::unique_ptr<cricket::VideoContentDescription> video(
158 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700159 // Set RTCP-mux to be true because the default policy is "mux required".
160 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800161 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
162 /*rejected=*/false, video.release());
163 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
164 }
165
166 void AddDataSection(cricket::SessionDescription* description,
167 const std::string& mid,
168 cricket::MediaProtocolType protocol_type,
169 const std::string& ufrag,
170 const std::string& pwd,
171 cricket::IceMode ice_mode,
172 cricket::ConnectionRole conn_role,
173 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
174 std::unique_ptr<cricket::DataContentDescription> data(
175 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700176 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800177 description->AddContent(mid, protocol_type,
178 /*rejected=*/false, data.release());
179 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
180 }
181
182 void AddTransportInfo(cricket::SessionDescription* description,
183 const std::string& mid,
184 const std::string& ufrag,
185 const std::string& pwd,
186 cricket::IceMode ice_mode,
187 cricket::ConnectionRole conn_role,
188 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
189 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
190 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700191 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800192 }
193
194 cricket::TransportDescription transport_desc(std::vector<std::string>(),
195 ufrag, pwd, ice_mode,
196 conn_role, fingerprint.get());
197 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
198 }
199
200 cricket::IceConfig CreateIceConfig(
201 int receiving_timeout,
202 cricket::ContinualGatheringPolicy continual_gathering_policy) {
203 cricket::IceConfig config;
204 config.receiving_timeout = receiving_timeout;
205 config.continual_gathering_policy = continual_gathering_policy;
206 return config;
207 }
208
209 Candidate CreateCandidate(const std::string& transport_name, int component) {
210 Candidate c;
211 c.set_transport_name(transport_name);
212 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
213 c.set_component(component);
214 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
215 c.set_priority(1);
216 return c;
217 }
218
219 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
220 if (!network_thread_->IsCurrent()) {
221 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
222 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
223 });
224 return;
225 }
226
227 auto description = CreateSessionDescriptionWithBundleGroup();
228 EXPECT_TRUE(transport_controller_
229 ->SetLocalDescription(SdpType::kOffer, description.get())
230 .ok());
231
232 transport_controller_->MaybeStartGathering();
233 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
234 transport_controller_->GetDtlsTransport(kAudioMid1));
235 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
236 transport_controller_->GetDtlsTransport(kVideoMid1));
237 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
238 fake_audio_dtls->fake_ice_transport(),
239 CreateCandidate(kAudioMid1, /*component=*/1));
240 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
241 fake_video_dtls->fake_ice_transport(),
242 CreateCandidate(kVideoMid1, /*component=*/1));
243 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
244 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
245 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
246 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
247 fake_audio_dtls->SetReceiving(true);
248 fake_video_dtls->SetReceiving(true);
249 fake_audio_dtls->SetWritable(true);
250 fake_video_dtls->SetWritable(true);
251 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
252 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
253 }
254
255 protected:
256 void OnConnectionState(cricket::IceConnectionState state) {
257 if (!signaling_thread_->IsCurrent()) {
258 signaled_on_non_signaling_thread_ = true;
259 }
260 connection_state_ = state;
261 ++connection_state_signal_count_;
262 }
263
Jonas Olsson635474e2018-10-18 15:58:17 +0200264 void OnStandardizedIceConnectionState(
265 PeerConnectionInterface::IceConnectionState state) {
266 if (!signaling_thread_->IsCurrent()) {
267 signaled_on_non_signaling_thread_ = true;
268 }
269 ice_connection_state_ = state;
270 ++ice_connection_state_signal_count_;
271 }
272
273 void OnCombinedConnectionState(
274 PeerConnectionInterface::PeerConnectionState state) {
275 if (!signaling_thread_->IsCurrent()) {
276 signaled_on_non_signaling_thread_ = true;
277 }
278 combined_connection_state_ = state;
279 ++combined_connection_state_signal_count_;
280 }
281
Zhi Huange818b6e2018-02-22 15:26:27 -0800282 void OnGatheringState(cricket::IceGatheringState state) {
283 if (!signaling_thread_->IsCurrent()) {
284 signaled_on_non_signaling_thread_ = true;
285 }
286 gathering_state_ = state;
287 ++gathering_state_signal_count_;
288 }
289
290 void OnCandidatesGathered(const std::string& transport_name,
291 const Candidates& candidates) {
292 if (!signaling_thread_->IsCurrent()) {
293 signaled_on_non_signaling_thread_ = true;
294 }
295 candidates_[transport_name].insert(candidates_[transport_name].end(),
296 candidates.begin(), candidates.end());
297 ++candidates_signal_count_;
298 }
299
Zhi Huang365381f2018-04-13 16:44:34 -0700300 // JsepTransportController::Observer overrides.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700301 bool OnTransportChanged(
Zhi Huang365381f2018-04-13 16:44:34 -0700302 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700303 RtpTransportInternal* rtp_transport,
Zhi Huang365381f2018-04-13 16:44:34 -0700304 cricket::DtlsTransportInternal* dtls_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700305 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800306 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700307 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800308 }
309
310 // Information received from signals from transport controller.
311 cricket::IceConnectionState connection_state_ =
312 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +0200313 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
314 PeerConnectionInterface::kIceConnectionNew;
315 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
316 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800317 bool receiving_ = false;
318 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
319 // transport_name => candidates
320 std::map<std::string, Candidates> candidates_;
321 // Counts of each signal emitted.
322 int connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200323 int ice_connection_state_signal_count_ = 0;
324 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800325 int receiving_signal_count_ = 0;
326 int gathering_state_signal_count_ = 0;
327 int candidates_signal_count_ = 0;
328
329 // |network_thread_| should be destroyed after |transport_controller_|
330 std::unique_ptr<rtc::Thread> network_thread_;
331 std::unique_ptr<JsepTransportController> transport_controller_;
332 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
333 rtc::Thread* const signaling_thread_ = nullptr;
334 bool signaled_on_non_signaling_thread_ = false;
335 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
336 // signaled correctly.
337 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
338 std::map<std::string, cricket::DtlsTransportInternal*>
339 changed_dtls_transport_by_mid_;
340};
341
342TEST_F(JsepTransportControllerTest, GetRtpTransport) {
343 CreateJsepTransportController(JsepTransportController::Config());
344 auto description = CreateSessionDescriptionWithoutBundle();
345 EXPECT_TRUE(transport_controller_
346 ->SetLocalDescription(SdpType::kOffer, description.get())
347 .ok());
348 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
349 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
350 EXPECT_NE(nullptr, audio_rtp_transport);
351 EXPECT_NE(nullptr, video_rtp_transport);
352 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
353 // Return nullptr for non-existing ones.
354 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
355}
356
357TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
358 JsepTransportController::Config config;
359 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
360 CreateJsepTransportController(config);
361 auto description = CreateSessionDescriptionWithoutBundle();
362 EXPECT_TRUE(transport_controller_
363 ->SetLocalDescription(SdpType::kOffer, description.get())
364 .ok());
365 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
366 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
367 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
368 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
369 // Return nullptr for non-existing ones.
370 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
371 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
372}
373
Zhi Huange830e682018-03-30 10:48:35 -0700374TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
375 JsepTransportController::Config config;
376 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
377 CreateJsepTransportController(config);
378 auto description = CreateSessionDescriptionWithoutBundle();
379 EXPECT_TRUE(transport_controller_
380 ->SetLocalDescription(SdpType::kOffer, description.get())
381 .ok());
382 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
383 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
384 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
385 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700386 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
387}
388
389TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
390 FakeMediaTransportFactory fake_media_transport_factory;
391 JsepTransportController::Config config;
392
393 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
394 config.media_transport_factory = &fake_media_transport_factory;
395 CreateJsepTransportController(config);
396 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700397 AddCryptoSettings(description.get());
398
Anton Sukhanov7940da02018-10-10 10:34:49 -0700399 EXPECT_TRUE(transport_controller_
400 ->SetLocalDescription(SdpType::kOffer, description.get())
401 .ok());
402
403 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
404 transport_controller_->GetMediaTransport(kAudioMid1));
405
406 ASSERT_NE(nullptr, media_transport);
407
408 // After SetLocalDescription, media transport should be created as caller.
409 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700410 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700411
412 // Return nullptr for non-existing mids.
413 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
414}
415
416TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
417 FakeMediaTransportFactory fake_media_transport_factory;
418 JsepTransportController::Config config;
419
420 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
421 config.media_transport_factory = &fake_media_transport_factory;
422 CreateJsepTransportController(config);
423 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700424 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700425 EXPECT_TRUE(transport_controller_
426 ->SetRemoteDescription(SdpType::kOffer, description.get())
427 .ok());
428
429 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
430 transport_controller_->GetMediaTransport(kAudioMid1));
431
432 ASSERT_NE(nullptr, media_transport);
433
434 // After SetRemoteDescription, media transport should be created as callee.
435 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700436 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700437
438 // Return nullptr for non-existing mids.
439 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 10:48:35 -0700440}
441
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700442TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
443 FakeMediaTransportFactory fake_media_transport_factory;
444 JsepTransportController::Config config;
445
446 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
447 config.media_transport_factory = &fake_media_transport_factory;
448 CreateJsepTransportController(config);
449 auto description = CreateSessionDescriptionWithoutBundle();
450 EXPECT_TRUE(transport_controller_
451 ->SetRemoteDescription(SdpType::kOffer, description.get())
452 .ok());
453
454 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
455
456 // Even if we set local description with crypto now (after the remote offer
457 // was set), media transport won't be provided.
458 auto description2 = CreateSessionDescriptionWithoutBundle();
459 AddCryptoSettings(description2.get());
460 EXPECT_TRUE(transport_controller_
461 ->SetLocalDescription(SdpType::kAnswer, description2.get())
462 .ok());
463
464 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
465}
466
467TEST_F(JsepTransportControllerTest,
468 AfterSettingAnswerTheSameMediaTransportIsReturned) {
469 FakeMediaTransportFactory fake_media_transport_factory;
470 JsepTransportController::Config config;
471
472 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
473 config.media_transport_factory = &fake_media_transport_factory;
474 CreateJsepTransportController(config);
475 auto description = CreateSessionDescriptionWithoutBundle();
476 AddCryptoSettings(description.get());
477 EXPECT_TRUE(transport_controller_
478 ->SetRemoteDescription(SdpType::kOffer, description.get())
479 .ok());
480
481 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
482 transport_controller_->GetMediaTransport(kAudioMid1));
483 EXPECT_NE(nullptr, media_transport);
484 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
485
486 // Even if we set local description with crypto now (after the remote offer
487 // was set), media transport won't be provided.
488 auto description2 = CreateSessionDescriptionWithoutBundle();
489 AddCryptoSettings(description2.get());
490
491 RTCError result = transport_controller_->SetLocalDescription(
492 SdpType::kAnswer, description2.get());
493 EXPECT_TRUE(result.ok()) << result.message();
494
495 // Media transport did not change.
496 EXPECT_EQ(media_transport,
497 transport_controller_->GetMediaTransport(kAudioMid1));
498}
499
Zhi Huange818b6e2018-02-22 15:26:27 -0800500TEST_F(JsepTransportControllerTest, SetIceConfig) {
501 CreateJsepTransportController(JsepTransportController::Config());
502 auto description = CreateSessionDescriptionWithoutBundle();
503 EXPECT_TRUE(transport_controller_
504 ->SetLocalDescription(SdpType::kOffer, description.get())
505 .ok());
506
507 transport_controller_->SetIceConfig(
508 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
509 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
510 transport_controller_->GetDtlsTransport(kAudioMid1));
511 ASSERT_NE(nullptr, fake_audio_dtls);
512 EXPECT_EQ(kTimeout,
513 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
514 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
515
516 // Test that value stored in controller is applied to new transports.
517 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
518 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
519 nullptr);
520
521 EXPECT_TRUE(transport_controller_
522 ->SetLocalDescription(SdpType::kOffer, description.get())
523 .ok());
524 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
525 transport_controller_->GetDtlsTransport(kAudioMid2));
526 ASSERT_NE(nullptr, fake_audio_dtls);
527 EXPECT_EQ(kTimeout,
528 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
529 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
530}
531
532// Tests the getter and setter of the ICE restart flag.
533TEST_F(JsepTransportControllerTest, NeedIceRestart) {
534 CreateJsepTransportController(JsepTransportController::Config());
535 auto description = CreateSessionDescriptionWithoutBundle();
536 EXPECT_TRUE(transport_controller_
537 ->SetLocalDescription(SdpType::kOffer, description.get())
538 .ok());
539 EXPECT_TRUE(transport_controller_
540 ->SetRemoteDescription(SdpType::kAnswer, description.get())
541 .ok());
542
543 // Initially NeedsIceRestart should return false.
544 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
545 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
546 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
547 // true.
548 transport_controller_->SetNeedsIceRestartFlag();
549 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
550 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
551 // For a nonexistent transport, false should be returned.
552 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
553
554 // Reset the ice_ufrag/ice_pwd for audio.
555 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
556 audio_transport_info->description.ice_ufrag = kIceUfrag2;
557 audio_transport_info->description.ice_pwd = kIcePwd2;
558 EXPECT_TRUE(transport_controller_
559 ->SetLocalDescription(SdpType::kOffer, description.get())
560 .ok());
561 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
562 // return false for audio and true for video.
563 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
564 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
565}
566
567TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
568 CreateJsepTransportController(JsepTransportController::Config());
569 auto description = CreateSessionDescriptionWithBundleGroup();
570 EXPECT_TRUE(transport_controller_
571 ->SetLocalDescription(SdpType::kOffer, description.get())
572 .ok());
573 // After setting the local description, we should be able to start gathering
574 // candidates.
575 transport_controller_->MaybeStartGathering();
576 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
577 EXPECT_EQ(1, gathering_state_signal_count_);
578}
579
580TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
581 CreateJsepTransportController(JsepTransportController::Config());
582 auto description = CreateSessionDescriptionWithoutBundle();
583 transport_controller_->SetLocalDescription(SdpType::kOffer,
584 description.get());
585 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
586 description.get());
587 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
588 transport_controller_->GetDtlsTransport(kAudioMid1));
589 ASSERT_NE(nullptr, fake_audio_dtls);
590 Candidates candidates;
591 candidates.push_back(
592 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
593 EXPECT_TRUE(
594 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
595 EXPECT_EQ(1U,
596 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
597
598 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
599 EXPECT_EQ(0U,
600 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
601}
602
603TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
604 CreateJsepTransportController(JsepTransportController::Config());
605
606 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
607 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
608 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
609 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
610
Karl Wiberg918f50c2018-07-05 11:40:33 +0200611 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800612 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
613 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
614 certificate1);
615
616 // Apply the local certificate.
617 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
618 // Apply the local description.
619 EXPECT_TRUE(transport_controller_
620 ->SetLocalDescription(SdpType::kOffer, description.get())
621 .ok());
622 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
623 EXPECT_TRUE(returned_certificate);
624 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
625 returned_certificate->identity()->certificate().ToPEMString());
626
627 // Should fail if called for a nonexistant transport.
628 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
629
630 // Shouldn't be able to change the identity once set.
631 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
632 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
633 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
634 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
635}
636
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800637TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800638 CreateJsepTransportController(JsepTransportController::Config());
639 auto description = CreateSessionDescriptionWithBundleGroup();
640 EXPECT_TRUE(transport_controller_
641 ->SetLocalDescription(SdpType::kOffer, description.get())
642 .ok());
643 rtc::FakeSSLCertificate fake_certificate("fake_data");
644
645 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
646 transport_controller_->GetDtlsTransport(kAudioMid1));
647 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800648 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
649 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
650 ASSERT_TRUE(returned_cert_chain);
651 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800652 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800653 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800654
655 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800656 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800657}
658
659TEST_F(JsepTransportControllerTest, GetDtlsRole) {
660 CreateJsepTransportController(JsepTransportController::Config());
661 auto offer_certificate =
662 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
663 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
664 auto answer_certificate =
665 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
666 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
667 transport_controller_->SetLocalCertificate(offer_certificate);
668
Karl Wiberg918f50c2018-07-05 11:40:33 +0200669 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800670 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
671 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
672 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200673 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800674 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
675 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
676 answer_certificate);
677
678 EXPECT_TRUE(transport_controller_
679 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
680 .ok());
681
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200682 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800683 transport_controller_->GetDtlsRole(kAudioMid1);
684 // The DTLS role is not decided yet.
685 EXPECT_FALSE(role);
686 EXPECT_TRUE(transport_controller_
687 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
688 .ok());
689 role = transport_controller_->GetDtlsRole(kAudioMid1);
690
691 ASSERT_TRUE(role);
692 EXPECT_EQ(rtc::SSL_CLIENT, *role);
693}
694
695TEST_F(JsepTransportControllerTest, GetStats) {
696 CreateJsepTransportController(JsepTransportController::Config());
697 auto description = CreateSessionDescriptionWithBundleGroup();
698 EXPECT_TRUE(transport_controller_
699 ->SetLocalDescription(SdpType::kOffer, description.get())
700 .ok());
701
702 cricket::TransportStats stats;
703 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
704 EXPECT_EQ(kAudioMid1, stats.transport_name);
705 EXPECT_EQ(1u, stats.channel_stats.size());
706 // Return false for non-existing transport.
707 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
708}
709
710TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
711 CreateJsepTransportController(JsepTransportController::Config());
712 auto description = CreateSessionDescriptionWithoutBundle();
713 EXPECT_TRUE(transport_controller_
714 ->SetLocalDescription(SdpType::kOffer, description.get())
715 .ok());
716
717 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
718 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
719 fake_ice->SetCandidatesGatheringComplete();
720 fake_ice->SetConnectionCount(1);
721 // The connection stats will be failed if there is no active connection.
722 fake_ice->SetConnectionCount(0);
723 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
724 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100725 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
726 ice_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200727 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100728 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
729 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200730 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800731}
732
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700733TEST_F(JsepTransportControllerTest,
734 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800735 CreateJsepTransportController(JsepTransportController::Config());
736 auto description = CreateSessionDescriptionWithoutBundle();
737 EXPECT_TRUE(transport_controller_
738 ->SetLocalDescription(SdpType::kOffer, description.get())
739 .ok());
740
741 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
742 transport_controller_->GetDtlsTransport(kAudioMid1));
743 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
744 transport_controller_->GetDtlsTransport(kVideoMid1));
745
746 // First, have one transport connect, and another fail, to ensure that
747 // the first transport connecting didn't trigger a "connected" state signal.
748 // We should only get a signal when all are connected.
749 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
750 fake_audio_dtls->SetWritable(true);
751 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
752 // Decrease the number of the connection to trigger the signal.
753 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
754 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
755 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
756
757 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
758 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100759 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
760 ice_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200761 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100762 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
763 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200764 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800765
Jonas Olsson635474e2018-10-18 15:58:17 +0200766 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
767 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800768 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
769 // the transport state to be STATE_CONNECTING.
770 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
771 fake_video_dtls->SetWritable(true);
772 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
773 EXPECT_EQ(2, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100774 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
775 ice_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200776 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100777 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
778 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200779 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800780}
781
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700782TEST_F(JsepTransportControllerTest,
783 SignalConnectionStateConnectedWithMediaTransport) {
784 FakeMediaTransportFactory fake_media_transport_factory;
785 JsepTransportController::Config config;
786 config.media_transport_factory = &fake_media_transport_factory;
787 CreateJsepTransportController(config);
788 auto description = CreateSessionDescriptionWithoutBundle();
789 AddCryptoSettings(description.get());
790 EXPECT_TRUE(transport_controller_
791 ->SetLocalDescription(SdpType::kOffer, description.get())
792 .ok());
793
794 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
795 transport_controller_->GetDtlsTransport(kAudioMid1));
796 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
797 transport_controller_->GetDtlsTransport(kVideoMid1));
798 fake_audio_dtls->SetWritable(true);
799 fake_video_dtls->SetWritable(true);
800 // Decreasing connection count from 2 to 1 triggers connection state event.
801 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
802 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
803 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
804 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
805 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
806 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
807
808 // Still not connected, because we are waiting for media transport.
809 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
810 kTimeout);
811
812 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
813 transport_controller_->GetMediaTransport(kAudioMid1));
814
815 media_transport->SetState(webrtc::MediaTransportState::kWritable);
816 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
817 kTimeout);
818
819 // Still waiting for the second media transport.
820 media_transport = static_cast<FakeMediaTransport*>(
821 transport_controller_->GetMediaTransport(kVideoMid1));
822 media_transport->SetState(webrtc::MediaTransportState::kWritable);
823
824 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
825}
826
827TEST_F(JsepTransportControllerTest,
828 SignalConnectionStateFailedWhenMediaTransportClosed) {
829 FakeMediaTransportFactory fake_media_transport_factory;
830 JsepTransportController::Config config;
831 config.media_transport_factory = &fake_media_transport_factory;
832 CreateJsepTransportController(config);
833 auto description = CreateSessionDescriptionWithoutBundle();
834 AddCryptoSettings(description.get());
835 EXPECT_TRUE(transport_controller_
836 ->SetLocalDescription(SdpType::kOffer, description.get())
837 .ok());
838
839 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
840 transport_controller_->GetDtlsTransport(kAudioMid1));
841 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
842 transport_controller_->GetDtlsTransport(kVideoMid1));
843 fake_audio_dtls->SetWritable(true);
844 fake_video_dtls->SetWritable(true);
845 // Decreasing connection count from 2 to 1 triggers connection state event.
846 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
847 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
848 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
849 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
850 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
851 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
852
853 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
854 transport_controller_->GetMediaTransport(kAudioMid1));
855
856 media_transport->SetState(webrtc::MediaTransportState::kWritable);
857
858 media_transport = static_cast<FakeMediaTransport*>(
859 transport_controller_->GetMediaTransport(kVideoMid1));
860
861 media_transport->SetState(webrtc::MediaTransportState::kWritable);
862
863 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
864
865 media_transport->SetState(webrtc::MediaTransportState::kClosed);
866 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
867}
868
Zhi Huange818b6e2018-02-22 15:26:27 -0800869TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
870 CreateJsepTransportController(JsepTransportController::Config());
871 auto description = CreateSessionDescriptionWithoutBundle();
872 EXPECT_TRUE(transport_controller_
873 ->SetLocalDescription(SdpType::kOffer, description.get())
874 .ok());
875
876 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
877 transport_controller_->GetDtlsTransport(kAudioMid1));
878 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
879 transport_controller_->GetDtlsTransport(kVideoMid1));
880
881 // First, have one transport connect, and another fail, to ensure that
882 // the first transport connecting didn't trigger a "connected" state signal.
883 // We should only get a signal when all are connected.
884 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
885 fake_audio_dtls->SetWritable(true);
886 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
887 // Decrease the number of the connection to trigger the signal.
888 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
889 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
890 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
891
892 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
893 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100894 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
895 ice_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200896 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100897 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
898 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200899 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800900
Jonas Olsson635474e2018-10-18 15:58:17 +0200901 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
902 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800903 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
904 // the transport state to be STATE_COMPLETED.
905 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
906 fake_video_dtls->SetWritable(true);
907 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
908 EXPECT_EQ(2, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100909 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
910 ice_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200911 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100912 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
913 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200914 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800915}
916
917TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
918 CreateJsepTransportController(JsepTransportController::Config());
919 auto description = CreateSessionDescriptionWithoutBundle();
920 EXPECT_TRUE(transport_controller_
921 ->SetLocalDescription(SdpType::kOffer, description.get())
922 .ok());
923
924 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
925 transport_controller_->GetDtlsTransport(kAudioMid1));
926 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
927 // Should be in the gathering state as soon as any transport starts gathering.
928 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
929 EXPECT_EQ(1, gathering_state_signal_count_);
930}
931
932TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
933 CreateJsepTransportController(JsepTransportController::Config());
934 auto description = CreateSessionDescriptionWithoutBundle();
935 EXPECT_TRUE(transport_controller_
936 ->SetLocalDescription(SdpType::kOffer, description.get())
937 .ok());
938
939 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
940 transport_controller_->GetDtlsTransport(kAudioMid1));
941 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
942 transport_controller_->GetDtlsTransport(kVideoMid1));
943
944 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
945 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
946 EXPECT_EQ(1, gathering_state_signal_count_);
947
948 // Have one transport finish gathering, to make sure gathering
949 // completion wasn't signalled if only one transport finished gathering.
950 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
951 EXPECT_EQ(1, gathering_state_signal_count_);
952
953 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
954 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
955 EXPECT_EQ(1, gathering_state_signal_count_);
956
957 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
958 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
959 EXPECT_EQ(2, gathering_state_signal_count_);
960}
961
962// Test that when the last transport that hasn't finished connecting and/or
963// gathering is destroyed, the aggregate state jumps to "completed". This can
964// happen if, for example, we have an audio and video transport, the audio
965// transport completes, then we start bundling video on the audio transport.
966TEST_F(JsepTransportControllerTest,
967 SignalingWhenLastIncompleteTransportDestroyed) {
968 CreateJsepTransportController(JsepTransportController::Config());
969 auto description = CreateSessionDescriptionWithBundleGroup();
970 EXPECT_TRUE(transport_controller_
971 ->SetLocalDescription(SdpType::kOffer, description.get())
972 .ok());
973
974 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
975 transport_controller_->GetDtlsTransport(kAudioMid1));
976 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
977 transport_controller_->GetDtlsTransport(kVideoMid1));
978 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
979
980 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
981 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
982 EXPECT_EQ(1, gathering_state_signal_count_);
983
984 // Let the audio transport complete.
985 fake_audio_dtls->SetWritable(true);
986 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
987 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +0200988 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800989 EXPECT_EQ(1, gathering_state_signal_count_);
990
991 // Set the remote description and enable the bundle.
992 EXPECT_TRUE(transport_controller_
993 ->SetRemoteDescription(SdpType::kAnswer, description.get())
994 .ok());
995 // The BUNDLE should be enabled, the incomplete video transport should be
996 // deleted and the states shoud be updated.
997 fake_video_dtls = static_cast<FakeDtlsTransport*>(
998 transport_controller_->GetDtlsTransport(kVideoMid1));
999 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
1000 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001001 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1002 ice_connection_state_);
1003 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1004 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001005 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1006 EXPECT_EQ(2, gathering_state_signal_count_);
1007}
1008
1009TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1010 CreateJsepTransportController(JsepTransportController::Config());
1011 auto description = CreateSessionDescriptionWithBundleGroup();
1012 EXPECT_TRUE(transport_controller_
1013 ->SetLocalDescription(SdpType::kOffer, description.get())
1014 .ok());
1015 transport_controller_->MaybeStartGathering();
1016
1017 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1018 transport_controller_->GetDtlsTransport(kAudioMid1));
1019 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1020 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1021 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1022 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1023}
1024
1025TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1026 network_thread_ = rtc::Thread::CreateWithSocketServer();
1027 network_thread_->Start();
1028 CreateJsepTransportController(JsepTransportController::Config(),
1029 signaling_thread_, network_thread_.get(),
1030 /*PortAllocator=*/nullptr);
1031 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1032
1033 // connecting --> connected --> completed
1034 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1035 EXPECT_EQ(2, connection_state_signal_count_);
1036
1037 // new --> gathering --> complete
1038 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1039 EXPECT_EQ(2, gathering_state_signal_count_);
1040
1041 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1042 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1043 EXPECT_EQ(2, candidates_signal_count_);
1044
1045 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1046}
1047
1048// Older versions of Chrome expect the ICE role to be re-determined when an
1049// ICE restart occurs, and also don't perform conflict resolution correctly,
1050// so for now we can't safely stop doing this.
1051// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1052// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1053// enough population.
1054TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1055 CreateJsepTransportController(JsepTransportController::Config());
1056 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001057 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001058 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1059 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1060 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001061 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001062 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1063 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1064 nullptr);
1065
1066 EXPECT_TRUE(transport_controller_
1067 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1068 .ok());
1069 EXPECT_TRUE(transport_controller_
1070 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1071 .ok());
1072
1073 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1074 transport_controller_->GetDtlsTransport(kAudioMid1));
1075 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1076 fake_dtls->fake_ice_transport()->GetIceRole());
1077
1078 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001079 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001080 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1081 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1082 nullptr);
1083 EXPECT_TRUE(
1084 transport_controller_
1085 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1086 .ok());
1087 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1088 fake_dtls->fake_ice_transport()->GetIceRole());
1089}
1090
1091// Test that if the TransportController was created with the
1092// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1093// redetermined on an ICE restart.
1094TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1095 JsepTransportController::Config config;
1096 config.redetermine_role_on_ice_restart = false;
1097
1098 CreateJsepTransportController(config);
1099 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001100 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001101 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1102 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1103 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001104 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001105 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1106 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1107 nullptr);
1108
1109 EXPECT_TRUE(transport_controller_
1110 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1111 .ok());
1112 EXPECT_TRUE(transport_controller_
1113 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1114 .ok());
1115
1116 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1117 transport_controller_->GetDtlsTransport(kAudioMid1));
1118 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1119 fake_dtls->fake_ice_transport()->GetIceRole());
1120
1121 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001122 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001123 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1124 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1125 nullptr);
1126 EXPECT_TRUE(
1127 transport_controller_
1128 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1129 .ok());
1130 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1131 fake_dtls->fake_ice_transport()->GetIceRole());
1132}
1133
1134// Tests ICE-Lite mode in remote answer.
1135TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1136 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001137 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001138 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1139 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1140 nullptr);
1141 EXPECT_TRUE(transport_controller_
1142 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1143 .ok());
1144 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1145 transport_controller_->GetDtlsTransport(kAudioMid1));
1146 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1147 fake_dtls->fake_ice_transport()->GetIceRole());
1148 EXPECT_EQ(cricket::ICEMODE_FULL,
1149 fake_dtls->fake_ice_transport()->remote_ice_mode());
1150
Karl Wiberg918f50c2018-07-05 11:40:33 +02001151 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001152 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1153 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1154 nullptr);
1155 EXPECT_TRUE(transport_controller_
1156 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1157 .ok());
1158 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1159 fake_dtls->fake_ice_transport()->GetIceRole());
1160 EXPECT_EQ(cricket::ICEMODE_LITE,
1161 fake_dtls->fake_ice_transport()->remote_ice_mode());
1162}
1163
1164// Tests that the ICE role remains "controlling" if a subsequent offer that
1165// does an ICE restart is received from an ICE lite endpoint. Regression test
1166// for: https://crbug.com/710760
1167TEST_F(JsepTransportControllerTest,
1168 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1169 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001170 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001171 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1172 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1173 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001174 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001175 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1176 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1177 nullptr);
1178 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1179 // local side is the controlling.
1180 EXPECT_TRUE(transport_controller_
1181 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1182 .ok());
1183 EXPECT_TRUE(transport_controller_
1184 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1185 .ok());
1186 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1187 transport_controller_->GetDtlsTransport(kAudioMid1));
1188 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1189 fake_dtls->fake_ice_transport()->GetIceRole());
1190
1191 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001192 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001193 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1194 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1195 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001196 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001197 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1198 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1199 nullptr);
1200 EXPECT_TRUE(transport_controller_
1201 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1202 .ok());
1203 EXPECT_TRUE(transport_controller_
1204 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1205 .ok());
1206 fake_dtls = static_cast<FakeDtlsTransport*>(
1207 transport_controller_->GetDtlsTransport(kAudioMid1));
1208 // The local side is still the controlling role since the remote side is using
1209 // ICE-Lite.
1210 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1211 fake_dtls->fake_ice_transport()->GetIceRole());
1212}
1213
1214// Tests that the SDP has more than one audio/video m= sections.
1215TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1216 CreateJsepTransportController(JsepTransportController::Config());
1217 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1218 bundle_group.AddContentName(kAudioMid1);
1219 bundle_group.AddContentName(kAudioMid2);
1220 bundle_group.AddContentName(kVideoMid1);
1221 bundle_group.AddContentName(kDataMid1);
1222
Karl Wiberg918f50c2018-07-05 11:40:33 +02001223 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001224 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1225 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1226 nullptr);
1227 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1228 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1229 nullptr);
1230 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1231 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1232 nullptr);
1233 AddDataSection(local_offer.get(), kDataMid1,
1234 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1235 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1236 nullptr);
1237
Karl Wiberg918f50c2018-07-05 11:40:33 +02001238 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001239 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1240 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1241 nullptr);
1242 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1243 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1244 nullptr);
1245 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1246 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1247 nullptr);
1248 AddDataSection(remote_answer.get(), kDataMid1,
1249 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1250 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1251 nullptr);
1252
1253 local_offer->AddGroup(bundle_group);
1254 remote_answer->AddGroup(bundle_group);
1255
1256 EXPECT_TRUE(transport_controller_
1257 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1258 .ok());
1259 EXPECT_TRUE(transport_controller_
1260 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1261 .ok());
1262 // Verify that all the sections are bundled on kAudio1.
1263 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1264 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1265 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1266 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1267 EXPECT_EQ(transport1, transport2);
1268 EXPECT_EQ(transport1, transport3);
1269 EXPECT_EQ(transport1, transport4);
1270
1271 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1272 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1273 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1274 EXPECT_EQ(transport1, it->second);
1275 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1276 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1277 EXPECT_EQ(transport1, it->second);
1278 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1279 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1280 EXPECT_EQ(transport1, it->second);
1281 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1282 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1283 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1284 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1285}
1286
1287// Tests that only a subset of all the m= sections are bundled.
1288TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1289 CreateJsepTransportController(JsepTransportController::Config());
1290 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1291 bundle_group.AddContentName(kAudioMid1);
1292 bundle_group.AddContentName(kVideoMid1);
1293
Karl Wiberg918f50c2018-07-05 11:40:33 +02001294 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001295 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1296 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1297 nullptr);
1298 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1299 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1300 nullptr);
1301 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1302 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1303 nullptr);
1304
Karl Wiberg918f50c2018-07-05 11:40:33 +02001305 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001306 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1307 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1308 nullptr);
1309 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1310 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1311 nullptr);
1312 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1313 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1314 nullptr);
1315
1316 local_offer->AddGroup(bundle_group);
1317 remote_answer->AddGroup(bundle_group);
1318 EXPECT_TRUE(transport_controller_
1319 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1320 .ok());
1321 EXPECT_TRUE(transport_controller_
1322 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1323 .ok());
1324
1325 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1326 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1327 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1328 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1329 EXPECT_NE(transport1, transport2);
1330 EXPECT_EQ(transport1, transport3);
1331
1332 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1333 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1334 EXPECT_EQ(transport1, it->second);
1335 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001336 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001337}
1338
1339// Tests that the initial offer/answer only have data section and audio/video
1340// sections are added in the subsequent offer.
1341TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1342 CreateJsepTransportController(JsepTransportController::Config());
1343 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1344 bundle_group.AddContentName(kDataMid1);
1345
Karl Wiberg918f50c2018-07-05 11:40:33 +02001346 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001347 AddDataSection(local_offer.get(), kDataMid1,
1348 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1349 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1350 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001351 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001352 AddDataSection(remote_answer.get(), kDataMid1,
1353 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1354 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1355 nullptr);
1356 local_offer->AddGroup(bundle_group);
1357 remote_answer->AddGroup(bundle_group);
1358
1359 EXPECT_TRUE(transport_controller_
1360 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1361 .ok());
1362 EXPECT_TRUE(transport_controller_
1363 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1364 .ok());
1365 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1366
1367 // Add audio/video sections in subsequent offer.
1368 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1369 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1370 nullptr);
1371 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1372 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1373 nullptr);
1374 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1375 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1376 nullptr);
1377 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1378 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1379 nullptr);
1380
1381 // Reset the bundle group and do another offer/answer exchange.
1382 bundle_group.AddContentName(kAudioMid1);
1383 bundle_group.AddContentName(kVideoMid1);
1384 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1385 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1386 local_offer->AddGroup(bundle_group);
1387 remote_answer->AddGroup(bundle_group);
1388
1389 EXPECT_TRUE(transport_controller_
1390 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1391 .ok());
1392 EXPECT_TRUE(transport_controller_
1393 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1394 .ok());
1395
1396 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1397 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1398 EXPECT_EQ(data_transport, audio_transport);
1399 EXPECT_EQ(data_transport, video_transport);
1400}
1401
1402TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1403 CreateJsepTransportController(JsepTransportController::Config());
1404 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1405 bundle_group.AddContentName(kAudioMid1);
1406 bundle_group.AddContentName(kVideoMid1);
1407 bundle_group.AddContentName(kDataMid1);
1408
Karl Wiberg918f50c2018-07-05 11:40:33 +02001409 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001410 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1411 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1412 nullptr);
1413 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1414 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1415 nullptr);
1416 AddDataSection(local_offer.get(), kDataMid1,
1417 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1418 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1419 nullptr);
1420
Karl Wiberg918f50c2018-07-05 11:40:33 +02001421 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001422 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1423 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1424 nullptr);
1425 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1426 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1427 nullptr);
1428 AddDataSection(remote_answer.get(), kDataMid1,
1429 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1430 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1431 nullptr);
1432 // Reject video and data section.
1433 remote_answer->contents()[1].rejected = true;
1434 remote_answer->contents()[2].rejected = true;
1435
1436 local_offer->AddGroup(bundle_group);
1437 remote_answer->AddGroup(bundle_group);
1438
1439 EXPECT_TRUE(transport_controller_
1440 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1441 .ok());
1442 EXPECT_TRUE(transport_controller_
1443 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1444 .ok());
1445
1446 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1447 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1448 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1449 // Verify the signals are fired correctly.
1450 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1451 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1452 EXPECT_EQ(nullptr, it->second);
1453 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1454 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1455 EXPECT_EQ(nullptr, it2->second);
1456}
1457
1458// Tests that changing the bundled MID in subsequent offer/answer exchange is
1459// not supported.
1460// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1461// fixed
1462TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1463 CreateJsepTransportController(JsepTransportController::Config());
1464 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1465 bundle_group.AddContentName(kAudioMid1);
1466 bundle_group.AddContentName(kVideoMid1);
1467
Karl Wiberg918f50c2018-07-05 11:40:33 +02001468 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001469 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1470 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1471 nullptr);
1472 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1473 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1474 nullptr);
1475
Karl Wiberg918f50c2018-07-05 11:40:33 +02001476 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001477 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1478 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1479 nullptr);
1480 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1481 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1482 nullptr);
1483
1484 local_offer->AddGroup(bundle_group);
1485 remote_answer->AddGroup(bundle_group);
1486 EXPECT_TRUE(transport_controller_
1487 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1488 .ok());
1489 EXPECT_TRUE(transport_controller_
1490 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1491 .ok());
1492 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1493 transport_controller_->GetRtpTransport(kVideoMid1));
1494
1495 // Reorder the bundle group.
1496 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1497 bundle_group.AddContentName(kAudioMid1);
1498 // The answerer uses the new bundle group and now the bundle mid is changed to
1499 // |kVideo1|.
1500 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1501 remote_answer->AddGroup(bundle_group);
1502 EXPECT_TRUE(transport_controller_
1503 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1504 .ok());
1505 EXPECT_FALSE(transport_controller_
1506 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1507 .ok());
1508}
Zhi Huange830e682018-03-30 10:48:35 -07001509// Test that rejecting only the first m= section of a BUNDLE group is treated as
1510// an error, but rejecting all of them works as expected.
1511TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1512 CreateJsepTransportController(JsepTransportController::Config());
1513 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1514 bundle_group.AddContentName(kAudioMid1);
1515 bundle_group.AddContentName(kVideoMid1);
1516 bundle_group.AddContentName(kDataMid1);
1517
Karl Wiberg918f50c2018-07-05 11:40:33 +02001518 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001519 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1520 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1521 nullptr);
1522 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1523 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1524 nullptr);
1525 AddDataSection(local_offer.get(), kDataMid1,
1526 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1527 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1528 nullptr);
1529
Karl Wiberg918f50c2018-07-05 11:40:33 +02001530 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001531 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1532 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1533 nullptr);
1534 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1535 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1536 nullptr);
1537 AddDataSection(remote_answer.get(), kDataMid1,
1538 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1539 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1540 nullptr);
1541 // Reject audio content in answer.
1542 remote_answer->contents()[0].rejected = true;
1543
1544 local_offer->AddGroup(bundle_group);
1545 remote_answer->AddGroup(bundle_group);
1546
1547 EXPECT_TRUE(transport_controller_
1548 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1549 .ok());
1550 EXPECT_FALSE(transport_controller_
1551 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1552 .ok());
1553
1554 // Reject all the contents.
1555 remote_answer->contents()[1].rejected = true;
1556 remote_answer->contents()[2].rejected = true;
1557 EXPECT_TRUE(transport_controller_
1558 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1559 .ok());
1560 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1561 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1562 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1563}
1564
1565// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1566// is used.
1567TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1568 JsepTransportController::Config config;
1569 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1570 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001571 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001572 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1573 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1574 nullptr);
1575
1576 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1577 // Applying a non-RTCP-mux offer is expected to fail.
1578 EXPECT_FALSE(transport_controller_
1579 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1580 .ok());
1581}
1582
1583// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1584// is used.
1585TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1586 JsepTransportController::Config config;
1587 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1588 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001589 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001590 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1591 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1592 nullptr);
1593 EXPECT_TRUE(transport_controller_
1594 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1595 .ok());
1596
Karl Wiberg918f50c2018-07-05 11:40:33 +02001597 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001598 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1599 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1600 nullptr);
1601 // Applying a non-RTCP-mux answer is expected to fail.
1602 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1603 EXPECT_FALSE(transport_controller_
1604 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1605 .ok());
1606}
Zhi Huange818b6e2018-02-22 15:26:27 -08001607
Zhi Huangd2248f82018-04-10 14:41:03 -07001608// This tests that the BUNDLE group in answer should be a subset of the offered
1609// group.
1610TEST_F(JsepTransportControllerTest,
1611 AddContentToBundleGroupInAnswerNotSupported) {
1612 CreateJsepTransportController(JsepTransportController::Config());
1613 auto local_offer = CreateSessionDescriptionWithoutBundle();
1614 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1615
1616 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1617 offer_bundle_group.AddContentName(kAudioMid1);
1618 local_offer->AddGroup(offer_bundle_group);
1619
1620 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1621 answer_bundle_group.AddContentName(kAudioMid1);
1622 answer_bundle_group.AddContentName(kVideoMid1);
1623 remote_answer->AddGroup(answer_bundle_group);
1624 EXPECT_TRUE(transport_controller_
1625 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1626 .ok());
1627 EXPECT_FALSE(transport_controller_
1628 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1629 .ok());
1630}
1631
1632// This tests that the BUNDLE group with non-existing MID should be rejectd.
1633TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1634 CreateJsepTransportController(JsepTransportController::Config());
1635 auto local_offer = CreateSessionDescriptionWithoutBundle();
1636 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1637
1638 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1639 // The BUNDLE group is invalid because there is no data section in the
1640 // description.
1641 invalid_bundle_group.AddContentName(kDataMid1);
1642 local_offer->AddGroup(invalid_bundle_group);
1643 remote_answer->AddGroup(invalid_bundle_group);
1644
1645 EXPECT_FALSE(transport_controller_
1646 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1647 .ok());
1648 EXPECT_FALSE(transport_controller_
1649 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1650 .ok());
1651}
1652
1653// This tests that an answer shouldn't be able to remove an m= section from an
1654// established group without rejecting it.
1655TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1656 CreateJsepTransportController(JsepTransportController::Config());
1657
1658 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1659 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1660 EXPECT_TRUE(transport_controller_
1661 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1662 .ok());
1663 EXPECT_TRUE(transport_controller_
1664 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1665 .ok());
1666
1667 // Do an re-offer/answer.
1668 EXPECT_TRUE(transport_controller_
1669 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1670 .ok());
1671 auto new_answer = CreateSessionDescriptionWithoutBundle();
1672 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1673 // The answer removes video from the BUNDLE group without rejecting it is
1674 // invalid.
1675 new_bundle_group.AddContentName(kAudioMid1);
1676 new_answer->AddGroup(new_bundle_group);
1677
1678 // Applying invalid answer is expected to fail.
1679 EXPECT_FALSE(transport_controller_
1680 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1681 .ok());
1682
1683 // Rejected the video content.
1684 auto video_content = new_answer->GetContentByName(kVideoMid1);
1685 ASSERT_TRUE(video_content);
1686 video_content->rejected = true;
1687 EXPECT_TRUE(transport_controller_
1688 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1689 .ok());
1690}
1691
Zhi Huange818b6e2018-02-22 15:26:27 -08001692} // namespace webrtc