blob: fd8a779c784899ea7d99d2a603aae16bbe131aea [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) {
276 if (!signaling_thread_->IsCurrent()) {
277 signaled_on_non_signaling_thread_ = true;
278 }
279 combined_connection_state_ = state;
280 ++combined_connection_state_signal_count_;
281 }
282
Zhi Huange818b6e2018-02-22 15:26:27 -0800283 void OnGatheringState(cricket::IceGatheringState state) {
284 if (!signaling_thread_->IsCurrent()) {
285 signaled_on_non_signaling_thread_ = true;
286 }
287 gathering_state_ = state;
288 ++gathering_state_signal_count_;
289 }
290
291 void OnCandidatesGathered(const std::string& transport_name,
292 const Candidates& candidates) {
293 if (!signaling_thread_->IsCurrent()) {
294 signaled_on_non_signaling_thread_ = true;
295 }
296 candidates_[transport_name].insert(candidates_[transport_name].end(),
297 candidates.begin(), candidates.end());
298 ++candidates_signal_count_;
299 }
300
Zhi Huang365381f2018-04-13 16:44:34 -0700301 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800302 bool OnTransportChanged(const std::string& mid,
303 RtpTransportInternal* rtp_transport,
304 cricket::DtlsTransportInternal* dtls_transport,
305 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700306 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800307 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800308 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700309 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 }
311
312 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000313 cricket::IceConnectionState connection_state_ =
314 cricket::kIceConnectionConnecting;
315 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200316 PeerConnectionInterface::kIceConnectionNew;
317 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
318 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800319 bool receiving_ = false;
320 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
321 // transport_name => candidates
322 std::map<std::string, Candidates> candidates_;
323 // Counts of each signal emitted.
324 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000325 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200326 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800327 int receiving_signal_count_ = 0;
328 int gathering_state_signal_count_ = 0;
329 int candidates_signal_count_ = 0;
330
331 // |network_thread_| should be destroyed after |transport_controller_|
332 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800333 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
334 rtc::Thread* const signaling_thread_ = nullptr;
335 bool signaled_on_non_signaling_thread_ = false;
336 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
337 // signaled correctly.
338 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
339 std::map<std::string, cricket::DtlsTransportInternal*>
340 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800341 std::map<std::string, MediaTransportInterface*>
342 changed_media_transport_by_mid_;
343
344 // Transport controller needs to be destroyed first, because it may issue
345 // callbacks that modify the changed_*_by_mid in the destructor.
346 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800347};
348
349TEST_F(JsepTransportControllerTest, GetRtpTransport) {
350 CreateJsepTransportController(JsepTransportController::Config());
351 auto description = CreateSessionDescriptionWithoutBundle();
352 EXPECT_TRUE(transport_controller_
353 ->SetLocalDescription(SdpType::kOffer, description.get())
354 .ok());
355 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
356 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
357 EXPECT_NE(nullptr, audio_rtp_transport);
358 EXPECT_NE(nullptr, video_rtp_transport);
359 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
360 // Return nullptr for non-existing ones.
361 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
362}
363
364TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
365 JsepTransportController::Config config;
366 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
367 CreateJsepTransportController(config);
368 auto description = CreateSessionDescriptionWithoutBundle();
369 EXPECT_TRUE(transport_controller_
370 ->SetLocalDescription(SdpType::kOffer, description.get())
371 .ok());
372 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
373 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100374 EXPECT_NE(nullptr,
375 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800376 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
377 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100378 EXPECT_NE(nullptr,
379 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
380 // Lookup for all MIDs should return different transports (no bundle)
381 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
382 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800383 // Return nullptr for non-existing ones.
384 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
385 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100386 EXPECT_EQ(nullptr,
387 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100388 // Take a pointer to a transport, shut down the transport controller,
389 // and verify that the resulting container is empty.
390 auto dtls_transport =
391 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
392 webrtc::DtlsTransport* my_transport =
393 static_cast<DtlsTransport*>(dtls_transport.get());
394 EXPECT_NE(nullptr, my_transport->internal());
395 transport_controller_.reset();
396 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800397}
398
Zhi Huange830e682018-03-30 10:48:35 -0700399TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
400 JsepTransportController::Config config;
401 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
402 CreateJsepTransportController(config);
403 auto description = CreateSessionDescriptionWithoutBundle();
404 EXPECT_TRUE(transport_controller_
405 ->SetLocalDescription(SdpType::kOffer, description.get())
406 .ok());
407 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
408 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
409 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
410 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700411 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
412}
413
414TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
415 FakeMediaTransportFactory fake_media_transport_factory;
416 JsepTransportController::Config config;
417
418 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
419 config.media_transport_factory = &fake_media_transport_factory;
420 CreateJsepTransportController(config);
421 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700422 AddCryptoSettings(description.get());
423
Anton Sukhanov7940da02018-10-10 10:34:49 -0700424 EXPECT_TRUE(transport_controller_
425 ->SetLocalDescription(SdpType::kOffer, description.get())
426 .ok());
427
428 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
429 transport_controller_->GetMediaTransport(kAudioMid1));
430
431 ASSERT_NE(nullptr, media_transport);
432
433 // After SetLocalDescription, media transport should be created as caller.
434 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700435 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700436
437 // Return nullptr for non-existing mids.
438 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
439}
440
441TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
442 FakeMediaTransportFactory fake_media_transport_factory;
443 JsepTransportController::Config config;
444
445 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
446 config.media_transport_factory = &fake_media_transport_factory;
447 CreateJsepTransportController(config);
448 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700449 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700450 EXPECT_TRUE(transport_controller_
451 ->SetRemoteDescription(SdpType::kOffer, description.get())
452 .ok());
453
454 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
455 transport_controller_->GetMediaTransport(kAudioMid1));
456
457 ASSERT_NE(nullptr, media_transport);
458
459 // After SetRemoteDescription, media transport should be created as callee.
460 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700461 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700462
463 // Return nullptr for non-existing mids.
464 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 10:48:35 -0700465}
466
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700467TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
468 FakeMediaTransportFactory fake_media_transport_factory;
469 JsepTransportController::Config config;
470
471 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
472 config.media_transport_factory = &fake_media_transport_factory;
473 CreateJsepTransportController(config);
474 auto description = CreateSessionDescriptionWithoutBundle();
475 EXPECT_TRUE(transport_controller_
476 ->SetRemoteDescription(SdpType::kOffer, description.get())
477 .ok());
478
479 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
480
481 // Even if we set local description with crypto now (after the remote offer
482 // was set), media transport won't be provided.
483 auto description2 = CreateSessionDescriptionWithoutBundle();
484 AddCryptoSettings(description2.get());
485 EXPECT_TRUE(transport_controller_
486 ->SetLocalDescription(SdpType::kAnswer, description2.get())
487 .ok());
488
489 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
490}
491
492TEST_F(JsepTransportControllerTest,
493 AfterSettingAnswerTheSameMediaTransportIsReturned) {
494 FakeMediaTransportFactory fake_media_transport_factory;
495 JsepTransportController::Config config;
496
497 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
498 config.media_transport_factory = &fake_media_transport_factory;
499 CreateJsepTransportController(config);
500 auto description = CreateSessionDescriptionWithoutBundle();
501 AddCryptoSettings(description.get());
502 EXPECT_TRUE(transport_controller_
503 ->SetRemoteDescription(SdpType::kOffer, description.get())
504 .ok());
505
506 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
507 transport_controller_->GetMediaTransport(kAudioMid1));
508 EXPECT_NE(nullptr, media_transport);
509 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
510
511 // Even if we set local description with crypto now (after the remote offer
512 // was set), media transport won't be provided.
513 auto description2 = CreateSessionDescriptionWithoutBundle();
514 AddCryptoSettings(description2.get());
515
516 RTCError result = transport_controller_->SetLocalDescription(
517 SdpType::kAnswer, description2.get());
518 EXPECT_TRUE(result.ok()) << result.message();
519
520 // Media transport did not change.
521 EXPECT_EQ(media_transport,
522 transport_controller_->GetMediaTransport(kAudioMid1));
523}
524
Zhi Huange818b6e2018-02-22 15:26:27 -0800525TEST_F(JsepTransportControllerTest, SetIceConfig) {
526 CreateJsepTransportController(JsepTransportController::Config());
527 auto description = CreateSessionDescriptionWithoutBundle();
528 EXPECT_TRUE(transport_controller_
529 ->SetLocalDescription(SdpType::kOffer, description.get())
530 .ok());
531
532 transport_controller_->SetIceConfig(
533 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
534 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
535 transport_controller_->GetDtlsTransport(kAudioMid1));
536 ASSERT_NE(nullptr, fake_audio_dtls);
537 EXPECT_EQ(kTimeout,
538 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
539 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
540
541 // Test that value stored in controller is applied to new transports.
542 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
543 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
544 nullptr);
545
546 EXPECT_TRUE(transport_controller_
547 ->SetLocalDescription(SdpType::kOffer, description.get())
548 .ok());
549 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
550 transport_controller_->GetDtlsTransport(kAudioMid2));
551 ASSERT_NE(nullptr, fake_audio_dtls);
552 EXPECT_EQ(kTimeout,
553 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
554 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
555}
556
557// Tests the getter and setter of the ICE restart flag.
558TEST_F(JsepTransportControllerTest, NeedIceRestart) {
559 CreateJsepTransportController(JsepTransportController::Config());
560 auto description = CreateSessionDescriptionWithoutBundle();
561 EXPECT_TRUE(transport_controller_
562 ->SetLocalDescription(SdpType::kOffer, description.get())
563 .ok());
564 EXPECT_TRUE(transport_controller_
565 ->SetRemoteDescription(SdpType::kAnswer, description.get())
566 .ok());
567
568 // Initially NeedsIceRestart should return false.
569 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
570 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
571 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
572 // true.
573 transport_controller_->SetNeedsIceRestartFlag();
574 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
575 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
576 // For a nonexistent transport, false should be returned.
577 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
578
579 // Reset the ice_ufrag/ice_pwd for audio.
580 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
581 audio_transport_info->description.ice_ufrag = kIceUfrag2;
582 audio_transport_info->description.ice_pwd = kIcePwd2;
583 EXPECT_TRUE(transport_controller_
584 ->SetLocalDescription(SdpType::kOffer, description.get())
585 .ok());
586 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
587 // return false for audio and true for video.
588 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
589 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
590}
591
592TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
593 CreateJsepTransportController(JsepTransportController::Config());
594 auto description = CreateSessionDescriptionWithBundleGroup();
595 EXPECT_TRUE(transport_controller_
596 ->SetLocalDescription(SdpType::kOffer, description.get())
597 .ok());
598 // After setting the local description, we should be able to start gathering
599 // candidates.
600 transport_controller_->MaybeStartGathering();
601 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
602 EXPECT_EQ(1, gathering_state_signal_count_);
603}
604
605TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
606 CreateJsepTransportController(JsepTransportController::Config());
607 auto description = CreateSessionDescriptionWithoutBundle();
608 transport_controller_->SetLocalDescription(SdpType::kOffer,
609 description.get());
610 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
611 description.get());
612 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
613 transport_controller_->GetDtlsTransport(kAudioMid1));
614 ASSERT_NE(nullptr, fake_audio_dtls);
615 Candidates candidates;
616 candidates.push_back(
617 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
618 EXPECT_TRUE(
619 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
620 EXPECT_EQ(1U,
621 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
622
623 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
624 EXPECT_EQ(0U,
625 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
626}
627
628TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
629 CreateJsepTransportController(JsepTransportController::Config());
630
631 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
632 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
633 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
634 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
635
Karl Wiberg918f50c2018-07-05 11:40:33 +0200636 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800637 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
638 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
639 certificate1);
640
641 // Apply the local certificate.
642 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
643 // Apply the local description.
644 EXPECT_TRUE(transport_controller_
645 ->SetLocalDescription(SdpType::kOffer, description.get())
646 .ok());
647 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
648 EXPECT_TRUE(returned_certificate);
649 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
650 returned_certificate->identity()->certificate().ToPEMString());
651
652 // Should fail if called for a nonexistant transport.
653 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
654
655 // Shouldn't be able to change the identity once set.
656 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
657 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
658 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
659 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
660}
661
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800662TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800663 CreateJsepTransportController(JsepTransportController::Config());
664 auto description = CreateSessionDescriptionWithBundleGroup();
665 EXPECT_TRUE(transport_controller_
666 ->SetLocalDescription(SdpType::kOffer, description.get())
667 .ok());
668 rtc::FakeSSLCertificate fake_certificate("fake_data");
669
670 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
671 transport_controller_->GetDtlsTransport(kAudioMid1));
672 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800673 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
674 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
675 ASSERT_TRUE(returned_cert_chain);
676 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800677 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800678 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800679
680 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800681 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800682}
683
684TEST_F(JsepTransportControllerTest, GetDtlsRole) {
685 CreateJsepTransportController(JsepTransportController::Config());
686 auto offer_certificate =
687 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
688 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
689 auto answer_certificate =
690 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
691 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
692 transport_controller_->SetLocalCertificate(offer_certificate);
693
Karl Wiberg918f50c2018-07-05 11:40:33 +0200694 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800695 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
696 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
697 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200698 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800699 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
700 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
701 answer_certificate);
702
703 EXPECT_TRUE(transport_controller_
704 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
705 .ok());
706
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200707 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800708 transport_controller_->GetDtlsRole(kAudioMid1);
709 // The DTLS role is not decided yet.
710 EXPECT_FALSE(role);
711 EXPECT_TRUE(transport_controller_
712 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
713 .ok());
714 role = transport_controller_->GetDtlsRole(kAudioMid1);
715
716 ASSERT_TRUE(role);
717 EXPECT_EQ(rtc::SSL_CLIENT, *role);
718}
719
720TEST_F(JsepTransportControllerTest, GetStats) {
721 CreateJsepTransportController(JsepTransportController::Config());
722 auto description = CreateSessionDescriptionWithBundleGroup();
723 EXPECT_TRUE(transport_controller_
724 ->SetLocalDescription(SdpType::kOffer, description.get())
725 .ok());
726
727 cricket::TransportStats stats;
728 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
729 EXPECT_EQ(kAudioMid1, stats.transport_name);
730 EXPECT_EQ(1u, stats.channel_stats.size());
731 // Return false for non-existing transport.
732 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
733}
734
735TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
736 CreateJsepTransportController(JsepTransportController::Config());
737 auto description = CreateSessionDescriptionWithoutBundle();
738 EXPECT_TRUE(transport_controller_
739 ->SetLocalDescription(SdpType::kOffer, description.get())
740 .ok());
741
742 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
743 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
744 fake_ice->SetCandidatesGatheringComplete();
745 fake_ice->SetConnectionCount(1);
746 // The connection stats will be failed if there is no active connection.
747 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000748 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100749 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000750 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
751 ice_connection_state_, kTimeout);
752 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100753 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
754 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200755 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800756}
757
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700758TEST_F(JsepTransportControllerTest,
759 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800760 CreateJsepTransportController(JsepTransportController::Config());
761 auto description = CreateSessionDescriptionWithoutBundle();
762 EXPECT_TRUE(transport_controller_
763 ->SetLocalDescription(SdpType::kOffer, description.get())
764 .ok());
765
766 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
767 transport_controller_->GetDtlsTransport(kAudioMid1));
768 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
769 transport_controller_->GetDtlsTransport(kVideoMid1));
770
771 // First, have one transport connect, and another fail, to ensure that
772 // the first transport connecting didn't trigger a "connected" state signal.
773 // We should only get a signal when all are connected.
774 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
775 fake_audio_dtls->SetWritable(true);
776 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
777 // Decrease the number of the connection to trigger the signal.
778 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
779 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
780 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
781
Alex Loiko9289eda2018-11-23 16:18:59 +0000782 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100783 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000784 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
785 ice_connection_state_, kTimeout);
786 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100787 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
788 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200789 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800790
Jonas Olsson635474e2018-10-18 15:58:17 +0200791 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
792 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800793 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
794 // the transport state to be STATE_CONNECTING.
795 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
796 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000797 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100798 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000799 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
800 ice_connection_state_, kTimeout);
801 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100802 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
803 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200804 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800805}
806
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700807TEST_F(JsepTransportControllerTest,
808 SignalConnectionStateConnectedWithMediaTransport) {
809 FakeMediaTransportFactory fake_media_transport_factory;
810 JsepTransportController::Config config;
811 config.media_transport_factory = &fake_media_transport_factory;
812 CreateJsepTransportController(config);
813 auto description = CreateSessionDescriptionWithoutBundle();
814 AddCryptoSettings(description.get());
815 EXPECT_TRUE(transport_controller_
816 ->SetLocalDescription(SdpType::kOffer, description.get())
817 .ok());
818
819 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
820 transport_controller_->GetDtlsTransport(kAudioMid1));
821 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
822 transport_controller_->GetDtlsTransport(kVideoMid1));
823 fake_audio_dtls->SetWritable(true);
824 fake_video_dtls->SetWritable(true);
825 // Decreasing connection count from 2 to 1 triggers connection state event.
826 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
827 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
828 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
829 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
830 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
831 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
832
833 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000834 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
835 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700836
837 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
838 transport_controller_->GetMediaTransport(kAudioMid1));
839
840 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000841 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
842 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700843
844 // Still waiting for the second media transport.
845 media_transport = static_cast<FakeMediaTransport*>(
846 transport_controller_->GetMediaTransport(kVideoMid1));
847 media_transport->SetState(webrtc::MediaTransportState::kWritable);
848
Alex Loiko9289eda2018-11-23 16:18:59 +0000849 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700850}
851
852TEST_F(JsepTransportControllerTest,
853 SignalConnectionStateFailedWhenMediaTransportClosed) {
854 FakeMediaTransportFactory fake_media_transport_factory;
855 JsepTransportController::Config config;
856 config.media_transport_factory = &fake_media_transport_factory;
857 CreateJsepTransportController(config);
858 auto description = CreateSessionDescriptionWithoutBundle();
859 AddCryptoSettings(description.get());
860 EXPECT_TRUE(transport_controller_
861 ->SetLocalDescription(SdpType::kOffer, description.get())
862 .ok());
863
864 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
865 transport_controller_->GetDtlsTransport(kAudioMid1));
866 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
867 transport_controller_->GetDtlsTransport(kVideoMid1));
868 fake_audio_dtls->SetWritable(true);
869 fake_video_dtls->SetWritable(true);
870 // Decreasing connection count from 2 to 1 triggers connection state event.
871 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
872 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
873 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
874 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
875 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
876 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
877
878 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
879 transport_controller_->GetMediaTransport(kAudioMid1));
880
881 media_transport->SetState(webrtc::MediaTransportState::kWritable);
882
883 media_transport = static_cast<FakeMediaTransport*>(
884 transport_controller_->GetMediaTransport(kVideoMid1));
885
886 media_transport->SetState(webrtc::MediaTransportState::kWritable);
887
Alex Loiko9289eda2018-11-23 16:18:59 +0000888 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700889
890 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +0000891 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700892}
893
Zhi Huange818b6e2018-02-22 15:26:27 -0800894TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
895 CreateJsepTransportController(JsepTransportController::Config());
896 auto description = CreateSessionDescriptionWithoutBundle();
897 EXPECT_TRUE(transport_controller_
898 ->SetLocalDescription(SdpType::kOffer, description.get())
899 .ok());
900
901 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
902 transport_controller_->GetDtlsTransport(kAudioMid1));
903 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
904 transport_controller_->GetDtlsTransport(kVideoMid1));
905
906 // First, have one transport connect, and another fail, to ensure that
907 // the first transport connecting didn't trigger a "connected" state signal.
908 // We should only get a signal when all are connected.
909 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
910 fake_audio_dtls->SetWritable(true);
911 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
912 // Decrease the number of the connection to trigger the signal.
913 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
914 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
915 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
916
Alex Loiko9289eda2018-11-23 16:18:59 +0000917 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100918 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000919 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
920 ice_connection_state_, kTimeout);
921 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100922 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
923 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200924 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800925
Jonas Olsson635474e2018-10-18 15:58:17 +0200926 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
927 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800928 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
929 // the transport state to be STATE_COMPLETED.
930 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
931 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000932 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100933 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000934 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
935 ice_connection_state_, kTimeout);
936 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100937 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
938 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200939 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800940}
941
942TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
943 CreateJsepTransportController(JsepTransportController::Config());
944 auto description = CreateSessionDescriptionWithoutBundle();
945 EXPECT_TRUE(transport_controller_
946 ->SetLocalDescription(SdpType::kOffer, description.get())
947 .ok());
948
949 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
950 transport_controller_->GetDtlsTransport(kAudioMid1));
951 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
952 // Should be in the gathering state as soon as any transport starts gathering.
953 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
954 EXPECT_EQ(1, gathering_state_signal_count_);
955}
956
957TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
958 CreateJsepTransportController(JsepTransportController::Config());
959 auto description = CreateSessionDescriptionWithoutBundle();
960 EXPECT_TRUE(transport_controller_
961 ->SetLocalDescription(SdpType::kOffer, description.get())
962 .ok());
963
964 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
965 transport_controller_->GetDtlsTransport(kAudioMid1));
966 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
967 transport_controller_->GetDtlsTransport(kVideoMid1));
968
969 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
970 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
971 EXPECT_EQ(1, gathering_state_signal_count_);
972
973 // Have one transport finish gathering, to make sure gathering
974 // completion wasn't signalled if only one transport finished gathering.
975 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
976 EXPECT_EQ(1, gathering_state_signal_count_);
977
978 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
979 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
980 EXPECT_EQ(1, gathering_state_signal_count_);
981
982 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
983 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
984 EXPECT_EQ(2, gathering_state_signal_count_);
985}
986
987// Test that when the last transport that hasn't finished connecting and/or
988// gathering is destroyed, the aggregate state jumps to "completed". This can
989// happen if, for example, we have an audio and video transport, the audio
990// transport completes, then we start bundling video on the audio transport.
991TEST_F(JsepTransportControllerTest,
992 SignalingWhenLastIncompleteTransportDestroyed) {
993 CreateJsepTransportController(JsepTransportController::Config());
994 auto description = CreateSessionDescriptionWithBundleGroup();
995 EXPECT_TRUE(transport_controller_
996 ->SetLocalDescription(SdpType::kOffer, description.get())
997 .ok());
998
999 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1000 transport_controller_->GetDtlsTransport(kAudioMid1));
1001 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1002 transport_controller_->GetDtlsTransport(kVideoMid1));
1003 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1004
1005 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1006 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1007 EXPECT_EQ(1, gathering_state_signal_count_);
1008
1009 // Let the audio transport complete.
1010 fake_audio_dtls->SetWritable(true);
1011 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1012 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001013 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001014 EXPECT_EQ(1, gathering_state_signal_count_);
1015
1016 // Set the remote description and enable the bundle.
1017 EXPECT_TRUE(transport_controller_
1018 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1019 .ok());
1020 // The BUNDLE should be enabled, the incomplete video transport should be
1021 // deleted and the states shoud be updated.
1022 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1023 transport_controller_->GetDtlsTransport(kVideoMid1));
1024 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001025 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1026 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1027 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001028 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1029 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001030 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1031 EXPECT_EQ(2, gathering_state_signal_count_);
1032}
1033
1034TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1035 CreateJsepTransportController(JsepTransportController::Config());
1036 auto description = CreateSessionDescriptionWithBundleGroup();
1037 EXPECT_TRUE(transport_controller_
1038 ->SetLocalDescription(SdpType::kOffer, description.get())
1039 .ok());
1040 transport_controller_->MaybeStartGathering();
1041
1042 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1043 transport_controller_->GetDtlsTransport(kAudioMid1));
1044 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1045 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1046 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1047 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1048}
1049
1050TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1051 network_thread_ = rtc::Thread::CreateWithSocketServer();
1052 network_thread_->Start();
1053 CreateJsepTransportController(JsepTransportController::Config(),
1054 signaling_thread_, network_thread_.get(),
1055 /*PortAllocator=*/nullptr);
1056 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1057
1058 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001059 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001060 EXPECT_EQ(2, connection_state_signal_count_);
1061
1062 // new --> gathering --> complete
1063 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1064 EXPECT_EQ(2, gathering_state_signal_count_);
1065
1066 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1067 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1068 EXPECT_EQ(2, candidates_signal_count_);
1069
1070 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1071}
1072
1073// Older versions of Chrome expect the ICE role to be re-determined when an
1074// ICE restart occurs, and also don't perform conflict resolution correctly,
1075// so for now we can't safely stop doing this.
1076// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1077// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1078// enough population.
1079TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1080 CreateJsepTransportController(JsepTransportController::Config());
1081 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001082 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001083 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1084 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1085 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001086 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001087 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1088 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1089 nullptr);
1090
1091 EXPECT_TRUE(transport_controller_
1092 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1093 .ok());
1094 EXPECT_TRUE(transport_controller_
1095 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1096 .ok());
1097
1098 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1099 transport_controller_->GetDtlsTransport(kAudioMid1));
1100 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1101 fake_dtls->fake_ice_transport()->GetIceRole());
1102
1103 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001104 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001105 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1106 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1107 nullptr);
1108 EXPECT_TRUE(
1109 transport_controller_
1110 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1111 .ok());
1112 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1113 fake_dtls->fake_ice_transport()->GetIceRole());
1114}
1115
1116// Test that if the TransportController was created with the
1117// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1118// redetermined on an ICE restart.
1119TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1120 JsepTransportController::Config config;
1121 config.redetermine_role_on_ice_restart = false;
1122
1123 CreateJsepTransportController(config);
1124 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001125 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001126 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1127 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1128 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001129 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001130 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1131 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1132 nullptr);
1133
1134 EXPECT_TRUE(transport_controller_
1135 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1136 .ok());
1137 EXPECT_TRUE(transport_controller_
1138 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1139 .ok());
1140
1141 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1142 transport_controller_->GetDtlsTransport(kAudioMid1));
1143 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1144 fake_dtls->fake_ice_transport()->GetIceRole());
1145
1146 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001147 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001148 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1149 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1150 nullptr);
1151 EXPECT_TRUE(
1152 transport_controller_
1153 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1154 .ok());
1155 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1156 fake_dtls->fake_ice_transport()->GetIceRole());
1157}
1158
1159// Tests ICE-Lite mode in remote answer.
1160TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1161 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001162 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001163 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1164 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1165 nullptr);
1166 EXPECT_TRUE(transport_controller_
1167 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1168 .ok());
1169 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1170 transport_controller_->GetDtlsTransport(kAudioMid1));
1171 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1172 fake_dtls->fake_ice_transport()->GetIceRole());
1173 EXPECT_EQ(cricket::ICEMODE_FULL,
1174 fake_dtls->fake_ice_transport()->remote_ice_mode());
1175
Karl Wiberg918f50c2018-07-05 11:40:33 +02001176 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001177 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1178 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1179 nullptr);
1180 EXPECT_TRUE(transport_controller_
1181 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1182 .ok());
1183 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1184 fake_dtls->fake_ice_transport()->GetIceRole());
1185 EXPECT_EQ(cricket::ICEMODE_LITE,
1186 fake_dtls->fake_ice_transport()->remote_ice_mode());
1187}
1188
1189// Tests that the ICE role remains "controlling" if a subsequent offer that
1190// does an ICE restart is received from an ICE lite endpoint. Regression test
1191// for: https://crbug.com/710760
1192TEST_F(JsepTransportControllerTest,
1193 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1194 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001195 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001196 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1197 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1198 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001199 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001200 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1201 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1202 nullptr);
1203 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1204 // local side is the controlling.
1205 EXPECT_TRUE(transport_controller_
1206 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1207 .ok());
1208 EXPECT_TRUE(transport_controller_
1209 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1210 .ok());
1211 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1212 transport_controller_->GetDtlsTransport(kAudioMid1));
1213 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1214 fake_dtls->fake_ice_transport()->GetIceRole());
1215
1216 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001217 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001218 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1219 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1220 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001221 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001222 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1223 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1224 nullptr);
1225 EXPECT_TRUE(transport_controller_
1226 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1227 .ok());
1228 EXPECT_TRUE(transport_controller_
1229 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1230 .ok());
1231 fake_dtls = static_cast<FakeDtlsTransport*>(
1232 transport_controller_->GetDtlsTransport(kAudioMid1));
1233 // The local side is still the controlling role since the remote side is using
1234 // ICE-Lite.
1235 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1236 fake_dtls->fake_ice_transport()->GetIceRole());
1237}
1238
1239// Tests that the SDP has more than one audio/video m= sections.
1240TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1241 CreateJsepTransportController(JsepTransportController::Config());
1242 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1243 bundle_group.AddContentName(kAudioMid1);
1244 bundle_group.AddContentName(kAudioMid2);
1245 bundle_group.AddContentName(kVideoMid1);
1246 bundle_group.AddContentName(kDataMid1);
1247
Karl Wiberg918f50c2018-07-05 11:40:33 +02001248 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001249 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1250 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1251 nullptr);
1252 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1253 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1254 nullptr);
1255 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1256 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1257 nullptr);
1258 AddDataSection(local_offer.get(), kDataMid1,
1259 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1260 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1261 nullptr);
1262
Karl Wiberg918f50c2018-07-05 11:40:33 +02001263 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001264 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1265 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1266 nullptr);
1267 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1268 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1269 nullptr);
1270 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1271 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1272 nullptr);
1273 AddDataSection(remote_answer.get(), kDataMid1,
1274 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1275 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1276 nullptr);
1277
1278 local_offer->AddGroup(bundle_group);
1279 remote_answer->AddGroup(bundle_group);
1280
1281 EXPECT_TRUE(transport_controller_
1282 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1283 .ok());
1284 EXPECT_TRUE(transport_controller_
1285 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1286 .ok());
1287 // Verify that all the sections are bundled on kAudio1.
1288 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1289 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1290 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1291 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1292 EXPECT_EQ(transport1, transport2);
1293 EXPECT_EQ(transport1, transport3);
1294 EXPECT_EQ(transport1, transport4);
1295
Harald Alvestrandad88c882018-11-28 16:47:46 +01001296 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1297 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1298
Zhi Huange818b6e2018-02-22 15:26:27 -08001299 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1300 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1301 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1302 EXPECT_EQ(transport1, it->second);
1303 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1304 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1305 EXPECT_EQ(transport1, it->second);
1306 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1307 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1308 EXPECT_EQ(transport1, it->second);
1309 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1310 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1311 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1312 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1313}
1314
1315// Tests that only a subset of all the m= sections are bundled.
1316TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1317 CreateJsepTransportController(JsepTransportController::Config());
1318 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1319 bundle_group.AddContentName(kAudioMid1);
1320 bundle_group.AddContentName(kVideoMid1);
1321
Karl Wiberg918f50c2018-07-05 11:40:33 +02001322 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001323 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1324 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1325 nullptr);
1326 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1327 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1328 nullptr);
1329 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1330 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1331 nullptr);
1332
Karl Wiberg918f50c2018-07-05 11:40:33 +02001333 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001334 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1335 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1336 nullptr);
1337 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1338 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1339 nullptr);
1340 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1341 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1342 nullptr);
1343
1344 local_offer->AddGroup(bundle_group);
1345 remote_answer->AddGroup(bundle_group);
1346 EXPECT_TRUE(transport_controller_
1347 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1348 .ok());
1349 EXPECT_TRUE(transport_controller_
1350 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1351 .ok());
1352
1353 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1354 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1355 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1356 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1357 EXPECT_NE(transport1, transport2);
1358 EXPECT_EQ(transport1, transport3);
1359
1360 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1361 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1362 EXPECT_EQ(transport1, it->second);
1363 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001364 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001365}
1366
1367// Tests that the initial offer/answer only have data section and audio/video
1368// sections are added in the subsequent offer.
1369TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1370 CreateJsepTransportController(JsepTransportController::Config());
1371 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1372 bundle_group.AddContentName(kDataMid1);
1373
Karl Wiberg918f50c2018-07-05 11:40:33 +02001374 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001375 AddDataSection(local_offer.get(), kDataMid1,
1376 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1377 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1378 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001379 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001380 AddDataSection(remote_answer.get(), kDataMid1,
1381 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1382 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1383 nullptr);
1384 local_offer->AddGroup(bundle_group);
1385 remote_answer->AddGroup(bundle_group);
1386
1387 EXPECT_TRUE(transport_controller_
1388 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1389 .ok());
1390 EXPECT_TRUE(transport_controller_
1391 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1392 .ok());
1393 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1394
1395 // Add audio/video sections in subsequent offer.
1396 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1397 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1398 nullptr);
1399 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1400 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1401 nullptr);
1402 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1403 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1404 nullptr);
1405 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1406 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1407 nullptr);
1408
1409 // Reset the bundle group and do another offer/answer exchange.
1410 bundle_group.AddContentName(kAudioMid1);
1411 bundle_group.AddContentName(kVideoMid1);
1412 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1413 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1414 local_offer->AddGroup(bundle_group);
1415 remote_answer->AddGroup(bundle_group);
1416
1417 EXPECT_TRUE(transport_controller_
1418 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1419 .ok());
1420 EXPECT_TRUE(transport_controller_
1421 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1422 .ok());
1423
1424 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1425 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1426 EXPECT_EQ(data_transport, audio_transport);
1427 EXPECT_EQ(data_transport, video_transport);
1428}
1429
1430TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1431 CreateJsepTransportController(JsepTransportController::Config());
1432 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1433 bundle_group.AddContentName(kAudioMid1);
1434 bundle_group.AddContentName(kVideoMid1);
1435 bundle_group.AddContentName(kDataMid1);
1436
Karl Wiberg918f50c2018-07-05 11:40:33 +02001437 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001438 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1439 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1440 nullptr);
1441 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1442 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1443 nullptr);
1444 AddDataSection(local_offer.get(), kDataMid1,
1445 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1446 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1447 nullptr);
1448
Karl Wiberg918f50c2018-07-05 11:40:33 +02001449 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001450 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1451 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1452 nullptr);
1453 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1454 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1455 nullptr);
1456 AddDataSection(remote_answer.get(), kDataMid1,
1457 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1458 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1459 nullptr);
1460 // Reject video and data section.
1461 remote_answer->contents()[1].rejected = true;
1462 remote_answer->contents()[2].rejected = true;
1463
1464 local_offer->AddGroup(bundle_group);
1465 remote_answer->AddGroup(bundle_group);
1466
1467 EXPECT_TRUE(transport_controller_
1468 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1469 .ok());
1470 EXPECT_TRUE(transport_controller_
1471 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1472 .ok());
1473
1474 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1475 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1476 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1477 // Verify the signals are fired correctly.
1478 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1479 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1480 EXPECT_EQ(nullptr, it->second);
1481 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1482 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1483 EXPECT_EQ(nullptr, it2->second);
1484}
1485
1486// Tests that changing the bundled MID in subsequent offer/answer exchange is
1487// not supported.
1488// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1489// fixed
1490TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1491 CreateJsepTransportController(JsepTransportController::Config());
1492 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1493 bundle_group.AddContentName(kAudioMid1);
1494 bundle_group.AddContentName(kVideoMid1);
1495
Karl Wiberg918f50c2018-07-05 11:40:33 +02001496 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001497 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1498 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1499 nullptr);
1500 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1501 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1502 nullptr);
1503
Karl Wiberg918f50c2018-07-05 11:40:33 +02001504 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001505 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1506 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1507 nullptr);
1508 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1509 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1510 nullptr);
1511
1512 local_offer->AddGroup(bundle_group);
1513 remote_answer->AddGroup(bundle_group);
1514 EXPECT_TRUE(transport_controller_
1515 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1516 .ok());
1517 EXPECT_TRUE(transport_controller_
1518 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1519 .ok());
1520 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1521 transport_controller_->GetRtpTransport(kVideoMid1));
1522
1523 // Reorder the bundle group.
1524 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1525 bundle_group.AddContentName(kAudioMid1);
1526 // The answerer uses the new bundle group and now the bundle mid is changed to
1527 // |kVideo1|.
1528 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1529 remote_answer->AddGroup(bundle_group);
1530 EXPECT_TRUE(transport_controller_
1531 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1532 .ok());
1533 EXPECT_FALSE(transport_controller_
1534 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1535 .ok());
1536}
Zhi Huange830e682018-03-30 10:48:35 -07001537// Test that rejecting only the first m= section of a BUNDLE group is treated as
1538// an error, but rejecting all of them works as expected.
1539TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1540 CreateJsepTransportController(JsepTransportController::Config());
1541 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1542 bundle_group.AddContentName(kAudioMid1);
1543 bundle_group.AddContentName(kVideoMid1);
1544 bundle_group.AddContentName(kDataMid1);
1545
Karl Wiberg918f50c2018-07-05 11:40:33 +02001546 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001547 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1548 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1549 nullptr);
1550 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1551 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1552 nullptr);
1553 AddDataSection(local_offer.get(), kDataMid1,
1554 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1555 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1556 nullptr);
1557
Karl Wiberg918f50c2018-07-05 11:40:33 +02001558 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001559 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1560 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1561 nullptr);
1562 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1563 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1564 nullptr);
1565 AddDataSection(remote_answer.get(), kDataMid1,
1566 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1567 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1568 nullptr);
1569 // Reject audio content in answer.
1570 remote_answer->contents()[0].rejected = true;
1571
1572 local_offer->AddGroup(bundle_group);
1573 remote_answer->AddGroup(bundle_group);
1574
1575 EXPECT_TRUE(transport_controller_
1576 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1577 .ok());
1578 EXPECT_FALSE(transport_controller_
1579 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1580 .ok());
1581
1582 // Reject all the contents.
1583 remote_answer->contents()[1].rejected = true;
1584 remote_answer->contents()[2].rejected = true;
1585 EXPECT_TRUE(transport_controller_
1586 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1587 .ok());
1588 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1589 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1590 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1591}
1592
1593// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1594// is used.
1595TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1596 JsepTransportController::Config config;
1597 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1598 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001599 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001600 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1601 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1602 nullptr);
1603
1604 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1605 // Applying a non-RTCP-mux offer is expected to fail.
1606 EXPECT_FALSE(transport_controller_
1607 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1608 .ok());
1609}
1610
1611// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1612// is used.
1613TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1614 JsepTransportController::Config config;
1615 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1616 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001617 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001618 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1619 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1620 nullptr);
1621 EXPECT_TRUE(transport_controller_
1622 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1623 .ok());
1624
Karl Wiberg918f50c2018-07-05 11:40:33 +02001625 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001626 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1627 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1628 nullptr);
1629 // Applying a non-RTCP-mux answer is expected to fail.
1630 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1631 EXPECT_FALSE(transport_controller_
1632 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1633 .ok());
1634}
Zhi Huange818b6e2018-02-22 15:26:27 -08001635
Zhi Huangd2248f82018-04-10 14:41:03 -07001636// This tests that the BUNDLE group in answer should be a subset of the offered
1637// group.
1638TEST_F(JsepTransportControllerTest,
1639 AddContentToBundleGroupInAnswerNotSupported) {
1640 CreateJsepTransportController(JsepTransportController::Config());
1641 auto local_offer = CreateSessionDescriptionWithoutBundle();
1642 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1643
1644 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1645 offer_bundle_group.AddContentName(kAudioMid1);
1646 local_offer->AddGroup(offer_bundle_group);
1647
1648 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1649 answer_bundle_group.AddContentName(kAudioMid1);
1650 answer_bundle_group.AddContentName(kVideoMid1);
1651 remote_answer->AddGroup(answer_bundle_group);
1652 EXPECT_TRUE(transport_controller_
1653 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1654 .ok());
1655 EXPECT_FALSE(transport_controller_
1656 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1657 .ok());
1658}
1659
1660// This tests that the BUNDLE group with non-existing MID should be rejectd.
1661TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1662 CreateJsepTransportController(JsepTransportController::Config());
1663 auto local_offer = CreateSessionDescriptionWithoutBundle();
1664 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1665
1666 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1667 // The BUNDLE group is invalid because there is no data section in the
1668 // description.
1669 invalid_bundle_group.AddContentName(kDataMid1);
1670 local_offer->AddGroup(invalid_bundle_group);
1671 remote_answer->AddGroup(invalid_bundle_group);
1672
1673 EXPECT_FALSE(transport_controller_
1674 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1675 .ok());
1676 EXPECT_FALSE(transport_controller_
1677 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1678 .ok());
1679}
1680
1681// This tests that an answer shouldn't be able to remove an m= section from an
1682// established group without rejecting it.
1683TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1684 CreateJsepTransportController(JsepTransportController::Config());
1685
1686 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1687 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1688 EXPECT_TRUE(transport_controller_
1689 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1690 .ok());
1691 EXPECT_TRUE(transport_controller_
1692 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1693 .ok());
1694
1695 // Do an re-offer/answer.
1696 EXPECT_TRUE(transport_controller_
1697 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1698 .ok());
1699 auto new_answer = CreateSessionDescriptionWithoutBundle();
1700 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1701 // The answer removes video from the BUNDLE group without rejecting it is
1702 // invalid.
1703 new_bundle_group.AddContentName(kAudioMid1);
1704 new_answer->AddGroup(new_bundle_group);
1705
1706 // Applying invalid answer is expected to fail.
1707 EXPECT_FALSE(transport_controller_
1708 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1709 .ok());
1710
1711 // Rejected the video content.
1712 auto video_content = new_answer->GetContentByName(kVideoMid1);
1713 ASSERT_TRUE(video_content);
1714 video_content->rejected = true;
1715 EXPECT_TRUE(transport_controller_
1716 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1717 .ok());
1718}
1719
Zhi Huange818b6e2018-02-22 15:26:27 -08001720} // namespace webrtc