blob: 66532bed1f5592d9718560efc3fbfd742ae9e7cc [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
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -080014#include "api/media_transport_interface.h"
Anton Sukhanov7940da02018-10-10 10:34:49 -070015#include "api/test/fake_media_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080016#include "p2p/base/fakedtlstransport.h"
17#include "p2p/base/fakeicetransport.h"
18#include "p2p/base/transportfactoryinterface.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/jseptransportcontroller.h"
21#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080022#include "rtc_base/thread.h"
23#include "test/gtest.h"
24
25using cricket::FakeDtlsTransport;
26using cricket::Candidate;
27using cricket::Candidates;
28using webrtc::SdpType;
29
30static const int kTimeout = 100;
31static const char kIceUfrag1[] = "u0001";
32static const char kIcePwd1[] = "TESTICEPWD00000000000001";
33static const char kIceUfrag2[] = "u0002";
34static const char kIcePwd2[] = "TESTICEPWD00000000000002";
35static const char kIceUfrag3[] = "u0003";
36static const char kIcePwd3[] = "TESTICEPWD00000000000003";
37static const char kAudioMid1[] = "audio1";
38static const char kAudioMid2[] = "audio2";
39static const char kVideoMid1[] = "video1";
40static const char kVideoMid2[] = "video2";
41static const char kDataMid1[] = "data1";
42
43namespace webrtc {
44
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070045namespace {
46
47// Media transport factory requires crypto settings to be present in order to
48// create media transport.
49void AddCryptoSettings(cricket::SessionDescription* description) {
50 for (auto& content : description->contents()) {
51 content.media_description()->AddCrypto(cricket::CryptoParams(
52 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
53 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
54 }
55}
56
57} // namespace
58
Zhi Huange818b6e2018-02-22 15:26:27 -080059class FakeTransportFactory : public cricket::TransportFactoryInterface {
60 public:
61 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
62 const std::string& transport_name,
63 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020064 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
65 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080066 }
67
68 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
69 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070070 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 15:26:27 -080071 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
72 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 11:40:33 +020073 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080074 }
75};
76
Zhi Huang365381f2018-04-13 16:44:34 -070077class JsepTransportControllerTest : public JsepTransportController::Observer,
78 public testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080079 public sigslot::has_slots<> {
80 public:
81 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020082 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080083 }
84
85 void CreateJsepTransportController(
86 JsepTransportController::Config config,
87 rtc::Thread* signaling_thread = rtc::Thread::Current(),
88 rtc::Thread* network_thread = rtc::Thread::Current(),
89 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070090 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 15:26:27 -080091 // The tests only works with |fake_transport_factory|;
92 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070093 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 11:40:33 +020094 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070095 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080096 ConnectTransportControllerSignals();
97 }
98
99 void ConnectTransportControllerSignals() {
100 transport_controller_->SignalIceConnectionState.connect(
101 this, &JsepTransportControllerTest::OnConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200102 transport_controller_->SignalConnectionState.connect(
103 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800104 transport_controller_->SignalIceGatheringState.connect(
105 this, &JsepTransportControllerTest::OnGatheringState);
106 transport_controller_->SignalIceCandidatesGathered.connect(
107 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800108 }
109
110 std::unique_ptr<cricket::SessionDescription>
111 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200112 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800113 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
114 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
115 nullptr);
116 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
117 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
118 nullptr);
119 return description;
120 }
121
122 std::unique_ptr<cricket::SessionDescription>
123 CreateSessionDescriptionWithBundleGroup() {
124 auto description = CreateSessionDescriptionWithoutBundle();
125 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
126 bundle_group.AddContentName(kAudioMid1);
127 bundle_group.AddContentName(kVideoMid1);
128 description->AddGroup(bundle_group);
129
130 return description;
131 }
132
133 void AddAudioSection(cricket::SessionDescription* description,
134 const std::string& mid,
135 const std::string& ufrag,
136 const std::string& pwd,
137 cricket::IceMode ice_mode,
138 cricket::ConnectionRole conn_role,
139 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
140 std::unique_ptr<cricket::AudioContentDescription> audio(
141 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700142 // Set RTCP-mux to be true because the default policy is "mux required".
143 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800144 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
145 /*rejected=*/false, audio.release());
146 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
147 }
148
149 void AddVideoSection(cricket::SessionDescription* description,
150 const std::string& mid,
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::VideoContentDescription> video(
157 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700158 // Set RTCP-mux to be true because the default policy is "mux required".
159 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800160 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
161 /*rejected=*/false, video.release());
162 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
163 }
164
165 void AddDataSection(cricket::SessionDescription* description,
166 const std::string& mid,
167 cricket::MediaProtocolType protocol_type,
168 const std::string& ufrag,
169 const std::string& pwd,
170 cricket::IceMode ice_mode,
171 cricket::ConnectionRole conn_role,
172 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
173 std::unique_ptr<cricket::DataContentDescription> data(
174 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700175 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800176 description->AddContent(mid, protocol_type,
177 /*rejected=*/false, data.release());
178 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
179 }
180
181 void AddTransportInfo(cricket::SessionDescription* description,
182 const std::string& mid,
183 const std::string& ufrag,
184 const std::string& pwd,
185 cricket::IceMode ice_mode,
186 cricket::ConnectionRole conn_role,
187 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
188 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
189 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700190 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800191 }
192
193 cricket::TransportDescription transport_desc(std::vector<std::string>(),
194 ufrag, pwd, ice_mode,
195 conn_role, fingerprint.get());
196 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
197 }
198
199 cricket::IceConfig CreateIceConfig(
200 int receiving_timeout,
201 cricket::ContinualGatheringPolicy continual_gathering_policy) {
202 cricket::IceConfig config;
203 config.receiving_timeout = receiving_timeout;
204 config.continual_gathering_policy = continual_gathering_policy;
205 return config;
206 }
207
208 Candidate CreateCandidate(const std::string& transport_name, int component) {
209 Candidate c;
210 c.set_transport_name(transport_name);
211 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
212 c.set_component(component);
213 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
214 c.set_priority(1);
215 return c;
216 }
217
218 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
219 if (!network_thread_->IsCurrent()) {
220 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
221 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
222 });
223 return;
224 }
225
226 auto description = CreateSessionDescriptionWithBundleGroup();
227 EXPECT_TRUE(transport_controller_
228 ->SetLocalDescription(SdpType::kOffer, description.get())
229 .ok());
230
231 transport_controller_->MaybeStartGathering();
232 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
233 transport_controller_->GetDtlsTransport(kAudioMid1));
234 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
235 transport_controller_->GetDtlsTransport(kVideoMid1));
236 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
237 fake_audio_dtls->fake_ice_transport(),
238 CreateCandidate(kAudioMid1, /*component=*/1));
239 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
240 fake_video_dtls->fake_ice_transport(),
241 CreateCandidate(kVideoMid1, /*component=*/1));
242 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
243 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
244 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
245 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
246 fake_audio_dtls->SetReceiving(true);
247 fake_video_dtls->SetReceiving(true);
248 fake_audio_dtls->SetWritable(true);
249 fake_video_dtls->SetWritable(true);
250 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
251 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
252 }
253
254 protected:
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100255 void OnConnectionState(PeerConnectionInterface::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800256 if (!signaling_thread_->IsCurrent()) {
257 signaled_on_non_signaling_thread_ = true;
258 }
259 connection_state_ = state;
260 ++connection_state_signal_count_;
261 }
262
Jonas Olsson635474e2018-10-18 15:58:17 +0200263 void OnCombinedConnectionState(
264 PeerConnectionInterface::PeerConnectionState state) {
265 if (!signaling_thread_->IsCurrent()) {
266 signaled_on_non_signaling_thread_ = true;
267 }
268 combined_connection_state_ = state;
269 ++combined_connection_state_signal_count_;
270 }
271
Zhi Huange818b6e2018-02-22 15:26:27 -0800272 void OnGatheringState(cricket::IceGatheringState state) {
273 if (!signaling_thread_->IsCurrent()) {
274 signaled_on_non_signaling_thread_ = true;
275 }
276 gathering_state_ = state;
277 ++gathering_state_signal_count_;
278 }
279
280 void OnCandidatesGathered(const std::string& transport_name,
281 const Candidates& candidates) {
282 if (!signaling_thread_->IsCurrent()) {
283 signaled_on_non_signaling_thread_ = true;
284 }
285 candidates_[transport_name].insert(candidates_[transport_name].end(),
286 candidates.begin(), candidates.end());
287 ++candidates_signal_count_;
288 }
289
Zhi Huang365381f2018-04-13 16:44:34 -0700290 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800291 bool OnTransportChanged(const std::string& mid,
292 RtpTransportInternal* rtp_transport,
293 cricket::DtlsTransportInternal* dtls_transport,
294 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700295 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800296 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800297 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700298 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800299 }
300
301 // Information received from signals from transport controller.
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100302 PeerConnectionInterface::IceConnectionState connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200303 PeerConnectionInterface::kIceConnectionNew;
304 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
305 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800306 bool receiving_ = false;
307 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
308 // transport_name => candidates
309 std::map<std::string, Candidates> candidates_;
310 // Counts of each signal emitted.
311 int connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200312 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800313 int receiving_signal_count_ = 0;
314 int gathering_state_signal_count_ = 0;
315 int candidates_signal_count_ = 0;
316
317 // |network_thread_| should be destroyed after |transport_controller_|
318 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800319 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
320 rtc::Thread* const signaling_thread_ = nullptr;
321 bool signaled_on_non_signaling_thread_ = false;
322 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
323 // signaled correctly.
324 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
325 std::map<std::string, cricket::DtlsTransportInternal*>
326 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800327 std::map<std::string, MediaTransportInterface*>
328 changed_media_transport_by_mid_;
329
330 // Transport controller needs to be destroyed first, because it may issue
331 // callbacks that modify the changed_*_by_mid in the destructor.
332 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800333};
334
335TEST_F(JsepTransportControllerTest, GetRtpTransport) {
336 CreateJsepTransportController(JsepTransportController::Config());
337 auto description = CreateSessionDescriptionWithoutBundle();
338 EXPECT_TRUE(transport_controller_
339 ->SetLocalDescription(SdpType::kOffer, description.get())
340 .ok());
341 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
342 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
343 EXPECT_NE(nullptr, audio_rtp_transport);
344 EXPECT_NE(nullptr, video_rtp_transport);
345 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
346 // Return nullptr for non-existing ones.
347 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
348}
349
350TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
351 JsepTransportController::Config config;
352 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
353 CreateJsepTransportController(config);
354 auto description = CreateSessionDescriptionWithoutBundle();
355 EXPECT_TRUE(transport_controller_
356 ->SetLocalDescription(SdpType::kOffer, description.get())
357 .ok());
358 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
359 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
360 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
361 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
362 // Return nullptr for non-existing ones.
363 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
364 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
365}
366
Zhi Huange830e682018-03-30 10:48:35 -0700367TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
368 JsepTransportController::Config config;
369 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
370 CreateJsepTransportController(config);
371 auto description = CreateSessionDescriptionWithoutBundle();
372 EXPECT_TRUE(transport_controller_
373 ->SetLocalDescription(SdpType::kOffer, description.get())
374 .ok());
375 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
376 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
377 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
378 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700379 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
380}
381
382TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
383 FakeMediaTransportFactory fake_media_transport_factory;
384 JsepTransportController::Config config;
385
386 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
387 config.media_transport_factory = &fake_media_transport_factory;
388 CreateJsepTransportController(config);
389 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700390 AddCryptoSettings(description.get());
391
Anton Sukhanov7940da02018-10-10 10:34:49 -0700392 EXPECT_TRUE(transport_controller_
393 ->SetLocalDescription(SdpType::kOffer, description.get())
394 .ok());
395
396 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
397 transport_controller_->GetMediaTransport(kAudioMid1));
398
399 ASSERT_NE(nullptr, media_transport);
400
401 // After SetLocalDescription, media transport should be created as caller.
402 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700403 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700404
405 // Return nullptr for non-existing mids.
406 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
407}
408
409TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
410 FakeMediaTransportFactory fake_media_transport_factory;
411 JsepTransportController::Config config;
412
413 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
414 config.media_transport_factory = &fake_media_transport_factory;
415 CreateJsepTransportController(config);
416 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700417 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700418 EXPECT_TRUE(transport_controller_
419 ->SetRemoteDescription(SdpType::kOffer, description.get())
420 .ok());
421
422 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
423 transport_controller_->GetMediaTransport(kAudioMid1));
424
425 ASSERT_NE(nullptr, media_transport);
426
427 // After SetRemoteDescription, media transport should be created as callee.
428 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700429 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700430
431 // Return nullptr for non-existing mids.
432 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 10:48:35 -0700433}
434
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700435TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
436 FakeMediaTransportFactory fake_media_transport_factory;
437 JsepTransportController::Config config;
438
439 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
440 config.media_transport_factory = &fake_media_transport_factory;
441 CreateJsepTransportController(config);
442 auto description = CreateSessionDescriptionWithoutBundle();
443 EXPECT_TRUE(transport_controller_
444 ->SetRemoteDescription(SdpType::kOffer, description.get())
445 .ok());
446
447 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
448
449 // Even if we set local description with crypto now (after the remote offer
450 // was set), media transport won't be provided.
451 auto description2 = CreateSessionDescriptionWithoutBundle();
452 AddCryptoSettings(description2.get());
453 EXPECT_TRUE(transport_controller_
454 ->SetLocalDescription(SdpType::kAnswer, description2.get())
455 .ok());
456
457 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
458}
459
460TEST_F(JsepTransportControllerTest,
461 AfterSettingAnswerTheSameMediaTransportIsReturned) {
462 FakeMediaTransportFactory fake_media_transport_factory;
463 JsepTransportController::Config config;
464
465 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
466 config.media_transport_factory = &fake_media_transport_factory;
467 CreateJsepTransportController(config);
468 auto description = CreateSessionDescriptionWithoutBundle();
469 AddCryptoSettings(description.get());
470 EXPECT_TRUE(transport_controller_
471 ->SetRemoteDescription(SdpType::kOffer, description.get())
472 .ok());
473
474 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
475 transport_controller_->GetMediaTransport(kAudioMid1));
476 EXPECT_NE(nullptr, media_transport);
477 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
478
479 // Even if we set local description with crypto now (after the remote offer
480 // was set), media transport won't be provided.
481 auto description2 = CreateSessionDescriptionWithoutBundle();
482 AddCryptoSettings(description2.get());
483
484 RTCError result = transport_controller_->SetLocalDescription(
485 SdpType::kAnswer, description2.get());
486 EXPECT_TRUE(result.ok()) << result.message();
487
488 // Media transport did not change.
489 EXPECT_EQ(media_transport,
490 transport_controller_->GetMediaTransport(kAudioMid1));
491}
492
Zhi Huange818b6e2018-02-22 15:26:27 -0800493TEST_F(JsepTransportControllerTest, SetIceConfig) {
494 CreateJsepTransportController(JsepTransportController::Config());
495 auto description = CreateSessionDescriptionWithoutBundle();
496 EXPECT_TRUE(transport_controller_
497 ->SetLocalDescription(SdpType::kOffer, description.get())
498 .ok());
499
500 transport_controller_->SetIceConfig(
501 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
502 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
503 transport_controller_->GetDtlsTransport(kAudioMid1));
504 ASSERT_NE(nullptr, fake_audio_dtls);
505 EXPECT_EQ(kTimeout,
506 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
507 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
508
509 // Test that value stored in controller is applied to new transports.
510 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
511 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
512 nullptr);
513
514 EXPECT_TRUE(transport_controller_
515 ->SetLocalDescription(SdpType::kOffer, description.get())
516 .ok());
517 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
518 transport_controller_->GetDtlsTransport(kAudioMid2));
519 ASSERT_NE(nullptr, fake_audio_dtls);
520 EXPECT_EQ(kTimeout,
521 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
522 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
523}
524
525// Tests the getter and setter of the ICE restart flag.
526TEST_F(JsepTransportControllerTest, NeedIceRestart) {
527 CreateJsepTransportController(JsepTransportController::Config());
528 auto description = CreateSessionDescriptionWithoutBundle();
529 EXPECT_TRUE(transport_controller_
530 ->SetLocalDescription(SdpType::kOffer, description.get())
531 .ok());
532 EXPECT_TRUE(transport_controller_
533 ->SetRemoteDescription(SdpType::kAnswer, description.get())
534 .ok());
535
536 // Initially NeedsIceRestart should return false.
537 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
538 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
539 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
540 // true.
541 transport_controller_->SetNeedsIceRestartFlag();
542 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
543 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
544 // For a nonexistent transport, false should be returned.
545 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
546
547 // Reset the ice_ufrag/ice_pwd for audio.
548 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
549 audio_transport_info->description.ice_ufrag = kIceUfrag2;
550 audio_transport_info->description.ice_pwd = kIcePwd2;
551 EXPECT_TRUE(transport_controller_
552 ->SetLocalDescription(SdpType::kOffer, description.get())
553 .ok());
554 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
555 // return false for audio and true for video.
556 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
557 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
558}
559
560TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
561 CreateJsepTransportController(JsepTransportController::Config());
562 auto description = CreateSessionDescriptionWithBundleGroup();
563 EXPECT_TRUE(transport_controller_
564 ->SetLocalDescription(SdpType::kOffer, description.get())
565 .ok());
566 // After setting the local description, we should be able to start gathering
567 // candidates.
568 transport_controller_->MaybeStartGathering();
569 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
570 EXPECT_EQ(1, gathering_state_signal_count_);
571}
572
573TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
574 CreateJsepTransportController(JsepTransportController::Config());
575 auto description = CreateSessionDescriptionWithoutBundle();
576 transport_controller_->SetLocalDescription(SdpType::kOffer,
577 description.get());
578 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
579 description.get());
580 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
581 transport_controller_->GetDtlsTransport(kAudioMid1));
582 ASSERT_NE(nullptr, fake_audio_dtls);
583 Candidates candidates;
584 candidates.push_back(
585 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
586 EXPECT_TRUE(
587 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
588 EXPECT_EQ(1U,
589 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
590
591 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
592 EXPECT_EQ(0U,
593 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
594}
595
596TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
597 CreateJsepTransportController(JsepTransportController::Config());
598
599 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
600 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
601 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
602 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
603
Karl Wiberg918f50c2018-07-05 11:40:33 +0200604 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800605 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
606 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
607 certificate1);
608
609 // Apply the local certificate.
610 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
611 // Apply the local description.
612 EXPECT_TRUE(transport_controller_
613 ->SetLocalDescription(SdpType::kOffer, description.get())
614 .ok());
615 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
616 EXPECT_TRUE(returned_certificate);
617 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
618 returned_certificate->identity()->certificate().ToPEMString());
619
620 // Should fail if called for a nonexistant transport.
621 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
622
623 // Shouldn't be able to change the identity once set.
624 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
625 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
626 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
627 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
628}
629
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800630TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800631 CreateJsepTransportController(JsepTransportController::Config());
632 auto description = CreateSessionDescriptionWithBundleGroup();
633 EXPECT_TRUE(transport_controller_
634 ->SetLocalDescription(SdpType::kOffer, description.get())
635 .ok());
636 rtc::FakeSSLCertificate fake_certificate("fake_data");
637
638 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
639 transport_controller_->GetDtlsTransport(kAudioMid1));
640 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800641 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
642 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
643 ASSERT_TRUE(returned_cert_chain);
644 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800645 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800646 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800647
648 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800649 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800650}
651
652TEST_F(JsepTransportControllerTest, GetDtlsRole) {
653 CreateJsepTransportController(JsepTransportController::Config());
654 auto offer_certificate =
655 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
656 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
657 auto answer_certificate =
658 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
659 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
660 transport_controller_->SetLocalCertificate(offer_certificate);
661
Karl Wiberg918f50c2018-07-05 11:40:33 +0200662 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800663 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
664 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
665 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200666 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800667 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
668 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
669 answer_certificate);
670
671 EXPECT_TRUE(transport_controller_
672 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
673 .ok());
674
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200675 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800676 transport_controller_->GetDtlsRole(kAudioMid1);
677 // The DTLS role is not decided yet.
678 EXPECT_FALSE(role);
679 EXPECT_TRUE(transport_controller_
680 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
681 .ok());
682 role = transport_controller_->GetDtlsRole(kAudioMid1);
683
684 ASSERT_TRUE(role);
685 EXPECT_EQ(rtc::SSL_CLIENT, *role);
686}
687
688TEST_F(JsepTransportControllerTest, GetStats) {
689 CreateJsepTransportController(JsepTransportController::Config());
690 auto description = CreateSessionDescriptionWithBundleGroup();
691 EXPECT_TRUE(transport_controller_
692 ->SetLocalDescription(SdpType::kOffer, description.get())
693 .ok());
694
695 cricket::TransportStats stats;
696 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
697 EXPECT_EQ(kAudioMid1, stats.transport_name);
698 EXPECT_EQ(1u, stats.channel_stats.size());
699 // Return false for non-existing transport.
700 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
701}
702
703TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
704 CreateJsepTransportController(JsepTransportController::Config());
705 auto description = CreateSessionDescriptionWithoutBundle();
706 EXPECT_TRUE(transport_controller_
707 ->SetLocalDescription(SdpType::kOffer, description.get())
708 .ok());
709
710 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
711 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
712 fake_ice->SetCandidatesGatheringComplete();
713 fake_ice->SetConnectionCount(1);
714 // The connection stats will be failed if there is no active connection.
715 fake_ice->SetConnectionCount(0);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100716 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100717 connection_state_, kTimeout);
718 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100719 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
720 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200721 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800722}
723
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700724TEST_F(JsepTransportControllerTest,
725 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800726 CreateJsepTransportController(JsepTransportController::Config());
727 auto description = CreateSessionDescriptionWithoutBundle();
728 EXPECT_TRUE(transport_controller_
729 ->SetLocalDescription(SdpType::kOffer, description.get())
730 .ok());
731
732 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
733 transport_controller_->GetDtlsTransport(kAudioMid1));
734 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
735 transport_controller_->GetDtlsTransport(kVideoMid1));
736
737 // First, have one transport connect, and another fail, to ensure that
738 // the first transport connecting didn't trigger a "connected" state signal.
739 // We should only get a signal when all are connected.
740 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
741 fake_audio_dtls->SetWritable(true);
742 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
743 // Decrease the number of the connection to trigger the signal.
744 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
745 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
746 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
747
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100748 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100749 connection_state_, kTimeout);
750 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100751 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
752 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200753 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800754
Jonas Olsson635474e2018-10-18 15:58:17 +0200755 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
756 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800757 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
758 // the transport state to be STATE_CONNECTING.
759 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
760 fake_video_dtls->SetWritable(true);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100761 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100762 connection_state_, kTimeout);
763 EXPECT_EQ(2, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100764 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
765 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200766 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800767}
768
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700769TEST_F(JsepTransportControllerTest,
770 SignalConnectionStateConnectedWithMediaTransport) {
771 FakeMediaTransportFactory fake_media_transport_factory;
772 JsepTransportController::Config config;
773 config.media_transport_factory = &fake_media_transport_factory;
774 CreateJsepTransportController(config);
775 auto description = CreateSessionDescriptionWithoutBundle();
776 AddCryptoSettings(description.get());
777 EXPECT_TRUE(transport_controller_
778 ->SetLocalDescription(SdpType::kOffer, description.get())
779 .ok());
780
781 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
782 transport_controller_->GetDtlsTransport(kAudioMid1));
783 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
784 transport_controller_->GetDtlsTransport(kVideoMid1));
785 fake_audio_dtls->SetWritable(true);
786 fake_video_dtls->SetWritable(true);
787 // Decreasing connection count from 2 to 1 triggers connection state event.
788 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
789 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
790 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
791 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
792 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
793 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
794
795 // Still not connected, because we are waiting for media transport.
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100796 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
797 combined_connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700798
799 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
800 transport_controller_->GetMediaTransport(kAudioMid1));
801
802 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100803 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
804 combined_connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700805
806 // Still waiting for the second media transport.
807 media_transport = static_cast<FakeMediaTransport*>(
808 transport_controller_->GetMediaTransport(kVideoMid1));
809 media_transport->SetState(webrtc::MediaTransportState::kWritable);
810
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100811 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
812 combined_connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700813}
814
815TEST_F(JsepTransportControllerTest,
816 SignalConnectionStateFailedWhenMediaTransportClosed) {
817 FakeMediaTransportFactory fake_media_transport_factory;
818 JsepTransportController::Config config;
819 config.media_transport_factory = &fake_media_transport_factory;
820 CreateJsepTransportController(config);
821 auto description = CreateSessionDescriptionWithoutBundle();
822 AddCryptoSettings(description.get());
823 EXPECT_TRUE(transport_controller_
824 ->SetLocalDescription(SdpType::kOffer, description.get())
825 .ok());
826
827 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
828 transport_controller_->GetDtlsTransport(kAudioMid1));
829 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
830 transport_controller_->GetDtlsTransport(kVideoMid1));
831 fake_audio_dtls->SetWritable(true);
832 fake_video_dtls->SetWritable(true);
833 // Decreasing connection count from 2 to 1 triggers connection state event.
834 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
835 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
836 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
837 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
838 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
839 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
840
841 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
842 transport_controller_->GetMediaTransport(kAudioMid1));
843
844 media_transport->SetState(webrtc::MediaTransportState::kWritable);
845
846 media_transport = static_cast<FakeMediaTransport*>(
847 transport_controller_->GetMediaTransport(kVideoMid1));
848
849 media_transport->SetState(webrtc::MediaTransportState::kWritable);
850
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100851 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
852 combined_connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700853
854 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100855 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
856 combined_connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700857}
858
Zhi Huange818b6e2018-02-22 15:26:27 -0800859TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
860 CreateJsepTransportController(JsepTransportController::Config());
861 auto description = CreateSessionDescriptionWithoutBundle();
862 EXPECT_TRUE(transport_controller_
863 ->SetLocalDescription(SdpType::kOffer, description.get())
864 .ok());
865
866 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
867 transport_controller_->GetDtlsTransport(kAudioMid1));
868 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
869 transport_controller_->GetDtlsTransport(kVideoMid1));
870
871 // First, have one transport connect, and another fail, to ensure that
872 // the first transport connecting didn't trigger a "connected" state signal.
873 // We should only get a signal when all are connected.
874 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
875 fake_audio_dtls->SetWritable(true);
876 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
877 // Decrease the number of the connection to trigger the signal.
878 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
879 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
880 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
881
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100882 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100883 connection_state_, kTimeout);
884 EXPECT_EQ(1, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100885 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
886 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200887 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800888
Jonas Olsson635474e2018-10-18 15:58:17 +0200889 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
890 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800891 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
892 // the transport state to be STATE_COMPLETED.
893 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
894 fake_video_dtls->SetWritable(true);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100895 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100896 connection_state_, kTimeout);
897 EXPECT_EQ(2, connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100898 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
899 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200900 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800901}
902
903TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
904 CreateJsepTransportController(JsepTransportController::Config());
905 auto description = CreateSessionDescriptionWithoutBundle();
906 EXPECT_TRUE(transport_controller_
907 ->SetLocalDescription(SdpType::kOffer, description.get())
908 .ok());
909
910 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
911 transport_controller_->GetDtlsTransport(kAudioMid1));
912 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
913 // Should be in the gathering state as soon as any transport starts gathering.
914 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
915 EXPECT_EQ(1, gathering_state_signal_count_);
916}
917
918TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
919 CreateJsepTransportController(JsepTransportController::Config());
920 auto description = CreateSessionDescriptionWithoutBundle();
921 EXPECT_TRUE(transport_controller_
922 ->SetLocalDescription(SdpType::kOffer, description.get())
923 .ok());
924
925 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
926 transport_controller_->GetDtlsTransport(kAudioMid1));
927 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
928 transport_controller_->GetDtlsTransport(kVideoMid1));
929
930 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
931 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
932 EXPECT_EQ(1, gathering_state_signal_count_);
933
934 // Have one transport finish gathering, to make sure gathering
935 // completion wasn't signalled if only one transport finished gathering.
936 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
937 EXPECT_EQ(1, gathering_state_signal_count_);
938
939 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
940 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
941 EXPECT_EQ(1, gathering_state_signal_count_);
942
943 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
944 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
945 EXPECT_EQ(2, gathering_state_signal_count_);
946}
947
948// Test that when the last transport that hasn't finished connecting and/or
949// gathering is destroyed, the aggregate state jumps to "completed". This can
950// happen if, for example, we have an audio and video transport, the audio
951// transport completes, then we start bundling video on the audio transport.
952TEST_F(JsepTransportControllerTest,
953 SignalingWhenLastIncompleteTransportDestroyed) {
954 CreateJsepTransportController(JsepTransportController::Config());
955 auto description = CreateSessionDescriptionWithBundleGroup();
956 EXPECT_TRUE(transport_controller_
957 ->SetLocalDescription(SdpType::kOffer, description.get())
958 .ok());
959
960 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
961 transport_controller_->GetDtlsTransport(kAudioMid1));
962 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
963 transport_controller_->GetDtlsTransport(kVideoMid1));
964 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
965
966 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
967 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
968 EXPECT_EQ(1, gathering_state_signal_count_);
969
970 // Let the audio transport complete.
971 fake_audio_dtls->SetWritable(true);
972 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
973 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +0200974 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800975 EXPECT_EQ(1, gathering_state_signal_count_);
976
977 // Set the remote description and enable the bundle.
978 EXPECT_TRUE(transport_controller_
979 ->SetRemoteDescription(SdpType::kAnswer, description.get())
980 .ok());
981 // The BUNDLE should be enabled, the incomplete video transport should be
982 // deleted and the states shoud be updated.
983 fake_video_dtls = static_cast<FakeDtlsTransport*>(
984 transport_controller_->GetDtlsTransport(kVideoMid1));
985 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100986 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
987 connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200988 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
989 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800990 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
991 EXPECT_EQ(2, gathering_state_signal_count_);
992}
993
994TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
995 CreateJsepTransportController(JsepTransportController::Config());
996 auto description = CreateSessionDescriptionWithBundleGroup();
997 EXPECT_TRUE(transport_controller_
998 ->SetLocalDescription(SdpType::kOffer, description.get())
999 .ok());
1000 transport_controller_->MaybeStartGathering();
1001
1002 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1003 transport_controller_->GetDtlsTransport(kAudioMid1));
1004 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1005 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1006 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1007 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1008}
1009
1010TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1011 network_thread_ = rtc::Thread::CreateWithSocketServer();
1012 network_thread_->Start();
1013 CreateJsepTransportController(JsepTransportController::Config(),
1014 signaling_thread_, network_thread_.get(),
1015 /*PortAllocator=*/nullptr);
1016 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1017
1018 // connecting --> connected --> completed
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001019 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1020 connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001021 EXPECT_EQ(2, connection_state_signal_count_);
1022
1023 // new --> gathering --> complete
1024 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1025 EXPECT_EQ(2, gathering_state_signal_count_);
1026
1027 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1028 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1029 EXPECT_EQ(2, candidates_signal_count_);
1030
1031 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1032}
1033
1034// Older versions of Chrome expect the ICE role to be re-determined when an
1035// ICE restart occurs, and also don't perform conflict resolution correctly,
1036// so for now we can't safely stop doing this.
1037// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1038// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1039// enough population.
1040TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1041 CreateJsepTransportController(JsepTransportController::Config());
1042 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001043 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001044 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1045 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1046 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001047 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001048 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1049 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1050 nullptr);
1051
1052 EXPECT_TRUE(transport_controller_
1053 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1054 .ok());
1055 EXPECT_TRUE(transport_controller_
1056 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1057 .ok());
1058
1059 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1060 transport_controller_->GetDtlsTransport(kAudioMid1));
1061 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1062 fake_dtls->fake_ice_transport()->GetIceRole());
1063
1064 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001065 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001066 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1067 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1068 nullptr);
1069 EXPECT_TRUE(
1070 transport_controller_
1071 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1072 .ok());
1073 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1074 fake_dtls->fake_ice_transport()->GetIceRole());
1075}
1076
1077// Test that if the TransportController was created with the
1078// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1079// redetermined on an ICE restart.
1080TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1081 JsepTransportController::Config config;
1082 config.redetermine_role_on_ice_restart = false;
1083
1084 CreateJsepTransportController(config);
1085 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001086 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001087 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1088 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1089 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001090 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001091 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1092 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1093 nullptr);
1094
1095 EXPECT_TRUE(transport_controller_
1096 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1097 .ok());
1098 EXPECT_TRUE(transport_controller_
1099 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1100 .ok());
1101
1102 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1103 transport_controller_->GetDtlsTransport(kAudioMid1));
1104 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1105 fake_dtls->fake_ice_transport()->GetIceRole());
1106
1107 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001108 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001109 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1110 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1111 nullptr);
1112 EXPECT_TRUE(
1113 transport_controller_
1114 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1115 .ok());
1116 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1117 fake_dtls->fake_ice_transport()->GetIceRole());
1118}
1119
1120// Tests ICE-Lite mode in remote answer.
1121TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1122 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001123 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001124 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1125 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1126 nullptr);
1127 EXPECT_TRUE(transport_controller_
1128 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1129 .ok());
1130 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1131 transport_controller_->GetDtlsTransport(kAudioMid1));
1132 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1133 fake_dtls->fake_ice_transport()->GetIceRole());
1134 EXPECT_EQ(cricket::ICEMODE_FULL,
1135 fake_dtls->fake_ice_transport()->remote_ice_mode());
1136
Karl Wiberg918f50c2018-07-05 11:40:33 +02001137 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001138 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1139 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1140 nullptr);
1141 EXPECT_TRUE(transport_controller_
1142 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1143 .ok());
1144 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1145 fake_dtls->fake_ice_transport()->GetIceRole());
1146 EXPECT_EQ(cricket::ICEMODE_LITE,
1147 fake_dtls->fake_ice_transport()->remote_ice_mode());
1148}
1149
1150// Tests that the ICE role remains "controlling" if a subsequent offer that
1151// does an ICE restart is received from an ICE lite endpoint. Regression test
1152// for: https://crbug.com/710760
1153TEST_F(JsepTransportControllerTest,
1154 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1155 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001156 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001157 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1158 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1159 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001160 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001161 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1162 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1163 nullptr);
1164 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1165 // local side is the controlling.
1166 EXPECT_TRUE(transport_controller_
1167 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1168 .ok());
1169 EXPECT_TRUE(transport_controller_
1170 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1171 .ok());
1172 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1173 transport_controller_->GetDtlsTransport(kAudioMid1));
1174 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1175 fake_dtls->fake_ice_transport()->GetIceRole());
1176
1177 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001178 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001179 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1180 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1181 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001182 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001183 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1184 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1185 nullptr);
1186 EXPECT_TRUE(transport_controller_
1187 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1188 .ok());
1189 EXPECT_TRUE(transport_controller_
1190 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1191 .ok());
1192 fake_dtls = static_cast<FakeDtlsTransport*>(
1193 transport_controller_->GetDtlsTransport(kAudioMid1));
1194 // The local side is still the controlling role since the remote side is using
1195 // ICE-Lite.
1196 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1197 fake_dtls->fake_ice_transport()->GetIceRole());
1198}
1199
1200// Tests that the SDP has more than one audio/video m= sections.
1201TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1202 CreateJsepTransportController(JsepTransportController::Config());
1203 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1204 bundle_group.AddContentName(kAudioMid1);
1205 bundle_group.AddContentName(kAudioMid2);
1206 bundle_group.AddContentName(kVideoMid1);
1207 bundle_group.AddContentName(kDataMid1);
1208
Karl Wiberg918f50c2018-07-05 11:40:33 +02001209 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001210 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1211 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1212 nullptr);
1213 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1214 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1215 nullptr);
1216 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1217 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1218 nullptr);
1219 AddDataSection(local_offer.get(), kDataMid1,
1220 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1221 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1222 nullptr);
1223
Karl Wiberg918f50c2018-07-05 11:40:33 +02001224 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001225 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1226 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1227 nullptr);
1228 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1229 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1230 nullptr);
1231 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1232 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1233 nullptr);
1234 AddDataSection(remote_answer.get(), kDataMid1,
1235 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1236 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1237 nullptr);
1238
1239 local_offer->AddGroup(bundle_group);
1240 remote_answer->AddGroup(bundle_group);
1241
1242 EXPECT_TRUE(transport_controller_
1243 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1244 .ok());
1245 EXPECT_TRUE(transport_controller_
1246 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1247 .ok());
1248 // Verify that all the sections are bundled on kAudio1.
1249 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1250 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1251 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1252 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1253 EXPECT_EQ(transport1, transport2);
1254 EXPECT_EQ(transport1, transport3);
1255 EXPECT_EQ(transport1, transport4);
1256
1257 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1258 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1259 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1260 EXPECT_EQ(transport1, it->second);
1261 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1262 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1263 EXPECT_EQ(transport1, it->second);
1264 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1265 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1266 EXPECT_EQ(transport1, it->second);
1267 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1268 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1269 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1270 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1271}
1272
1273// Tests that only a subset of all the m= sections are bundled.
1274TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1275 CreateJsepTransportController(JsepTransportController::Config());
1276 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1277 bundle_group.AddContentName(kAudioMid1);
1278 bundle_group.AddContentName(kVideoMid1);
1279
Karl Wiberg918f50c2018-07-05 11:40:33 +02001280 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001281 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1282 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1283 nullptr);
1284 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1285 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1286 nullptr);
1287 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1288 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1289 nullptr);
1290
Karl Wiberg918f50c2018-07-05 11:40:33 +02001291 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001292 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1293 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1294 nullptr);
1295 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1296 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1297 nullptr);
1298 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1299 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1300 nullptr);
1301
1302 local_offer->AddGroup(bundle_group);
1303 remote_answer->AddGroup(bundle_group);
1304 EXPECT_TRUE(transport_controller_
1305 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1306 .ok());
1307 EXPECT_TRUE(transport_controller_
1308 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1309 .ok());
1310
1311 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1312 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1313 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1314 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1315 EXPECT_NE(transport1, transport2);
1316 EXPECT_EQ(transport1, transport3);
1317
1318 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1319 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1320 EXPECT_EQ(transport1, it->second);
1321 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001322 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001323}
1324
1325// Tests that the initial offer/answer only have data section and audio/video
1326// sections are added in the subsequent offer.
1327TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1328 CreateJsepTransportController(JsepTransportController::Config());
1329 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1330 bundle_group.AddContentName(kDataMid1);
1331
Karl Wiberg918f50c2018-07-05 11:40:33 +02001332 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001333 AddDataSection(local_offer.get(), kDataMid1,
1334 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1335 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1336 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001337 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001338 AddDataSection(remote_answer.get(), kDataMid1,
1339 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1340 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1341 nullptr);
1342 local_offer->AddGroup(bundle_group);
1343 remote_answer->AddGroup(bundle_group);
1344
1345 EXPECT_TRUE(transport_controller_
1346 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1347 .ok());
1348 EXPECT_TRUE(transport_controller_
1349 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1350 .ok());
1351 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1352
1353 // Add audio/video sections in subsequent offer.
1354 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1355 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1356 nullptr);
1357 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1358 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1359 nullptr);
1360 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1361 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1362 nullptr);
1363 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1364 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1365 nullptr);
1366
1367 // Reset the bundle group and do another offer/answer exchange.
1368 bundle_group.AddContentName(kAudioMid1);
1369 bundle_group.AddContentName(kVideoMid1);
1370 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1371 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1372 local_offer->AddGroup(bundle_group);
1373 remote_answer->AddGroup(bundle_group);
1374
1375 EXPECT_TRUE(transport_controller_
1376 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1377 .ok());
1378 EXPECT_TRUE(transport_controller_
1379 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1380 .ok());
1381
1382 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1383 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1384 EXPECT_EQ(data_transport, audio_transport);
1385 EXPECT_EQ(data_transport, video_transport);
1386}
1387
1388TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1389 CreateJsepTransportController(JsepTransportController::Config());
1390 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1391 bundle_group.AddContentName(kAudioMid1);
1392 bundle_group.AddContentName(kVideoMid1);
1393 bundle_group.AddContentName(kDataMid1);
1394
Karl Wiberg918f50c2018-07-05 11:40:33 +02001395 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001396 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1397 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1398 nullptr);
1399 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1400 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1401 nullptr);
1402 AddDataSection(local_offer.get(), kDataMid1,
1403 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1404 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1405 nullptr);
1406
Karl Wiberg918f50c2018-07-05 11:40:33 +02001407 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001408 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1409 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1410 nullptr);
1411 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1412 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1413 nullptr);
1414 AddDataSection(remote_answer.get(), kDataMid1,
1415 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1416 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1417 nullptr);
1418 // Reject video and data section.
1419 remote_answer->contents()[1].rejected = true;
1420 remote_answer->contents()[2].rejected = true;
1421
1422 local_offer->AddGroup(bundle_group);
1423 remote_answer->AddGroup(bundle_group);
1424
1425 EXPECT_TRUE(transport_controller_
1426 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1427 .ok());
1428 EXPECT_TRUE(transport_controller_
1429 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1430 .ok());
1431
1432 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1433 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1434 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1435 // Verify the signals are fired correctly.
1436 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1437 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1438 EXPECT_EQ(nullptr, it->second);
1439 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1440 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1441 EXPECT_EQ(nullptr, it2->second);
1442}
1443
1444// Tests that changing the bundled MID in subsequent offer/answer exchange is
1445// not supported.
1446// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1447// fixed
1448TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1449 CreateJsepTransportController(JsepTransportController::Config());
1450 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1451 bundle_group.AddContentName(kAudioMid1);
1452 bundle_group.AddContentName(kVideoMid1);
1453
Karl Wiberg918f50c2018-07-05 11:40:33 +02001454 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001455 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1456 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1457 nullptr);
1458 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1459 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1460 nullptr);
1461
Karl Wiberg918f50c2018-07-05 11:40:33 +02001462 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001463 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1464 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1465 nullptr);
1466 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1467 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1468 nullptr);
1469
1470 local_offer->AddGroup(bundle_group);
1471 remote_answer->AddGroup(bundle_group);
1472 EXPECT_TRUE(transport_controller_
1473 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1474 .ok());
1475 EXPECT_TRUE(transport_controller_
1476 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1477 .ok());
1478 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1479 transport_controller_->GetRtpTransport(kVideoMid1));
1480
1481 // Reorder the bundle group.
1482 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1483 bundle_group.AddContentName(kAudioMid1);
1484 // The answerer uses the new bundle group and now the bundle mid is changed to
1485 // |kVideo1|.
1486 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1487 remote_answer->AddGroup(bundle_group);
1488 EXPECT_TRUE(transport_controller_
1489 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1490 .ok());
1491 EXPECT_FALSE(transport_controller_
1492 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1493 .ok());
1494}
Zhi Huange830e682018-03-30 10:48:35 -07001495// Test that rejecting only the first m= section of a BUNDLE group is treated as
1496// an error, but rejecting all of them works as expected.
1497TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1498 CreateJsepTransportController(JsepTransportController::Config());
1499 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1500 bundle_group.AddContentName(kAudioMid1);
1501 bundle_group.AddContentName(kVideoMid1);
1502 bundle_group.AddContentName(kDataMid1);
1503
Karl Wiberg918f50c2018-07-05 11:40:33 +02001504 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001505 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1506 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1507 nullptr);
1508 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1509 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1510 nullptr);
1511 AddDataSection(local_offer.get(), kDataMid1,
1512 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1513 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1514 nullptr);
1515
Karl Wiberg918f50c2018-07-05 11:40:33 +02001516 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001517 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1518 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1519 nullptr);
1520 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1521 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1522 nullptr);
1523 AddDataSection(remote_answer.get(), kDataMid1,
1524 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1525 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1526 nullptr);
1527 // Reject audio content in answer.
1528 remote_answer->contents()[0].rejected = true;
1529
1530 local_offer->AddGroup(bundle_group);
1531 remote_answer->AddGroup(bundle_group);
1532
1533 EXPECT_TRUE(transport_controller_
1534 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1535 .ok());
1536 EXPECT_FALSE(transport_controller_
1537 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1538 .ok());
1539
1540 // Reject all the contents.
1541 remote_answer->contents()[1].rejected = true;
1542 remote_answer->contents()[2].rejected = true;
1543 EXPECT_TRUE(transport_controller_
1544 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1545 .ok());
1546 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1547 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1548 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1549}
1550
1551// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1552// is used.
1553TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1554 JsepTransportController::Config config;
1555 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1556 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001557 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001558 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1559 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1560 nullptr);
1561
1562 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1563 // Applying a non-RTCP-mux offer is expected to fail.
1564 EXPECT_FALSE(transport_controller_
1565 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1566 .ok());
1567}
1568
1569// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1570// is used.
1571TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1572 JsepTransportController::Config config;
1573 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1574 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001575 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001576 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1577 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1578 nullptr);
1579 EXPECT_TRUE(transport_controller_
1580 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1581 .ok());
1582
Karl Wiberg918f50c2018-07-05 11:40:33 +02001583 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001584 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1585 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1586 nullptr);
1587 // Applying a non-RTCP-mux answer is expected to fail.
1588 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1589 EXPECT_FALSE(transport_controller_
1590 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1591 .ok());
1592}
Zhi Huange818b6e2018-02-22 15:26:27 -08001593
Zhi Huangd2248f82018-04-10 14:41:03 -07001594// This tests that the BUNDLE group in answer should be a subset of the offered
1595// group.
1596TEST_F(JsepTransportControllerTest,
1597 AddContentToBundleGroupInAnswerNotSupported) {
1598 CreateJsepTransportController(JsepTransportController::Config());
1599 auto local_offer = CreateSessionDescriptionWithoutBundle();
1600 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1601
1602 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1603 offer_bundle_group.AddContentName(kAudioMid1);
1604 local_offer->AddGroup(offer_bundle_group);
1605
1606 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1607 answer_bundle_group.AddContentName(kAudioMid1);
1608 answer_bundle_group.AddContentName(kVideoMid1);
1609 remote_answer->AddGroup(answer_bundle_group);
1610 EXPECT_TRUE(transport_controller_
1611 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1612 .ok());
1613 EXPECT_FALSE(transport_controller_
1614 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1615 .ok());
1616}
1617
1618// This tests that the BUNDLE group with non-existing MID should be rejectd.
1619TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1620 CreateJsepTransportController(JsepTransportController::Config());
1621 auto local_offer = CreateSessionDescriptionWithoutBundle();
1622 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1623
1624 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1625 // The BUNDLE group is invalid because there is no data section in the
1626 // description.
1627 invalid_bundle_group.AddContentName(kDataMid1);
1628 local_offer->AddGroup(invalid_bundle_group);
1629 remote_answer->AddGroup(invalid_bundle_group);
1630
1631 EXPECT_FALSE(transport_controller_
1632 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1633 .ok());
1634 EXPECT_FALSE(transport_controller_
1635 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1636 .ok());
1637}
1638
1639// This tests that an answer shouldn't be able to remove an m= section from an
1640// established group without rejecting it.
1641TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1642 CreateJsepTransportController(JsepTransportController::Config());
1643
1644 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1645 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1646 EXPECT_TRUE(transport_controller_
1647 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1648 .ok());
1649 EXPECT_TRUE(transport_controller_
1650 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1651 .ok());
1652
1653 // Do an re-offer/answer.
1654 EXPECT_TRUE(transport_controller_
1655 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1656 .ok());
1657 auto new_answer = CreateSessionDescriptionWithoutBundle();
1658 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1659 // The answer removes video from the BUNDLE group without rejecting it is
1660 // invalid.
1661 new_bundle_group.AddContentName(kAudioMid1);
1662 new_answer->AddGroup(new_bundle_group);
1663
1664 // Applying invalid answer is expected to fail.
1665 EXPECT_FALSE(transport_controller_
1666 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1667 .ok());
1668
1669 // Rejected the video content.
1670 auto video_content = new_answer->GetContentByName(kVideoMid1);
1671 ASSERT_TRUE(video_content);
1672 video_content->rejected = true;
1673 EXPECT_TRUE(transport_controller_
1674 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1675 .ok());
1676}
1677
Zhi Huange818b6e2018-02-22 15:26:27 -08001678} // namespace webrtc