blob: 03ef2eae0f4a063b1ffcff68628221aefff249a2 [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));
Zhi Huange818b6e2018-02-22 15:26:27 -0800388}
389
Zhi Huange830e682018-03-30 10:48:35 -0700390TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
391 JsepTransportController::Config config;
392 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
393 CreateJsepTransportController(config);
394 auto description = CreateSessionDescriptionWithoutBundle();
395 EXPECT_TRUE(transport_controller_
396 ->SetLocalDescription(SdpType::kOffer, description.get())
397 .ok());
398 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
399 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
400 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
401 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700402 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
403}
404
405TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
406 FakeMediaTransportFactory fake_media_transport_factory;
407 JsepTransportController::Config config;
408
409 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
410 config.media_transport_factory = &fake_media_transport_factory;
411 CreateJsepTransportController(config);
412 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700413 AddCryptoSettings(description.get());
414
Anton Sukhanov7940da02018-10-10 10:34:49 -0700415 EXPECT_TRUE(transport_controller_
416 ->SetLocalDescription(SdpType::kOffer, description.get())
417 .ok());
418
419 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
420 transport_controller_->GetMediaTransport(kAudioMid1));
421
422 ASSERT_NE(nullptr, media_transport);
423
424 // After SetLocalDescription, media transport should be created as caller.
425 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700426 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700427
428 // Return nullptr for non-existing mids.
429 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
430}
431
432TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
433 FakeMediaTransportFactory fake_media_transport_factory;
434 JsepTransportController::Config config;
435
436 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
437 config.media_transport_factory = &fake_media_transport_factory;
438 CreateJsepTransportController(config);
439 auto description = CreateSessionDescriptionWithoutBundle();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700440 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700441 EXPECT_TRUE(transport_controller_
442 ->SetRemoteDescription(SdpType::kOffer, description.get())
443 .ok());
444
445 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
446 transport_controller_->GetMediaTransport(kAudioMid1));
447
448 ASSERT_NE(nullptr, media_transport);
449
450 // After SetRemoteDescription, media transport should be created as callee.
451 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700452 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700453
454 // Return nullptr for non-existing mids.
455 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Zhi Huange830e682018-03-30 10:48:35 -0700456}
457
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700458TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
459 FakeMediaTransportFactory fake_media_transport_factory;
460 JsepTransportController::Config config;
461
462 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
463 config.media_transport_factory = &fake_media_transport_factory;
464 CreateJsepTransportController(config);
465 auto description = CreateSessionDescriptionWithoutBundle();
466 EXPECT_TRUE(transport_controller_
467 ->SetRemoteDescription(SdpType::kOffer, description.get())
468 .ok());
469
470 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
471
472 // Even if we set local description with crypto now (after the remote offer
473 // was set), media transport won't be provided.
474 auto description2 = CreateSessionDescriptionWithoutBundle();
475 AddCryptoSettings(description2.get());
476 EXPECT_TRUE(transport_controller_
477 ->SetLocalDescription(SdpType::kAnswer, description2.get())
478 .ok());
479
480 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
481}
482
483TEST_F(JsepTransportControllerTest,
484 AfterSettingAnswerTheSameMediaTransportIsReturned) {
485 FakeMediaTransportFactory fake_media_transport_factory;
486 JsepTransportController::Config config;
487
488 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
489 config.media_transport_factory = &fake_media_transport_factory;
490 CreateJsepTransportController(config);
491 auto description = CreateSessionDescriptionWithoutBundle();
492 AddCryptoSettings(description.get());
493 EXPECT_TRUE(transport_controller_
494 ->SetRemoteDescription(SdpType::kOffer, description.get())
495 .ok());
496
497 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
498 transport_controller_->GetMediaTransport(kAudioMid1));
499 EXPECT_NE(nullptr, media_transport);
500 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
501
502 // Even if we set local description with crypto now (after the remote offer
503 // was set), media transport won't be provided.
504 auto description2 = CreateSessionDescriptionWithoutBundle();
505 AddCryptoSettings(description2.get());
506
507 RTCError result = transport_controller_->SetLocalDescription(
508 SdpType::kAnswer, description2.get());
509 EXPECT_TRUE(result.ok()) << result.message();
510
511 // Media transport did not change.
512 EXPECT_EQ(media_transport,
513 transport_controller_->GetMediaTransport(kAudioMid1));
514}
515
Zhi Huange818b6e2018-02-22 15:26:27 -0800516TEST_F(JsepTransportControllerTest, SetIceConfig) {
517 CreateJsepTransportController(JsepTransportController::Config());
518 auto description = CreateSessionDescriptionWithoutBundle();
519 EXPECT_TRUE(transport_controller_
520 ->SetLocalDescription(SdpType::kOffer, description.get())
521 .ok());
522
523 transport_controller_->SetIceConfig(
524 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
525 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
526 transport_controller_->GetDtlsTransport(kAudioMid1));
527 ASSERT_NE(nullptr, fake_audio_dtls);
528 EXPECT_EQ(kTimeout,
529 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
530 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
531
532 // Test that value stored in controller is applied to new transports.
533 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
534 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
535 nullptr);
536
537 EXPECT_TRUE(transport_controller_
538 ->SetLocalDescription(SdpType::kOffer, description.get())
539 .ok());
540 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
541 transport_controller_->GetDtlsTransport(kAudioMid2));
542 ASSERT_NE(nullptr, fake_audio_dtls);
543 EXPECT_EQ(kTimeout,
544 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
545 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
546}
547
548// Tests the getter and setter of the ICE restart flag.
549TEST_F(JsepTransportControllerTest, NeedIceRestart) {
550 CreateJsepTransportController(JsepTransportController::Config());
551 auto description = CreateSessionDescriptionWithoutBundle();
552 EXPECT_TRUE(transport_controller_
553 ->SetLocalDescription(SdpType::kOffer, description.get())
554 .ok());
555 EXPECT_TRUE(transport_controller_
556 ->SetRemoteDescription(SdpType::kAnswer, description.get())
557 .ok());
558
559 // Initially NeedsIceRestart should return false.
560 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
561 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
562 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
563 // true.
564 transport_controller_->SetNeedsIceRestartFlag();
565 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
566 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
567 // For a nonexistent transport, false should be returned.
568 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
569
570 // Reset the ice_ufrag/ice_pwd for audio.
571 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
572 audio_transport_info->description.ice_ufrag = kIceUfrag2;
573 audio_transport_info->description.ice_pwd = kIcePwd2;
574 EXPECT_TRUE(transport_controller_
575 ->SetLocalDescription(SdpType::kOffer, description.get())
576 .ok());
577 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
578 // return false for audio and true for video.
579 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
580 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
581}
582
583TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
584 CreateJsepTransportController(JsepTransportController::Config());
585 auto description = CreateSessionDescriptionWithBundleGroup();
586 EXPECT_TRUE(transport_controller_
587 ->SetLocalDescription(SdpType::kOffer, description.get())
588 .ok());
589 // After setting the local description, we should be able to start gathering
590 // candidates.
591 transport_controller_->MaybeStartGathering();
592 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
593 EXPECT_EQ(1, gathering_state_signal_count_);
594}
595
596TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
597 CreateJsepTransportController(JsepTransportController::Config());
598 auto description = CreateSessionDescriptionWithoutBundle();
599 transport_controller_->SetLocalDescription(SdpType::kOffer,
600 description.get());
601 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
602 description.get());
603 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
604 transport_controller_->GetDtlsTransport(kAudioMid1));
605 ASSERT_NE(nullptr, fake_audio_dtls);
606 Candidates candidates;
607 candidates.push_back(
608 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
609 EXPECT_TRUE(
610 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
611 EXPECT_EQ(1U,
612 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
613
614 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
615 EXPECT_EQ(0U,
616 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
617}
618
619TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
620 CreateJsepTransportController(JsepTransportController::Config());
621
622 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
623 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
624 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
625 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
626
Karl Wiberg918f50c2018-07-05 11:40:33 +0200627 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800628 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
629 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
630 certificate1);
631
632 // Apply the local certificate.
633 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
634 // Apply the local description.
635 EXPECT_TRUE(transport_controller_
636 ->SetLocalDescription(SdpType::kOffer, description.get())
637 .ok());
638 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
639 EXPECT_TRUE(returned_certificate);
640 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
641 returned_certificate->identity()->certificate().ToPEMString());
642
643 // Should fail if called for a nonexistant transport.
644 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
645
646 // Shouldn't be able to change the identity once set.
647 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
648 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
649 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
650 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
651}
652
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800653TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800654 CreateJsepTransportController(JsepTransportController::Config());
655 auto description = CreateSessionDescriptionWithBundleGroup();
656 EXPECT_TRUE(transport_controller_
657 ->SetLocalDescription(SdpType::kOffer, description.get())
658 .ok());
659 rtc::FakeSSLCertificate fake_certificate("fake_data");
660
661 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
662 transport_controller_->GetDtlsTransport(kAudioMid1));
663 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800664 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
665 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
666 ASSERT_TRUE(returned_cert_chain);
667 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800668 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800669 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800670
671 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800672 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800673}
674
675TEST_F(JsepTransportControllerTest, GetDtlsRole) {
676 CreateJsepTransportController(JsepTransportController::Config());
677 auto offer_certificate =
678 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
679 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
680 auto answer_certificate =
681 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
682 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
683 transport_controller_->SetLocalCertificate(offer_certificate);
684
Karl Wiberg918f50c2018-07-05 11:40:33 +0200685 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800686 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
687 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
688 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200689 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800690 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
691 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
692 answer_certificate);
693
694 EXPECT_TRUE(transport_controller_
695 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
696 .ok());
697
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200698 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800699 transport_controller_->GetDtlsRole(kAudioMid1);
700 // The DTLS role is not decided yet.
701 EXPECT_FALSE(role);
702 EXPECT_TRUE(transport_controller_
703 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
704 .ok());
705 role = transport_controller_->GetDtlsRole(kAudioMid1);
706
707 ASSERT_TRUE(role);
708 EXPECT_EQ(rtc::SSL_CLIENT, *role);
709}
710
711TEST_F(JsepTransportControllerTest, GetStats) {
712 CreateJsepTransportController(JsepTransportController::Config());
713 auto description = CreateSessionDescriptionWithBundleGroup();
714 EXPECT_TRUE(transport_controller_
715 ->SetLocalDescription(SdpType::kOffer, description.get())
716 .ok());
717
718 cricket::TransportStats stats;
719 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
720 EXPECT_EQ(kAudioMid1, stats.transport_name);
721 EXPECT_EQ(1u, stats.channel_stats.size());
722 // Return false for non-existing transport.
723 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
724}
725
726TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
727 CreateJsepTransportController(JsepTransportController::Config());
728 auto description = CreateSessionDescriptionWithoutBundle();
729 EXPECT_TRUE(transport_controller_
730 ->SetLocalDescription(SdpType::kOffer, description.get())
731 .ok());
732
733 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
734 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
735 fake_ice->SetCandidatesGatheringComplete();
736 fake_ice->SetConnectionCount(1);
737 // The connection stats will be failed if there is no active connection.
738 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000739 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100740 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000741 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
742 ice_connection_state_, kTimeout);
743 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100744 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
745 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200746 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800747}
748
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700749TEST_F(JsepTransportControllerTest,
750 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800751 CreateJsepTransportController(JsepTransportController::Config());
752 auto description = CreateSessionDescriptionWithoutBundle();
753 EXPECT_TRUE(transport_controller_
754 ->SetLocalDescription(SdpType::kOffer, description.get())
755 .ok());
756
757 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
758 transport_controller_->GetDtlsTransport(kAudioMid1));
759 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
760 transport_controller_->GetDtlsTransport(kVideoMid1));
761
762 // First, have one transport connect, and another fail, to ensure that
763 // the first transport connecting didn't trigger a "connected" state signal.
764 // We should only get a signal when all are connected.
765 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
766 fake_audio_dtls->SetWritable(true);
767 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
768 // Decrease the number of the connection to trigger the signal.
769 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
770 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
771 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
772
Alex Loiko9289eda2018-11-23 16:18:59 +0000773 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100774 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000775 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
776 ice_connection_state_, kTimeout);
777 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100778 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
779 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200780 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800781
Jonas Olsson635474e2018-10-18 15:58:17 +0200782 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
783 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800784 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
785 // the transport state to be STATE_CONNECTING.
786 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
787 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000788 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100789 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000790 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
791 ice_connection_state_, kTimeout);
792 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100793 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
794 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200795 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800796}
797
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700798TEST_F(JsepTransportControllerTest,
799 SignalConnectionStateConnectedWithMediaTransport) {
800 FakeMediaTransportFactory fake_media_transport_factory;
801 JsepTransportController::Config config;
802 config.media_transport_factory = &fake_media_transport_factory;
803 CreateJsepTransportController(config);
804 auto description = CreateSessionDescriptionWithoutBundle();
805 AddCryptoSettings(description.get());
806 EXPECT_TRUE(transport_controller_
807 ->SetLocalDescription(SdpType::kOffer, description.get())
808 .ok());
809
810 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
811 transport_controller_->GetDtlsTransport(kAudioMid1));
812 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
813 transport_controller_->GetDtlsTransport(kVideoMid1));
814 fake_audio_dtls->SetWritable(true);
815 fake_video_dtls->SetWritable(true);
816 // Decreasing connection count from 2 to 1 triggers connection state event.
817 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
818 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
819 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
820 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
821 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
822 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
823
824 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000825 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
826 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700827
828 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
829 transport_controller_->GetMediaTransport(kAudioMid1));
830
831 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000832 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
833 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700834
835 // Still waiting for the second media transport.
836 media_transport = static_cast<FakeMediaTransport*>(
837 transport_controller_->GetMediaTransport(kVideoMid1));
838 media_transport->SetState(webrtc::MediaTransportState::kWritable);
839
Alex Loiko9289eda2018-11-23 16:18:59 +0000840 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700841}
842
843TEST_F(JsepTransportControllerTest,
844 SignalConnectionStateFailedWhenMediaTransportClosed) {
845 FakeMediaTransportFactory fake_media_transport_factory;
846 JsepTransportController::Config config;
847 config.media_transport_factory = &fake_media_transport_factory;
848 CreateJsepTransportController(config);
849 auto description = CreateSessionDescriptionWithoutBundle();
850 AddCryptoSettings(description.get());
851 EXPECT_TRUE(transport_controller_
852 ->SetLocalDescription(SdpType::kOffer, description.get())
853 .ok());
854
855 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
856 transport_controller_->GetDtlsTransport(kAudioMid1));
857 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
858 transport_controller_->GetDtlsTransport(kVideoMid1));
859 fake_audio_dtls->SetWritable(true);
860 fake_video_dtls->SetWritable(true);
861 // Decreasing connection count from 2 to 1 triggers connection state event.
862 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
863 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
864 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
865 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
866 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
867 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
868
869 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
870 transport_controller_->GetMediaTransport(kAudioMid1));
871
872 media_transport->SetState(webrtc::MediaTransportState::kWritable);
873
874 media_transport = static_cast<FakeMediaTransport*>(
875 transport_controller_->GetMediaTransport(kVideoMid1));
876
877 media_transport->SetState(webrtc::MediaTransportState::kWritable);
878
Alex Loiko9289eda2018-11-23 16:18:59 +0000879 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700880
881 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +0000882 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700883}
884
Zhi Huange818b6e2018-02-22 15:26:27 -0800885TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
886 CreateJsepTransportController(JsepTransportController::Config());
887 auto description = CreateSessionDescriptionWithoutBundle();
888 EXPECT_TRUE(transport_controller_
889 ->SetLocalDescription(SdpType::kOffer, description.get())
890 .ok());
891
892 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
893 transport_controller_->GetDtlsTransport(kAudioMid1));
894 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
895 transport_controller_->GetDtlsTransport(kVideoMid1));
896
897 // First, have one transport connect, and another fail, to ensure that
898 // the first transport connecting didn't trigger a "connected" state signal.
899 // We should only get a signal when all are connected.
900 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
901 fake_audio_dtls->SetWritable(true);
902 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
903 // Decrease the number of the connection to trigger the signal.
904 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
905 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
906 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
907
Alex Loiko9289eda2018-11-23 16:18:59 +0000908 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100909 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000910 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
911 ice_connection_state_, kTimeout);
912 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100913 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
914 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200915 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800916
Jonas Olsson635474e2018-10-18 15:58:17 +0200917 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
918 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800919 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
920 // the transport state to be STATE_COMPLETED.
921 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
922 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000923 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100924 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000925 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
926 ice_connection_state_, kTimeout);
927 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100928 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
929 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200930 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800931}
932
933TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
934 CreateJsepTransportController(JsepTransportController::Config());
935 auto description = CreateSessionDescriptionWithoutBundle();
936 EXPECT_TRUE(transport_controller_
937 ->SetLocalDescription(SdpType::kOffer, description.get())
938 .ok());
939
940 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
941 transport_controller_->GetDtlsTransport(kAudioMid1));
942 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
943 // Should be in the gathering state as soon as any transport starts gathering.
944 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
945 EXPECT_EQ(1, gathering_state_signal_count_);
946}
947
948TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
949 CreateJsepTransportController(JsepTransportController::Config());
950 auto description = CreateSessionDescriptionWithoutBundle();
951 EXPECT_TRUE(transport_controller_
952 ->SetLocalDescription(SdpType::kOffer, description.get())
953 .ok());
954
955 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
956 transport_controller_->GetDtlsTransport(kAudioMid1));
957 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
958 transport_controller_->GetDtlsTransport(kVideoMid1));
959
960 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
961 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
962 EXPECT_EQ(1, gathering_state_signal_count_);
963
964 // Have one transport finish gathering, to make sure gathering
965 // completion wasn't signalled if only one transport finished gathering.
966 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
967 EXPECT_EQ(1, gathering_state_signal_count_);
968
969 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
970 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
971 EXPECT_EQ(1, gathering_state_signal_count_);
972
973 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
974 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
975 EXPECT_EQ(2, gathering_state_signal_count_);
976}
977
978// Test that when the last transport that hasn't finished connecting and/or
979// gathering is destroyed, the aggregate state jumps to "completed". This can
980// happen if, for example, we have an audio and video transport, the audio
981// transport completes, then we start bundling video on the audio transport.
982TEST_F(JsepTransportControllerTest,
983 SignalingWhenLastIncompleteTransportDestroyed) {
984 CreateJsepTransportController(JsepTransportController::Config());
985 auto description = CreateSessionDescriptionWithBundleGroup();
986 EXPECT_TRUE(transport_controller_
987 ->SetLocalDescription(SdpType::kOffer, description.get())
988 .ok());
989
990 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
991 transport_controller_->GetDtlsTransport(kAudioMid1));
992 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
993 transport_controller_->GetDtlsTransport(kVideoMid1));
994 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
995
996 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
997 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
998 EXPECT_EQ(1, gathering_state_signal_count_);
999
1000 // Let the audio transport complete.
1001 fake_audio_dtls->SetWritable(true);
1002 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1003 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001004 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001005 EXPECT_EQ(1, gathering_state_signal_count_);
1006
1007 // Set the remote description and enable the bundle.
1008 EXPECT_TRUE(transport_controller_
1009 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1010 .ok());
1011 // The BUNDLE should be enabled, the incomplete video transport should be
1012 // deleted and the states shoud be updated.
1013 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1014 transport_controller_->GetDtlsTransport(kVideoMid1));
1015 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001016 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1017 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1018 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001019 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1020 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001021 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1022 EXPECT_EQ(2, gathering_state_signal_count_);
1023}
1024
1025TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1026 CreateJsepTransportController(JsepTransportController::Config());
1027 auto description = CreateSessionDescriptionWithBundleGroup();
1028 EXPECT_TRUE(transport_controller_
1029 ->SetLocalDescription(SdpType::kOffer, description.get())
1030 .ok());
1031 transport_controller_->MaybeStartGathering();
1032
1033 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1034 transport_controller_->GetDtlsTransport(kAudioMid1));
1035 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1036 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1037 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1038 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1039}
1040
1041TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1042 network_thread_ = rtc::Thread::CreateWithSocketServer();
1043 network_thread_->Start();
1044 CreateJsepTransportController(JsepTransportController::Config(),
1045 signaling_thread_, network_thread_.get(),
1046 /*PortAllocator=*/nullptr);
1047 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1048
1049 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001050 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001051 EXPECT_EQ(2, connection_state_signal_count_);
1052
1053 // new --> gathering --> complete
1054 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1055 EXPECT_EQ(2, gathering_state_signal_count_);
1056
1057 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1058 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1059 EXPECT_EQ(2, candidates_signal_count_);
1060
1061 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1062}
1063
1064// Older versions of Chrome expect the ICE role to be re-determined when an
1065// ICE restart occurs, and also don't perform conflict resolution correctly,
1066// so for now we can't safely stop doing this.
1067// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1068// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1069// enough population.
1070TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1071 CreateJsepTransportController(JsepTransportController::Config());
1072 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001073 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001074 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1075 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1076 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001077 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001078 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1079 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1080 nullptr);
1081
1082 EXPECT_TRUE(transport_controller_
1083 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1084 .ok());
1085 EXPECT_TRUE(transport_controller_
1086 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1087 .ok());
1088
1089 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1090 transport_controller_->GetDtlsTransport(kAudioMid1));
1091 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1092 fake_dtls->fake_ice_transport()->GetIceRole());
1093
1094 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001095 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001096 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1097 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1098 nullptr);
1099 EXPECT_TRUE(
1100 transport_controller_
1101 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1102 .ok());
1103 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1104 fake_dtls->fake_ice_transport()->GetIceRole());
1105}
1106
1107// Test that if the TransportController was created with the
1108// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1109// redetermined on an ICE restart.
1110TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1111 JsepTransportController::Config config;
1112 config.redetermine_role_on_ice_restart = false;
1113
1114 CreateJsepTransportController(config);
1115 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001116 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001117 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1118 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1119 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001120 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001121 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1122 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1123 nullptr);
1124
1125 EXPECT_TRUE(transport_controller_
1126 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1127 .ok());
1128 EXPECT_TRUE(transport_controller_
1129 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1130 .ok());
1131
1132 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1133 transport_controller_->GetDtlsTransport(kAudioMid1));
1134 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1135 fake_dtls->fake_ice_transport()->GetIceRole());
1136
1137 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001138 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001139 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1140 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1141 nullptr);
1142 EXPECT_TRUE(
1143 transport_controller_
1144 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1145 .ok());
1146 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1147 fake_dtls->fake_ice_transport()->GetIceRole());
1148}
1149
1150// Tests ICE-Lite mode in remote answer.
1151TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1152 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001153 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001154 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1155 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1156 nullptr);
1157 EXPECT_TRUE(transport_controller_
1158 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1159 .ok());
1160 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1161 transport_controller_->GetDtlsTransport(kAudioMid1));
1162 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1163 fake_dtls->fake_ice_transport()->GetIceRole());
1164 EXPECT_EQ(cricket::ICEMODE_FULL,
1165 fake_dtls->fake_ice_transport()->remote_ice_mode());
1166
Karl Wiberg918f50c2018-07-05 11:40:33 +02001167 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001168 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1169 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1170 nullptr);
1171 EXPECT_TRUE(transport_controller_
1172 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1173 .ok());
1174 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1175 fake_dtls->fake_ice_transport()->GetIceRole());
1176 EXPECT_EQ(cricket::ICEMODE_LITE,
1177 fake_dtls->fake_ice_transport()->remote_ice_mode());
1178}
1179
1180// Tests that the ICE role remains "controlling" if a subsequent offer that
1181// does an ICE restart is received from an ICE lite endpoint. Regression test
1182// for: https://crbug.com/710760
1183TEST_F(JsepTransportControllerTest,
1184 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1185 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001186 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001187 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1188 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1189 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001190 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001191 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1192 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1193 nullptr);
1194 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1195 // local side is the controlling.
1196 EXPECT_TRUE(transport_controller_
1197 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1198 .ok());
1199 EXPECT_TRUE(transport_controller_
1200 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1201 .ok());
1202 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1203 transport_controller_->GetDtlsTransport(kAudioMid1));
1204 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1205 fake_dtls->fake_ice_transport()->GetIceRole());
1206
1207 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001208 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001209 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1210 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1211 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001212 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001213 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1214 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1215 nullptr);
1216 EXPECT_TRUE(transport_controller_
1217 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1218 .ok());
1219 EXPECT_TRUE(transport_controller_
1220 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1221 .ok());
1222 fake_dtls = static_cast<FakeDtlsTransport*>(
1223 transport_controller_->GetDtlsTransport(kAudioMid1));
1224 // The local side is still the controlling role since the remote side is using
1225 // ICE-Lite.
1226 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1227 fake_dtls->fake_ice_transport()->GetIceRole());
1228}
1229
1230// Tests that the SDP has more than one audio/video m= sections.
1231TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1232 CreateJsepTransportController(JsepTransportController::Config());
1233 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1234 bundle_group.AddContentName(kAudioMid1);
1235 bundle_group.AddContentName(kAudioMid2);
1236 bundle_group.AddContentName(kVideoMid1);
1237 bundle_group.AddContentName(kDataMid1);
1238
Karl Wiberg918f50c2018-07-05 11:40:33 +02001239 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001240 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1241 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1242 nullptr);
1243 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1244 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1245 nullptr);
1246 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1247 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1248 nullptr);
1249 AddDataSection(local_offer.get(), kDataMid1,
1250 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1251 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1252 nullptr);
1253
Karl Wiberg918f50c2018-07-05 11:40:33 +02001254 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001255 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1256 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1257 nullptr);
1258 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1259 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1260 nullptr);
1261 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1262 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1263 nullptr);
1264 AddDataSection(remote_answer.get(), kDataMid1,
1265 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1266 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1267 nullptr);
1268
1269 local_offer->AddGroup(bundle_group);
1270 remote_answer->AddGroup(bundle_group);
1271
1272 EXPECT_TRUE(transport_controller_
1273 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1274 .ok());
1275 EXPECT_TRUE(transport_controller_
1276 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1277 .ok());
1278 // Verify that all the sections are bundled on kAudio1.
1279 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1280 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1281 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1282 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1283 EXPECT_EQ(transport1, transport2);
1284 EXPECT_EQ(transport1, transport3);
1285 EXPECT_EQ(transport1, transport4);
1286
Harald Alvestrandad88c882018-11-28 16:47:46 +01001287 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1288 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1289
Zhi Huange818b6e2018-02-22 15:26:27 -08001290 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1291 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1292 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1293 EXPECT_EQ(transport1, it->second);
1294 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1295 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1296 EXPECT_EQ(transport1, it->second);
1297 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1298 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1299 EXPECT_EQ(transport1, it->second);
1300 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1301 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1302 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1303 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1304}
1305
1306// Tests that only a subset of all the m= sections are bundled.
1307TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1308 CreateJsepTransportController(JsepTransportController::Config());
1309 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1310 bundle_group.AddContentName(kAudioMid1);
1311 bundle_group.AddContentName(kVideoMid1);
1312
Karl Wiberg918f50c2018-07-05 11:40:33 +02001313 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001314 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1315 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1316 nullptr);
1317 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1318 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1319 nullptr);
1320 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1321 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1322 nullptr);
1323
Karl Wiberg918f50c2018-07-05 11:40:33 +02001324 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001325 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1326 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1327 nullptr);
1328 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1329 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1330 nullptr);
1331 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1332 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1333 nullptr);
1334
1335 local_offer->AddGroup(bundle_group);
1336 remote_answer->AddGroup(bundle_group);
1337 EXPECT_TRUE(transport_controller_
1338 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1339 .ok());
1340 EXPECT_TRUE(transport_controller_
1341 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1342 .ok());
1343
1344 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1345 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1346 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1347 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1348 EXPECT_NE(transport1, transport2);
1349 EXPECT_EQ(transport1, transport3);
1350
1351 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1352 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1353 EXPECT_EQ(transport1, it->second);
1354 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001355 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001356}
1357
1358// Tests that the initial offer/answer only have data section and audio/video
1359// sections are added in the subsequent offer.
1360TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1361 CreateJsepTransportController(JsepTransportController::Config());
1362 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1363 bundle_group.AddContentName(kDataMid1);
1364
Karl Wiberg918f50c2018-07-05 11:40:33 +02001365 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001366 AddDataSection(local_offer.get(), kDataMid1,
1367 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1368 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1369 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001370 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001371 AddDataSection(remote_answer.get(), kDataMid1,
1372 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1373 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1374 nullptr);
1375 local_offer->AddGroup(bundle_group);
1376 remote_answer->AddGroup(bundle_group);
1377
1378 EXPECT_TRUE(transport_controller_
1379 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1380 .ok());
1381 EXPECT_TRUE(transport_controller_
1382 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1383 .ok());
1384 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1385
1386 // Add audio/video sections in subsequent offer.
1387 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1388 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1389 nullptr);
1390 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1391 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1392 nullptr);
1393 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1394 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1395 nullptr);
1396 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1397 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1398 nullptr);
1399
1400 // Reset the bundle group and do another offer/answer exchange.
1401 bundle_group.AddContentName(kAudioMid1);
1402 bundle_group.AddContentName(kVideoMid1);
1403 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1404 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1405 local_offer->AddGroup(bundle_group);
1406 remote_answer->AddGroup(bundle_group);
1407
1408 EXPECT_TRUE(transport_controller_
1409 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1410 .ok());
1411 EXPECT_TRUE(transport_controller_
1412 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1413 .ok());
1414
1415 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1416 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1417 EXPECT_EQ(data_transport, audio_transport);
1418 EXPECT_EQ(data_transport, video_transport);
1419}
1420
1421TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1422 CreateJsepTransportController(JsepTransportController::Config());
1423 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1424 bundle_group.AddContentName(kAudioMid1);
1425 bundle_group.AddContentName(kVideoMid1);
1426 bundle_group.AddContentName(kDataMid1);
1427
Karl Wiberg918f50c2018-07-05 11:40:33 +02001428 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001429 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1430 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1431 nullptr);
1432 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1433 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1434 nullptr);
1435 AddDataSection(local_offer.get(), kDataMid1,
1436 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1437 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1438 nullptr);
1439
Karl Wiberg918f50c2018-07-05 11:40:33 +02001440 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001441 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1442 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1443 nullptr);
1444 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1445 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1446 nullptr);
1447 AddDataSection(remote_answer.get(), kDataMid1,
1448 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1449 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1450 nullptr);
1451 // Reject video and data section.
1452 remote_answer->contents()[1].rejected = true;
1453 remote_answer->contents()[2].rejected = true;
1454
1455 local_offer->AddGroup(bundle_group);
1456 remote_answer->AddGroup(bundle_group);
1457
1458 EXPECT_TRUE(transport_controller_
1459 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1460 .ok());
1461 EXPECT_TRUE(transport_controller_
1462 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1463 .ok());
1464
1465 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1466 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1467 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1468 // Verify the signals are fired correctly.
1469 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1470 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1471 EXPECT_EQ(nullptr, it->second);
1472 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1473 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1474 EXPECT_EQ(nullptr, it2->second);
1475}
1476
1477// Tests that changing the bundled MID in subsequent offer/answer exchange is
1478// not supported.
1479// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1480// fixed
1481TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1482 CreateJsepTransportController(JsepTransportController::Config());
1483 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1484 bundle_group.AddContentName(kAudioMid1);
1485 bundle_group.AddContentName(kVideoMid1);
1486
Karl Wiberg918f50c2018-07-05 11:40:33 +02001487 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001488 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1489 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1490 nullptr);
1491 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1492 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1493 nullptr);
1494
Karl Wiberg918f50c2018-07-05 11:40:33 +02001495 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001496 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1497 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1498 nullptr);
1499 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1500 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1501 nullptr);
1502
1503 local_offer->AddGroup(bundle_group);
1504 remote_answer->AddGroup(bundle_group);
1505 EXPECT_TRUE(transport_controller_
1506 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1507 .ok());
1508 EXPECT_TRUE(transport_controller_
1509 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1510 .ok());
1511 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1512 transport_controller_->GetRtpTransport(kVideoMid1));
1513
1514 // Reorder the bundle group.
1515 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1516 bundle_group.AddContentName(kAudioMid1);
1517 // The answerer uses the new bundle group and now the bundle mid is changed to
1518 // |kVideo1|.
1519 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1520 remote_answer->AddGroup(bundle_group);
1521 EXPECT_TRUE(transport_controller_
1522 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1523 .ok());
1524 EXPECT_FALSE(transport_controller_
1525 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1526 .ok());
1527}
Zhi Huange830e682018-03-30 10:48:35 -07001528// Test that rejecting only the first m= section of a BUNDLE group is treated as
1529// an error, but rejecting all of them works as expected.
1530TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1531 CreateJsepTransportController(JsepTransportController::Config());
1532 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1533 bundle_group.AddContentName(kAudioMid1);
1534 bundle_group.AddContentName(kVideoMid1);
1535 bundle_group.AddContentName(kDataMid1);
1536
Karl Wiberg918f50c2018-07-05 11:40:33 +02001537 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001538 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1539 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1540 nullptr);
1541 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1542 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1543 nullptr);
1544 AddDataSection(local_offer.get(), kDataMid1,
1545 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1546 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1547 nullptr);
1548
Karl Wiberg918f50c2018-07-05 11:40:33 +02001549 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001550 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1551 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1552 nullptr);
1553 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1554 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1555 nullptr);
1556 AddDataSection(remote_answer.get(), kDataMid1,
1557 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1558 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1559 nullptr);
1560 // Reject audio content in answer.
1561 remote_answer->contents()[0].rejected = true;
1562
1563 local_offer->AddGroup(bundle_group);
1564 remote_answer->AddGroup(bundle_group);
1565
1566 EXPECT_TRUE(transport_controller_
1567 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1568 .ok());
1569 EXPECT_FALSE(transport_controller_
1570 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1571 .ok());
1572
1573 // Reject all the contents.
1574 remote_answer->contents()[1].rejected = true;
1575 remote_answer->contents()[2].rejected = true;
1576 EXPECT_TRUE(transport_controller_
1577 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1578 .ok());
1579 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1580 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1581 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1582}
1583
1584// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1585// is used.
1586TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1587 JsepTransportController::Config config;
1588 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1589 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001590 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001591 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1592 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1593 nullptr);
1594
1595 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1596 // Applying a non-RTCP-mux offer is expected to fail.
1597 EXPECT_FALSE(transport_controller_
1598 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1599 .ok());
1600}
1601
1602// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1603// is used.
1604TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1605 JsepTransportController::Config config;
1606 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1607 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001608 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001609 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1610 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1611 nullptr);
1612 EXPECT_TRUE(transport_controller_
1613 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1614 .ok());
1615
Karl Wiberg918f50c2018-07-05 11:40:33 +02001616 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001617 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1618 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1619 nullptr);
1620 // Applying a non-RTCP-mux answer is expected to fail.
1621 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1622 EXPECT_FALSE(transport_controller_
1623 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1624 .ok());
1625}
Zhi Huange818b6e2018-02-22 15:26:27 -08001626
Zhi Huangd2248f82018-04-10 14:41:03 -07001627// This tests that the BUNDLE group in answer should be a subset of the offered
1628// group.
1629TEST_F(JsepTransportControllerTest,
1630 AddContentToBundleGroupInAnswerNotSupported) {
1631 CreateJsepTransportController(JsepTransportController::Config());
1632 auto local_offer = CreateSessionDescriptionWithoutBundle();
1633 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1634
1635 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1636 offer_bundle_group.AddContentName(kAudioMid1);
1637 local_offer->AddGroup(offer_bundle_group);
1638
1639 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1640 answer_bundle_group.AddContentName(kAudioMid1);
1641 answer_bundle_group.AddContentName(kVideoMid1);
1642 remote_answer->AddGroup(answer_bundle_group);
1643 EXPECT_TRUE(transport_controller_
1644 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1645 .ok());
1646 EXPECT_FALSE(transport_controller_
1647 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1648 .ok());
1649}
1650
1651// This tests that the BUNDLE group with non-existing MID should be rejectd.
1652TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1653 CreateJsepTransportController(JsepTransportController::Config());
1654 auto local_offer = CreateSessionDescriptionWithoutBundle();
1655 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1656
1657 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1658 // The BUNDLE group is invalid because there is no data section in the
1659 // description.
1660 invalid_bundle_group.AddContentName(kDataMid1);
1661 local_offer->AddGroup(invalid_bundle_group);
1662 remote_answer->AddGroup(invalid_bundle_group);
1663
1664 EXPECT_FALSE(transport_controller_
1665 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1666 .ok());
1667 EXPECT_FALSE(transport_controller_
1668 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1669 .ok());
1670}
1671
1672// This tests that an answer shouldn't be able to remove an m= section from an
1673// established group without rejecting it.
1674TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1675 CreateJsepTransportController(JsepTransportController::Config());
1676
1677 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1678 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1679 EXPECT_TRUE(transport_controller_
1680 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1681 .ok());
1682 EXPECT_TRUE(transport_controller_
1683 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1684 .ok());
1685
1686 // Do an re-offer/answer.
1687 EXPECT_TRUE(transport_controller_
1688 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1689 .ok());
1690 auto new_answer = CreateSessionDescriptionWithoutBundle();
1691 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1692 // The answer removes video from the BUNDLE group without rejecting it is
1693 // invalid.
1694 new_bundle_group.AddContentName(kAudioMid1);
1695 new_answer->AddGroup(new_bundle_group);
1696
1697 // Applying invalid answer is expected to fail.
1698 EXPECT_FALSE(transport_controller_
1699 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1700 .ok());
1701
1702 // Rejected the video content.
1703 auto video_content = new_answer->GetContentByName(kVideoMid1);
1704 ASSERT_TRUE(video_content);
1705 video_content->rejected = true;
1706 EXPECT_TRUE(transport_controller_
1707 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1708 .ok());
1709}
1710
Zhi Huange818b6e2018-02-22 15:26:27 -08001711} // namespace webrtc