blob: 3031b8df7acafa2e478de578bee271d67fcf86dc [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);
Alex Loiko9289eda2018-11-23 16:18:59 +0000102 transport_controller_->SignalStandardizedIceConnectionState.connect(
103 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200104 transport_controller_->SignalConnectionState.connect(
105 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800106 transport_controller_->SignalIceGatheringState.connect(
107 this, &JsepTransportControllerTest::OnGatheringState);
108 transport_controller_->SignalIceCandidatesGathered.connect(
109 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800110 }
111
112 std::unique_ptr<cricket::SessionDescription>
113 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200114 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800115 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
116 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
117 nullptr);
118 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
119 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
120 nullptr);
121 return description;
122 }
123
124 std::unique_ptr<cricket::SessionDescription>
125 CreateSessionDescriptionWithBundleGroup() {
126 auto description = CreateSessionDescriptionWithoutBundle();
127 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
128 bundle_group.AddContentName(kAudioMid1);
129 bundle_group.AddContentName(kVideoMid1);
130 description->AddGroup(bundle_group);
131
132 return description;
133 }
134
135 void AddAudioSection(cricket::SessionDescription* description,
136 const std::string& mid,
137 const std::string& ufrag,
138 const std::string& pwd,
139 cricket::IceMode ice_mode,
140 cricket::ConnectionRole conn_role,
141 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
142 std::unique_ptr<cricket::AudioContentDescription> audio(
143 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700144 // Set RTCP-mux to be true because the default policy is "mux required".
145 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800146 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
147 /*rejected=*/false, audio.release());
148 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
149 }
150
151 void AddVideoSection(cricket::SessionDescription* description,
152 const std::string& mid,
153 const std::string& ufrag,
154 const std::string& pwd,
155 cricket::IceMode ice_mode,
156 cricket::ConnectionRole conn_role,
157 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
158 std::unique_ptr<cricket::VideoContentDescription> video(
159 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700160 // Set RTCP-mux to be true because the default policy is "mux required".
161 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800162 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
163 /*rejected=*/false, video.release());
164 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
165 }
166
167 void AddDataSection(cricket::SessionDescription* description,
168 const std::string& mid,
169 cricket::MediaProtocolType protocol_type,
170 const std::string& ufrag,
171 const std::string& pwd,
172 cricket::IceMode ice_mode,
173 cricket::ConnectionRole conn_role,
174 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
175 std::unique_ptr<cricket::DataContentDescription> data(
176 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700177 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800178 description->AddContent(mid, protocol_type,
179 /*rejected=*/false, data.release());
180 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
181 }
182
183 void AddTransportInfo(cricket::SessionDescription* description,
184 const std::string& mid,
185 const std::string& ufrag,
186 const std::string& pwd,
187 cricket::IceMode ice_mode,
188 cricket::ConnectionRole conn_role,
189 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
190 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
191 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700192 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800193 }
194
195 cricket::TransportDescription transport_desc(std::vector<std::string>(),
196 ufrag, pwd, ice_mode,
197 conn_role, fingerprint.get());
198 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
199 }
200
201 cricket::IceConfig CreateIceConfig(
202 int receiving_timeout,
203 cricket::ContinualGatheringPolicy continual_gathering_policy) {
204 cricket::IceConfig config;
205 config.receiving_timeout = receiving_timeout;
206 config.continual_gathering_policy = continual_gathering_policy;
207 return config;
208 }
209
210 Candidate CreateCandidate(const std::string& transport_name, int component) {
211 Candidate c;
212 c.set_transport_name(transport_name);
213 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
214 c.set_component(component);
215 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
216 c.set_priority(1);
217 return c;
218 }
219
220 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
221 if (!network_thread_->IsCurrent()) {
222 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
223 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
224 });
225 return;
226 }
227
228 auto description = CreateSessionDescriptionWithBundleGroup();
229 EXPECT_TRUE(transport_controller_
230 ->SetLocalDescription(SdpType::kOffer, description.get())
231 .ok());
232
233 transport_controller_->MaybeStartGathering();
234 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
235 transport_controller_->GetDtlsTransport(kAudioMid1));
236 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
237 transport_controller_->GetDtlsTransport(kVideoMid1));
238 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
239 fake_audio_dtls->fake_ice_transport(),
240 CreateCandidate(kAudioMid1, /*component=*/1));
241 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
242 fake_video_dtls->fake_ice_transport(),
243 CreateCandidate(kVideoMid1, /*component=*/1));
244 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
245 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
246 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
247 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
248 fake_audio_dtls->SetReceiving(true);
249 fake_video_dtls->SetReceiving(true);
250 fake_audio_dtls->SetWritable(true);
251 fake_video_dtls->SetWritable(true);
252 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
253 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
254 }
255
256 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000257 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800258 if (!signaling_thread_->IsCurrent()) {
259 signaled_on_non_signaling_thread_ = true;
260 }
261 connection_state_ = state;
262 ++connection_state_signal_count_;
263 }
264
Alex Loiko9289eda2018-11-23 16:18:59 +0000265 void OnStandardizedIceConnectionState(
266 PeerConnectionInterface::IceConnectionState state) {
267 if (!signaling_thread_->IsCurrent()) {
268 signaled_on_non_signaling_thread_ = true;
269 }
270 ice_connection_state_ = state;
271 ++ice_connection_state_signal_count_;
272 }
273
Jonas Olsson635474e2018-10-18 15:58:17 +0200274 void OnCombinedConnectionState(
275 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100276 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
277 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200278 if (!signaling_thread_->IsCurrent()) {
279 signaled_on_non_signaling_thread_ = true;
280 }
281 combined_connection_state_ = state;
282 ++combined_connection_state_signal_count_;
283 }
284
Zhi Huange818b6e2018-02-22 15:26:27 -0800285 void OnGatheringState(cricket::IceGatheringState state) {
286 if (!signaling_thread_->IsCurrent()) {
287 signaled_on_non_signaling_thread_ = true;
288 }
289 gathering_state_ = state;
290 ++gathering_state_signal_count_;
291 }
292
293 void OnCandidatesGathered(const std::string& transport_name,
294 const Candidates& candidates) {
295 if (!signaling_thread_->IsCurrent()) {
296 signaled_on_non_signaling_thread_ = true;
297 }
298 candidates_[transport_name].insert(candidates_[transport_name].end(),
299 candidates.begin(), candidates.end());
300 ++candidates_signal_count_;
301 }
302
Zhi Huang365381f2018-04-13 16:44:34 -0700303 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800304 bool OnTransportChanged(const std::string& mid,
305 RtpTransportInternal* rtp_transport,
306 cricket::DtlsTransportInternal* dtls_transport,
307 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700308 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800309 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800310 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700311 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800312 }
313
314 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000315 cricket::IceConnectionState connection_state_ =
316 cricket::kIceConnectionConnecting;
317 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200318 PeerConnectionInterface::kIceConnectionNew;
319 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
320 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800321 bool receiving_ = false;
322 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
323 // transport_name => candidates
324 std::map<std::string, Candidates> candidates_;
325 // Counts of each signal emitted.
326 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000327 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200328 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800329 int receiving_signal_count_ = 0;
330 int gathering_state_signal_count_ = 0;
331 int candidates_signal_count_ = 0;
332
333 // |network_thread_| should be destroyed after |transport_controller_|
334 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800335 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
336 rtc::Thread* const signaling_thread_ = nullptr;
337 bool signaled_on_non_signaling_thread_ = false;
338 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
339 // signaled correctly.
340 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
341 std::map<std::string, cricket::DtlsTransportInternal*>
342 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800343 std::map<std::string, MediaTransportInterface*>
344 changed_media_transport_by_mid_;
345
346 // Transport controller needs to be destroyed first, because it may issue
347 // callbacks that modify the changed_*_by_mid in the destructor.
348 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800349};
350
351TEST_F(JsepTransportControllerTest, GetRtpTransport) {
352 CreateJsepTransportController(JsepTransportController::Config());
353 auto description = CreateSessionDescriptionWithoutBundle();
354 EXPECT_TRUE(transport_controller_
355 ->SetLocalDescription(SdpType::kOffer, description.get())
356 .ok());
357 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
358 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
359 EXPECT_NE(nullptr, audio_rtp_transport);
360 EXPECT_NE(nullptr, video_rtp_transport);
361 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
362 // Return nullptr for non-existing ones.
363 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
364}
365
366TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
367 JsepTransportController::Config config;
368 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
369 CreateJsepTransportController(config);
370 auto description = CreateSessionDescriptionWithoutBundle();
371 EXPECT_TRUE(transport_controller_
372 ->SetLocalDescription(SdpType::kOffer, description.get())
373 .ok());
374 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
375 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100376 EXPECT_NE(nullptr,
377 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800378 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
379 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100380 EXPECT_NE(nullptr,
381 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
382 // Lookup for all MIDs should return different transports (no bundle)
383 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
384 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800385 // Return nullptr for non-existing ones.
386 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
387 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100388 EXPECT_EQ(nullptr,
389 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100390 // Take a pointer to a transport, shut down the transport controller,
391 // and verify that the resulting container is empty.
392 auto dtls_transport =
393 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
394 webrtc::DtlsTransport* my_transport =
395 static_cast<DtlsTransport*>(dtls_transport.get());
396 EXPECT_NE(nullptr, my_transport->internal());
397 transport_controller_.reset();
398 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800399}
400
Zhi Huange830e682018-03-30 10:48:35 -0700401TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
402 JsepTransportController::Config config;
403 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
404 CreateJsepTransportController(config);
405 auto description = CreateSessionDescriptionWithoutBundle();
406 EXPECT_TRUE(transport_controller_
407 ->SetLocalDescription(SdpType::kOffer, description.get())
408 .ok());
409 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
410 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
411 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
412 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700413 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
414}
415
416TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
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());
425
Anton Sukhanov7940da02018-10-10 10:34:49 -0700426 EXPECT_TRUE(transport_controller_
427 ->SetLocalDescription(SdpType::kOffer, description.get())
428 .ok());
429
430 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
431 transport_controller_->GetMediaTransport(kAudioMid1));
432
433 ASSERT_NE(nullptr, media_transport);
434
435 // After SetLocalDescription, media transport should be created as caller.
436 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700437 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700438
439 // Return nullptr for non-existing mids.
440 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
441}
442
443TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
444 FakeMediaTransportFactory fake_media_transport_factory;
445 JsepTransportController::Config config;
446
447 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
448 config.media_transport_factory = &fake_media_transport_factory;
449 CreateJsepTransportController(config);
450 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700451 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700452 EXPECT_TRUE(transport_controller_
453 ->SetRemoteDescription(SdpType::kOffer, description.get())
454 .ok());
455
456 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
457 transport_controller_->GetMediaTransport(kAudioMid1));
458
459 ASSERT_NE(nullptr, media_transport);
460
461 // After SetRemoteDescription, media transport should be created as callee.
462 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700463 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700464
465 // Return nullptr for non-existing mids.
466 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 10:48:35 -0700467}
468
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700469TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
470 FakeMediaTransportFactory fake_media_transport_factory;
471 JsepTransportController::Config config;
472
473 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
474 config.media_transport_factory = &fake_media_transport_factory;
475 CreateJsepTransportController(config);
476 auto description = CreateSessionDescriptionWithoutBundle();
477 EXPECT_TRUE(transport_controller_
478 ->SetRemoteDescription(SdpType::kOffer, description.get())
479 .ok());
480
481 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
482
483 // Even if we set local description with crypto now (after the remote offer
484 // was set), media transport won't be provided.
485 auto description2 = CreateSessionDescriptionWithoutBundle();
486 AddCryptoSettings(description2.get());
487 EXPECT_TRUE(transport_controller_
488 ->SetLocalDescription(SdpType::kAnswer, description2.get())
489 .ok());
490
491 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
492}
493
494TEST_F(JsepTransportControllerTest,
495 AfterSettingAnswerTheSameMediaTransportIsReturned) {
496 FakeMediaTransportFactory fake_media_transport_factory;
497 JsepTransportController::Config config;
498
499 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
500 config.media_transport_factory = &fake_media_transport_factory;
501 CreateJsepTransportController(config);
502 auto description = CreateSessionDescriptionWithoutBundle();
503 AddCryptoSettings(description.get());
504 EXPECT_TRUE(transport_controller_
505 ->SetRemoteDescription(SdpType::kOffer, description.get())
506 .ok());
507
508 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
509 transport_controller_->GetMediaTransport(kAudioMid1));
510 EXPECT_NE(nullptr, media_transport);
511 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
512
513 // Even if we set local description with crypto now (after the remote offer
514 // was set), media transport won't be provided.
515 auto description2 = CreateSessionDescriptionWithoutBundle();
516 AddCryptoSettings(description2.get());
517
518 RTCError result = transport_controller_->SetLocalDescription(
519 SdpType::kAnswer, description2.get());
520 EXPECT_TRUE(result.ok()) << result.message();
521
522 // Media transport did not change.
523 EXPECT_EQ(media_transport,
524 transport_controller_->GetMediaTransport(kAudioMid1));
525}
526
Zhi Huange818b6e2018-02-22 15:26:27 -0800527TEST_F(JsepTransportControllerTest, SetIceConfig) {
528 CreateJsepTransportController(JsepTransportController::Config());
529 auto description = CreateSessionDescriptionWithoutBundle();
530 EXPECT_TRUE(transport_controller_
531 ->SetLocalDescription(SdpType::kOffer, description.get())
532 .ok());
533
534 transport_controller_->SetIceConfig(
535 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
536 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
537 transport_controller_->GetDtlsTransport(kAudioMid1));
538 ASSERT_NE(nullptr, fake_audio_dtls);
539 EXPECT_EQ(kTimeout,
540 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
541 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
542
543 // Test that value stored in controller is applied to new transports.
544 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
545 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
546 nullptr);
547
548 EXPECT_TRUE(transport_controller_
549 ->SetLocalDescription(SdpType::kOffer, description.get())
550 .ok());
551 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
552 transport_controller_->GetDtlsTransport(kAudioMid2));
553 ASSERT_NE(nullptr, fake_audio_dtls);
554 EXPECT_EQ(kTimeout,
555 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
556 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
557}
558
559// Tests the getter and setter of the ICE restart flag.
560TEST_F(JsepTransportControllerTest, NeedIceRestart) {
561 CreateJsepTransportController(JsepTransportController::Config());
562 auto description = CreateSessionDescriptionWithoutBundle();
563 EXPECT_TRUE(transport_controller_
564 ->SetLocalDescription(SdpType::kOffer, description.get())
565 .ok());
566 EXPECT_TRUE(transport_controller_
567 ->SetRemoteDescription(SdpType::kAnswer, description.get())
568 .ok());
569
570 // Initially NeedsIceRestart should return false.
571 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
572 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
573 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
574 // true.
575 transport_controller_->SetNeedsIceRestartFlag();
576 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
577 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
578 // For a nonexistent transport, false should be returned.
579 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
580
581 // Reset the ice_ufrag/ice_pwd for audio.
582 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
583 audio_transport_info->description.ice_ufrag = kIceUfrag2;
584 audio_transport_info->description.ice_pwd = kIcePwd2;
585 EXPECT_TRUE(transport_controller_
586 ->SetLocalDescription(SdpType::kOffer, description.get())
587 .ok());
588 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
589 // return false for audio and true for video.
590 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
591 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
592}
593
594TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
595 CreateJsepTransportController(JsepTransportController::Config());
596 auto description = CreateSessionDescriptionWithBundleGroup();
597 EXPECT_TRUE(transport_controller_
598 ->SetLocalDescription(SdpType::kOffer, description.get())
599 .ok());
600 // After setting the local description, we should be able to start gathering
601 // candidates.
602 transport_controller_->MaybeStartGathering();
603 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
604 EXPECT_EQ(1, gathering_state_signal_count_);
605}
606
607TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
608 CreateJsepTransportController(JsepTransportController::Config());
609 auto description = CreateSessionDescriptionWithoutBundle();
610 transport_controller_->SetLocalDescription(SdpType::kOffer,
611 description.get());
612 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
613 description.get());
614 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
615 transport_controller_->GetDtlsTransport(kAudioMid1));
616 ASSERT_NE(nullptr, fake_audio_dtls);
617 Candidates candidates;
618 candidates.push_back(
619 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
620 EXPECT_TRUE(
621 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
622 EXPECT_EQ(1U,
623 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
624
625 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
626 EXPECT_EQ(0U,
627 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
628}
629
630TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
631 CreateJsepTransportController(JsepTransportController::Config());
632
633 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
634 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
635 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
636 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
637
Karl Wiberg918f50c2018-07-05 11:40:33 +0200638 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800639 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
640 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
641 certificate1);
642
643 // Apply the local certificate.
644 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
645 // Apply the local description.
646 EXPECT_TRUE(transport_controller_
647 ->SetLocalDescription(SdpType::kOffer, description.get())
648 .ok());
649 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
650 EXPECT_TRUE(returned_certificate);
651 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
652 returned_certificate->identity()->certificate().ToPEMString());
653
654 // Should fail if called for a nonexistant transport.
655 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
656
657 // Shouldn't be able to change the identity once set.
658 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
659 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
660 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
661 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
662}
663
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800664TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800665 CreateJsepTransportController(JsepTransportController::Config());
666 auto description = CreateSessionDescriptionWithBundleGroup();
667 EXPECT_TRUE(transport_controller_
668 ->SetLocalDescription(SdpType::kOffer, description.get())
669 .ok());
670 rtc::FakeSSLCertificate fake_certificate("fake_data");
671
672 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
673 transport_controller_->GetDtlsTransport(kAudioMid1));
674 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800675 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
676 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
677 ASSERT_TRUE(returned_cert_chain);
678 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800679 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800680 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800681
682 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800683 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800684}
685
686TEST_F(JsepTransportControllerTest, GetDtlsRole) {
687 CreateJsepTransportController(JsepTransportController::Config());
688 auto offer_certificate =
689 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
690 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
691 auto answer_certificate =
692 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
693 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
694 transport_controller_->SetLocalCertificate(offer_certificate);
695
Karl Wiberg918f50c2018-07-05 11:40:33 +0200696 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800697 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
698 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
699 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200700 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800701 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
702 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
703 answer_certificate);
704
705 EXPECT_TRUE(transport_controller_
706 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
707 .ok());
708
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200709 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800710 transport_controller_->GetDtlsRole(kAudioMid1);
711 // The DTLS role is not decided yet.
712 EXPECT_FALSE(role);
713 EXPECT_TRUE(transport_controller_
714 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
715 .ok());
716 role = transport_controller_->GetDtlsRole(kAudioMid1);
717
718 ASSERT_TRUE(role);
719 EXPECT_EQ(rtc::SSL_CLIENT, *role);
720}
721
722TEST_F(JsepTransportControllerTest, GetStats) {
723 CreateJsepTransportController(JsepTransportController::Config());
724 auto description = CreateSessionDescriptionWithBundleGroup();
725 EXPECT_TRUE(transport_controller_
726 ->SetLocalDescription(SdpType::kOffer, description.get())
727 .ok());
728
729 cricket::TransportStats stats;
730 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
731 EXPECT_EQ(kAudioMid1, stats.transport_name);
732 EXPECT_EQ(1u, stats.channel_stats.size());
733 // Return false for non-existing transport.
734 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
735}
736
737TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
738 CreateJsepTransportController(JsepTransportController::Config());
739 auto description = CreateSessionDescriptionWithoutBundle();
740 EXPECT_TRUE(transport_controller_
741 ->SetLocalDescription(SdpType::kOffer, description.get())
742 .ok());
743
744 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
745 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
746 fake_ice->SetCandidatesGatheringComplete();
747 fake_ice->SetConnectionCount(1);
748 // The connection stats will be failed if there is no active connection.
749 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000750 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100751 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000752 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
753 ice_connection_state_, kTimeout);
754 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100755 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
756 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200757 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800758}
759
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700760TEST_F(JsepTransportControllerTest,
761 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800762 CreateJsepTransportController(JsepTransportController::Config());
763 auto description = CreateSessionDescriptionWithoutBundle();
764 EXPECT_TRUE(transport_controller_
765 ->SetLocalDescription(SdpType::kOffer, description.get())
766 .ok());
767
768 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
769 transport_controller_->GetDtlsTransport(kAudioMid1));
770 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
771 transport_controller_->GetDtlsTransport(kVideoMid1));
772
773 // First, have one transport connect, and another fail, to ensure that
774 // the first transport connecting didn't trigger a "connected" state signal.
775 // We should only get a signal when all are connected.
776 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
777 fake_audio_dtls->SetWritable(true);
778 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
779 // Decrease the number of the connection to trigger the signal.
780 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
781 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
782 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
783
Alex Loiko9289eda2018-11-23 16:18:59 +0000784 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100785 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000786 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
787 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100788 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100789 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
790 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100791 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800792
Jonas Olsson635474e2018-10-18 15:58:17 +0200793 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
794 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800795 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
796 // the transport state to be STATE_CONNECTING.
797 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
798 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000799 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100800 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000801 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
802 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100803 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100804 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
805 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100806 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800807}
808
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700809TEST_F(JsepTransportControllerTest,
810 SignalConnectionStateConnectedWithMediaTransport) {
811 FakeMediaTransportFactory fake_media_transport_factory;
812 JsepTransportController::Config config;
813 config.media_transport_factory = &fake_media_transport_factory;
814 CreateJsepTransportController(config);
815 auto description = CreateSessionDescriptionWithoutBundle();
816 AddCryptoSettings(description.get());
817 EXPECT_TRUE(transport_controller_
818 ->SetLocalDescription(SdpType::kOffer, description.get())
819 .ok());
820
821 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
822 transport_controller_->GetDtlsTransport(kAudioMid1));
823 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
824 transport_controller_->GetDtlsTransport(kVideoMid1));
825 fake_audio_dtls->SetWritable(true);
826 fake_video_dtls->SetWritable(true);
827 // Decreasing connection count from 2 to 1 triggers connection state event.
828 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
829 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
830 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
831 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
832 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
833 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
834
835 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000836 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
837 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700838
839 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
840 transport_controller_->GetMediaTransport(kAudioMid1));
841
842 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000843 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
844 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700845
846 // Still waiting for the second media transport.
847 media_transport = static_cast<FakeMediaTransport*>(
848 transport_controller_->GetMediaTransport(kVideoMid1));
849 media_transport->SetState(webrtc::MediaTransportState::kWritable);
850
Alex Loiko9289eda2018-11-23 16:18:59 +0000851 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700852}
853
854TEST_F(JsepTransportControllerTest,
855 SignalConnectionStateFailedWhenMediaTransportClosed) {
856 FakeMediaTransportFactory fake_media_transport_factory;
857 JsepTransportController::Config config;
858 config.media_transport_factory = &fake_media_transport_factory;
859 CreateJsepTransportController(config);
860 auto description = CreateSessionDescriptionWithoutBundle();
861 AddCryptoSettings(description.get());
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 fake_audio_dtls->SetWritable(true);
871 fake_video_dtls->SetWritable(true);
872 // Decreasing connection count from 2 to 1 triggers connection state event.
873 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
874 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
875 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
876 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
877 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
878 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
879
880 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
881 transport_controller_->GetMediaTransport(kAudioMid1));
882
883 media_transport->SetState(webrtc::MediaTransportState::kWritable);
884
885 media_transport = static_cast<FakeMediaTransport*>(
886 transport_controller_->GetMediaTransport(kVideoMid1));
887
888 media_transport->SetState(webrtc::MediaTransportState::kWritable);
889
Alex Loiko9289eda2018-11-23 16:18:59 +0000890 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700891
892 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +0000893 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700894}
895
Zhi Huange818b6e2018-02-22 15:26:27 -0800896TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
897 CreateJsepTransportController(JsepTransportController::Config());
898 auto description = CreateSessionDescriptionWithoutBundle();
899 EXPECT_TRUE(transport_controller_
900 ->SetLocalDescription(SdpType::kOffer, description.get())
901 .ok());
902
903 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
904 transport_controller_->GetDtlsTransport(kAudioMid1));
905 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
906 transport_controller_->GetDtlsTransport(kVideoMid1));
907
908 // First, have one transport connect, and another fail, to ensure that
909 // the first transport connecting didn't trigger a "connected" state signal.
910 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100911 fake_audio_dtls->fake_ice_transport()->SetTransportState(
912 IceTransportState::kCompleted,
913 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800914 fake_audio_dtls->SetWritable(true);
915 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100916
917 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
918 ice_connection_state_, kTimeout);
919 EXPECT_EQ(1, ice_connection_state_signal_count_);
920 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
921 combined_connection_state_, kTimeout);
922 EXPECT_EQ(1, combined_connection_state_signal_count_);
923
924 fake_video_dtls->fake_ice_transport()->SetTransportState(
925 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800926 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
927
Alex Loiko9289eda2018-11-23 16:18:59 +0000928 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100929 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000930 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
931 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100932 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100933 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
934 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100935 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800936
Jonas Olsson635474e2018-10-18 15:58:17 +0200937 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
938 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800939 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
940 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100941 fake_video_dtls->fake_ice_transport()->SetTransportState(
942 IceTransportState::kCompleted,
943 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800944 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000945 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100946 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000947 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
948 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100949 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100950 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
951 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100952 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800953}
954
955TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
956 CreateJsepTransportController(JsepTransportController::Config());
957 auto description = CreateSessionDescriptionWithoutBundle();
958 EXPECT_TRUE(transport_controller_
959 ->SetLocalDescription(SdpType::kOffer, description.get())
960 .ok());
961
962 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
963 transport_controller_->GetDtlsTransport(kAudioMid1));
964 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
965 // Should be in the gathering state as soon as any transport starts gathering.
966 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
967 EXPECT_EQ(1, gathering_state_signal_count_);
968}
969
970TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
971 CreateJsepTransportController(JsepTransportController::Config());
972 auto description = CreateSessionDescriptionWithoutBundle();
973 EXPECT_TRUE(transport_controller_
974 ->SetLocalDescription(SdpType::kOffer, description.get())
975 .ok());
976
977 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
978 transport_controller_->GetDtlsTransport(kAudioMid1));
979 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
980 transport_controller_->GetDtlsTransport(kVideoMid1));
981
982 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
983 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
984 EXPECT_EQ(1, gathering_state_signal_count_);
985
986 // Have one transport finish gathering, to make sure gathering
987 // completion wasn't signalled if only one transport finished gathering.
988 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
989 EXPECT_EQ(1, gathering_state_signal_count_);
990
991 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
992 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
993 EXPECT_EQ(1, gathering_state_signal_count_);
994
995 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
996 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
997 EXPECT_EQ(2, gathering_state_signal_count_);
998}
999
1000// Test that when the last transport that hasn't finished connecting and/or
1001// gathering is destroyed, the aggregate state jumps to "completed". This can
1002// happen if, for example, we have an audio and video transport, the audio
1003// transport completes, then we start bundling video on the audio transport.
1004TEST_F(JsepTransportControllerTest,
1005 SignalingWhenLastIncompleteTransportDestroyed) {
1006 CreateJsepTransportController(JsepTransportController::Config());
1007 auto description = CreateSessionDescriptionWithBundleGroup();
1008 EXPECT_TRUE(transport_controller_
1009 ->SetLocalDescription(SdpType::kOffer, description.get())
1010 .ok());
1011
1012 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1013 transport_controller_->GetDtlsTransport(kAudioMid1));
1014 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1015 transport_controller_->GetDtlsTransport(kVideoMid1));
1016 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1017
1018 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1019 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1020 EXPECT_EQ(1, gathering_state_signal_count_);
1021
1022 // Let the audio transport complete.
1023 fake_audio_dtls->SetWritable(true);
1024 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1025 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001026 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001027 EXPECT_EQ(1, gathering_state_signal_count_);
1028
1029 // Set the remote description and enable the bundle.
1030 EXPECT_TRUE(transport_controller_
1031 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1032 .ok());
1033 // The BUNDLE should be enabled, the incomplete video transport should be
1034 // deleted and the states shoud be updated.
1035 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1036 transport_controller_->GetDtlsTransport(kVideoMid1));
1037 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001038 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1039 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1040 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001041 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1042 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001043 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1044 EXPECT_EQ(2, gathering_state_signal_count_);
1045}
1046
1047TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1048 CreateJsepTransportController(JsepTransportController::Config());
1049 auto description = CreateSessionDescriptionWithBundleGroup();
1050 EXPECT_TRUE(transport_controller_
1051 ->SetLocalDescription(SdpType::kOffer, description.get())
1052 .ok());
1053 transport_controller_->MaybeStartGathering();
1054
1055 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1056 transport_controller_->GetDtlsTransport(kAudioMid1));
1057 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1058 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1059 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1060 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1061}
1062
1063TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1064 network_thread_ = rtc::Thread::CreateWithSocketServer();
1065 network_thread_->Start();
1066 CreateJsepTransportController(JsepTransportController::Config(),
1067 signaling_thread_, network_thread_.get(),
1068 /*PortAllocator=*/nullptr);
1069 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1070
1071 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001072 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001073 EXPECT_EQ(2, connection_state_signal_count_);
1074
1075 // new --> gathering --> complete
1076 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1077 EXPECT_EQ(2, gathering_state_signal_count_);
1078
1079 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1080 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1081 EXPECT_EQ(2, candidates_signal_count_);
1082
1083 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1084}
1085
1086// Older versions of Chrome expect the ICE role to be re-determined when an
1087// ICE restart occurs, and also don't perform conflict resolution correctly,
1088// so for now we can't safely stop doing this.
1089// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1090// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1091// enough population.
1092TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1093 CreateJsepTransportController(JsepTransportController::Config());
1094 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001095 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001096 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1097 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1098 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001099 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001100 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1101 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1102 nullptr);
1103
1104 EXPECT_TRUE(transport_controller_
1105 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1106 .ok());
1107 EXPECT_TRUE(transport_controller_
1108 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1109 .ok());
1110
1111 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1112 transport_controller_->GetDtlsTransport(kAudioMid1));
1113 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1114 fake_dtls->fake_ice_transport()->GetIceRole());
1115
1116 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001117 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001118 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1119 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1120 nullptr);
1121 EXPECT_TRUE(
1122 transport_controller_
1123 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1124 .ok());
1125 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1126 fake_dtls->fake_ice_transport()->GetIceRole());
1127}
1128
1129// Test that if the TransportController was created with the
1130// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1131// redetermined on an ICE restart.
1132TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1133 JsepTransportController::Config config;
1134 config.redetermine_role_on_ice_restart = false;
1135
1136 CreateJsepTransportController(config);
1137 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001138 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001139 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1140 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1141 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001142 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001143 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1144 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1145 nullptr);
1146
1147 EXPECT_TRUE(transport_controller_
1148 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1149 .ok());
1150 EXPECT_TRUE(transport_controller_
1151 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1152 .ok());
1153
1154 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1155 transport_controller_->GetDtlsTransport(kAudioMid1));
1156 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1157 fake_dtls->fake_ice_transport()->GetIceRole());
1158
1159 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001160 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001161 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1162 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1163 nullptr);
1164 EXPECT_TRUE(
1165 transport_controller_
1166 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1167 .ok());
1168 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1169 fake_dtls->fake_ice_transport()->GetIceRole());
1170}
1171
1172// Tests ICE-Lite mode in remote answer.
1173TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1174 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001175 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001176 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1177 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1178 nullptr);
1179 EXPECT_TRUE(transport_controller_
1180 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1181 .ok());
1182 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1183 transport_controller_->GetDtlsTransport(kAudioMid1));
1184 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1185 fake_dtls->fake_ice_transport()->GetIceRole());
1186 EXPECT_EQ(cricket::ICEMODE_FULL,
1187 fake_dtls->fake_ice_transport()->remote_ice_mode());
1188
Karl Wiberg918f50c2018-07-05 11:40:33 +02001189 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001190 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1191 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1192 nullptr);
1193 EXPECT_TRUE(transport_controller_
1194 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1195 .ok());
1196 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1197 fake_dtls->fake_ice_transport()->GetIceRole());
1198 EXPECT_EQ(cricket::ICEMODE_LITE,
1199 fake_dtls->fake_ice_transport()->remote_ice_mode());
1200}
1201
1202// Tests that the ICE role remains "controlling" if a subsequent offer that
1203// does an ICE restart is received from an ICE lite endpoint. Regression test
1204// for: https://crbug.com/710760
1205TEST_F(JsepTransportControllerTest,
1206 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1207 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001208 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001209 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1210 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1211 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001212 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001213 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1214 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1215 nullptr);
1216 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1217 // local side is the controlling.
1218 EXPECT_TRUE(transport_controller_
1219 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1220 .ok());
1221 EXPECT_TRUE(transport_controller_
1222 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1223 .ok());
1224 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1225 transport_controller_->GetDtlsTransport(kAudioMid1));
1226 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1227 fake_dtls->fake_ice_transport()->GetIceRole());
1228
1229 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001230 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001231 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1232 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1233 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001234 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001235 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1236 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1237 nullptr);
1238 EXPECT_TRUE(transport_controller_
1239 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1240 .ok());
1241 EXPECT_TRUE(transport_controller_
1242 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1243 .ok());
1244 fake_dtls = static_cast<FakeDtlsTransport*>(
1245 transport_controller_->GetDtlsTransport(kAudioMid1));
1246 // The local side is still the controlling role since the remote side is using
1247 // ICE-Lite.
1248 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1249 fake_dtls->fake_ice_transport()->GetIceRole());
1250}
1251
1252// Tests that the SDP has more than one audio/video m= sections.
1253TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1254 CreateJsepTransportController(JsepTransportController::Config());
1255 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1256 bundle_group.AddContentName(kAudioMid1);
1257 bundle_group.AddContentName(kAudioMid2);
1258 bundle_group.AddContentName(kVideoMid1);
1259 bundle_group.AddContentName(kDataMid1);
1260
Karl Wiberg918f50c2018-07-05 11:40:33 +02001261 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001262 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1263 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1264 nullptr);
1265 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1266 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1267 nullptr);
1268 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1269 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1270 nullptr);
1271 AddDataSection(local_offer.get(), kDataMid1,
1272 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1273 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1274 nullptr);
1275
Karl Wiberg918f50c2018-07-05 11:40:33 +02001276 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001277 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1278 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1279 nullptr);
1280 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1281 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1282 nullptr);
1283 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1284 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1285 nullptr);
1286 AddDataSection(remote_answer.get(), kDataMid1,
1287 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1288 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1289 nullptr);
1290
1291 local_offer->AddGroup(bundle_group);
1292 remote_answer->AddGroup(bundle_group);
1293
1294 EXPECT_TRUE(transport_controller_
1295 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1296 .ok());
1297 EXPECT_TRUE(transport_controller_
1298 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1299 .ok());
1300 // Verify that all the sections are bundled on kAudio1.
1301 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1302 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1303 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1304 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1305 EXPECT_EQ(transport1, transport2);
1306 EXPECT_EQ(transport1, transport3);
1307 EXPECT_EQ(transport1, transport4);
1308
Harald Alvestrandad88c882018-11-28 16:47:46 +01001309 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1310 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1311
Zhi Huange818b6e2018-02-22 15:26:27 -08001312 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1313 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1314 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1315 EXPECT_EQ(transport1, it->second);
1316 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1317 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1318 EXPECT_EQ(transport1, it->second);
1319 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1320 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1321 EXPECT_EQ(transport1, it->second);
1322 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1323 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1324 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1325 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1326}
1327
1328// Tests that only a subset of all the m= sections are bundled.
1329TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1330 CreateJsepTransportController(JsepTransportController::Config());
1331 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1332 bundle_group.AddContentName(kAudioMid1);
1333 bundle_group.AddContentName(kVideoMid1);
1334
Karl Wiberg918f50c2018-07-05 11:40:33 +02001335 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001336 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1337 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1338 nullptr);
1339 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1340 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1341 nullptr);
1342 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1343 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1344 nullptr);
1345
Karl Wiberg918f50c2018-07-05 11:40:33 +02001346 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001347 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1348 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1349 nullptr);
1350 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1351 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1352 nullptr);
1353 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1354 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1355 nullptr);
1356
1357 local_offer->AddGroup(bundle_group);
1358 remote_answer->AddGroup(bundle_group);
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
1366 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1367 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1368 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1369 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1370 EXPECT_NE(transport1, transport2);
1371 EXPECT_EQ(transport1, transport3);
1372
1373 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1374 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1375 EXPECT_EQ(transport1, it->second);
1376 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001377 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001378}
1379
1380// Tests that the initial offer/answer only have data section and audio/video
1381// sections are added in the subsequent offer.
1382TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1383 CreateJsepTransportController(JsepTransportController::Config());
1384 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1385 bundle_group.AddContentName(kDataMid1);
1386
Karl Wiberg918f50c2018-07-05 11:40:33 +02001387 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001388 AddDataSection(local_offer.get(), kDataMid1,
1389 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1390 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1391 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001392 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001393 AddDataSection(remote_answer.get(), kDataMid1,
1394 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1395 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1396 nullptr);
1397 local_offer->AddGroup(bundle_group);
1398 remote_answer->AddGroup(bundle_group);
1399
1400 EXPECT_TRUE(transport_controller_
1401 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1402 .ok());
1403 EXPECT_TRUE(transport_controller_
1404 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1405 .ok());
1406 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1407
1408 // Add audio/video sections in subsequent offer.
1409 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1410 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1411 nullptr);
1412 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1413 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1414 nullptr);
1415 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1416 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1417 nullptr);
1418 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1419 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1420 nullptr);
1421
1422 // Reset the bundle group and do another offer/answer exchange.
1423 bundle_group.AddContentName(kAudioMid1);
1424 bundle_group.AddContentName(kVideoMid1);
1425 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1426 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1427 local_offer->AddGroup(bundle_group);
1428 remote_answer->AddGroup(bundle_group);
1429
1430 EXPECT_TRUE(transport_controller_
1431 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1432 .ok());
1433 EXPECT_TRUE(transport_controller_
1434 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1435 .ok());
1436
1437 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1438 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1439 EXPECT_EQ(data_transport, audio_transport);
1440 EXPECT_EQ(data_transport, video_transport);
1441}
1442
1443TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1444 CreateJsepTransportController(JsepTransportController::Config());
1445 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1446 bundle_group.AddContentName(kAudioMid1);
1447 bundle_group.AddContentName(kVideoMid1);
1448 bundle_group.AddContentName(kDataMid1);
1449
Karl Wiberg918f50c2018-07-05 11:40:33 +02001450 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001451 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1452 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1453 nullptr);
1454 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1455 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1456 nullptr);
1457 AddDataSection(local_offer.get(), kDataMid1,
1458 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
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 AddDataSection(remote_answer.get(), kDataMid1,
1470 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1471 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1472 nullptr);
1473 // Reject video and data section.
1474 remote_answer->contents()[1].rejected = true;
1475 remote_answer->contents()[2].rejected = true;
1476
1477 local_offer->AddGroup(bundle_group);
1478 remote_answer->AddGroup(bundle_group);
1479
1480 EXPECT_TRUE(transport_controller_
1481 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1482 .ok());
1483 EXPECT_TRUE(transport_controller_
1484 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1485 .ok());
1486
1487 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1488 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1489 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1490 // Verify the signals are fired correctly.
1491 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1492 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1493 EXPECT_EQ(nullptr, it->second);
1494 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1495 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1496 EXPECT_EQ(nullptr, it2->second);
1497}
1498
1499// Tests that changing the bundled MID in subsequent offer/answer exchange is
1500// not supported.
1501// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1502// fixed
1503TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1504 CreateJsepTransportController(JsepTransportController::Config());
1505 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1506 bundle_group.AddContentName(kAudioMid1);
1507 bundle_group.AddContentName(kVideoMid1);
1508
Karl Wiberg918f50c2018-07-05 11:40:33 +02001509 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001510 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1511 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1512 nullptr);
1513 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1514 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1515 nullptr);
1516
Karl Wiberg918f50c2018-07-05 11:40:33 +02001517 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001518 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1519 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1520 nullptr);
1521 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1522 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1523 nullptr);
1524
1525 local_offer->AddGroup(bundle_group);
1526 remote_answer->AddGroup(bundle_group);
1527 EXPECT_TRUE(transport_controller_
1528 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1529 .ok());
1530 EXPECT_TRUE(transport_controller_
1531 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1532 .ok());
1533 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1534 transport_controller_->GetRtpTransport(kVideoMid1));
1535
1536 // Reorder the bundle group.
1537 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1538 bundle_group.AddContentName(kAudioMid1);
1539 // The answerer uses the new bundle group and now the bundle mid is changed to
1540 // |kVideo1|.
1541 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1542 remote_answer->AddGroup(bundle_group);
1543 EXPECT_TRUE(transport_controller_
1544 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1545 .ok());
1546 EXPECT_FALSE(transport_controller_
1547 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1548 .ok());
1549}
Zhi Huange830e682018-03-30 10:48:35 -07001550// Test that rejecting only the first m= section of a BUNDLE group is treated as
1551// an error, but rejecting all of them works as expected.
1552TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1553 CreateJsepTransportController(JsepTransportController::Config());
1554 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1555 bundle_group.AddContentName(kAudioMid1);
1556 bundle_group.AddContentName(kVideoMid1);
1557 bundle_group.AddContentName(kDataMid1);
1558
Karl Wiberg918f50c2018-07-05 11:40:33 +02001559 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001560 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1561 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1562 nullptr);
1563 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1564 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1565 nullptr);
1566 AddDataSection(local_offer.get(), kDataMid1,
1567 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1568 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1569 nullptr);
1570
Karl Wiberg918f50c2018-07-05 11:40:33 +02001571 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001572 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1573 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1574 nullptr);
1575 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1576 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1577 nullptr);
1578 AddDataSection(remote_answer.get(), kDataMid1,
1579 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1580 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1581 nullptr);
1582 // Reject audio content in answer.
1583 remote_answer->contents()[0].rejected = true;
1584
1585 local_offer->AddGroup(bundle_group);
1586 remote_answer->AddGroup(bundle_group);
1587
1588 EXPECT_TRUE(transport_controller_
1589 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1590 .ok());
1591 EXPECT_FALSE(transport_controller_
1592 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1593 .ok());
1594
1595 // Reject all the contents.
1596 remote_answer->contents()[1].rejected = true;
1597 remote_answer->contents()[2].rejected = true;
1598 EXPECT_TRUE(transport_controller_
1599 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1600 .ok());
1601 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1602 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1603 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1604}
1605
1606// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1607// is used.
1608TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1609 JsepTransportController::Config config;
1610 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1611 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001612 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001613 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1614 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1615 nullptr);
1616
1617 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1618 // Applying a non-RTCP-mux offer is expected to fail.
1619 EXPECT_FALSE(transport_controller_
1620 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1621 .ok());
1622}
1623
1624// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1625// is used.
1626TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1627 JsepTransportController::Config config;
1628 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1629 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001630 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001631 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1632 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1633 nullptr);
1634 EXPECT_TRUE(transport_controller_
1635 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1636 .ok());
1637
Karl Wiberg918f50c2018-07-05 11:40:33 +02001638 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001639 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1640 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1641 nullptr);
1642 // Applying a non-RTCP-mux answer is expected to fail.
1643 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1644 EXPECT_FALSE(transport_controller_
1645 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1646 .ok());
1647}
Zhi Huange818b6e2018-02-22 15:26:27 -08001648
Zhi Huangd2248f82018-04-10 14:41:03 -07001649// This tests that the BUNDLE group in answer should be a subset of the offered
1650// group.
1651TEST_F(JsepTransportControllerTest,
1652 AddContentToBundleGroupInAnswerNotSupported) {
1653 CreateJsepTransportController(JsepTransportController::Config());
1654 auto local_offer = CreateSessionDescriptionWithoutBundle();
1655 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1656
1657 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1658 offer_bundle_group.AddContentName(kAudioMid1);
1659 local_offer->AddGroup(offer_bundle_group);
1660
1661 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1662 answer_bundle_group.AddContentName(kAudioMid1);
1663 answer_bundle_group.AddContentName(kVideoMid1);
1664 remote_answer->AddGroup(answer_bundle_group);
1665 EXPECT_TRUE(transport_controller_
1666 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1667 .ok());
1668 EXPECT_FALSE(transport_controller_
1669 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1670 .ok());
1671}
1672
1673// This tests that the BUNDLE group with non-existing MID should be rejectd.
1674TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1675 CreateJsepTransportController(JsepTransportController::Config());
1676 auto local_offer = CreateSessionDescriptionWithoutBundle();
1677 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1678
1679 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1680 // The BUNDLE group is invalid because there is no data section in the
1681 // description.
1682 invalid_bundle_group.AddContentName(kDataMid1);
1683 local_offer->AddGroup(invalid_bundle_group);
1684 remote_answer->AddGroup(invalid_bundle_group);
1685
1686 EXPECT_FALSE(transport_controller_
1687 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1688 .ok());
1689 EXPECT_FALSE(transport_controller_
1690 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1691 .ok());
1692}
1693
1694// This tests that an answer shouldn't be able to remove an m= section from an
1695// established group without rejecting it.
1696TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1697 CreateJsepTransportController(JsepTransportController::Config());
1698
1699 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1700 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1701 EXPECT_TRUE(transport_controller_
1702 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1703 .ok());
1704 EXPECT_TRUE(transport_controller_
1705 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1706 .ok());
1707
1708 // Do an re-offer/answer.
1709 EXPECT_TRUE(transport_controller_
1710 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1711 .ok());
1712 auto new_answer = CreateSessionDescriptionWithoutBundle();
1713 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1714 // The answer removes video from the BUNDLE group without rejecting it is
1715 // invalid.
1716 new_bundle_group.AddContentName(kAudioMid1);
1717 new_answer->AddGroup(new_bundle_group);
1718
1719 // Applying invalid answer is expected to fail.
1720 EXPECT_FALSE(transport_controller_
1721 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1722 .ok());
1723
1724 // Rejected the video content.
1725 auto video_content = new_answer->GetContentByName(kVideoMid1);
1726 ASSERT_TRUE(video_content);
1727 video_content->rejected = true;
1728 EXPECT_TRUE(transport_controller_
1729 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1730 .ok());
1731}
1732
Zhi Huange818b6e2018-02-22 15:26:27 -08001733} // namespace webrtc