blob: 7b18be880990526499945ccda74a74368ff9d463 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <map>
14#include <memory>
15
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080017#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/media/media_transport_interface.h"
Qingsi Wang25ec8882019-11-15 12:33:05 -080019#include "p2p/base/dtls_transport_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "p2p/base/fake_dtls_transport.h"
21#include "p2p/base/fake_ice_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/thread.h"
25#include "test/gtest.h"
26
Zhi Huange818b6e2018-02-22 15:26:27 -080027using cricket::Candidate;
28using cricket::Candidates;
Jonas Olssona4d87372019-07-05 19:08:33 +020029using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 15:26:27 -080030using webrtc::SdpType;
31
32static const int kTimeout = 100;
33static const char kIceUfrag1[] = "u0001";
34static const char kIcePwd1[] = "TESTICEPWD00000000000001";
35static const char kIceUfrag2[] = "u0002";
36static const char kIcePwd2[] = "TESTICEPWD00000000000002";
37static const char kIceUfrag3[] = "u0003";
38static const char kIcePwd3[] = "TESTICEPWD00000000000003";
39static const char kAudioMid1[] = "audio1";
40static const char kAudioMid2[] = "audio2";
41static const char kVideoMid1[] = "video1";
42static const char kVideoMid2[] = "video2";
43static const char kDataMid1[] = "data1";
44
45namespace webrtc {
46
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070047namespace {
48
49// Media transport factory requires crypto settings to be present in order to
50// create media transport.
51void AddCryptoSettings(cricket::SessionDescription* description) {
52 for (auto& content : description->contents()) {
53 content.media_description()->AddCrypto(cricket::CryptoParams(
54 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
55 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
56 }
57}
58
59} // namespace
60
Qingsi Wang25ec8882019-11-15 12:33:05 -080061class FakeIceTransportFactory : public webrtc::IceTransportFactory {
Zhi Huange818b6e2018-02-22 15:26:27 -080062 public:
Qingsi Wang25ec8882019-11-15 12:33:05 -080063 ~FakeIceTransportFactory() override = default;
64 rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -080065 const std::string& transport_name,
Qingsi Wang25ec8882019-11-15 12:33:05 -080066 int component,
67 IceTransportInit init) override {
68 return new rtc::RefCountedObject<cricket::FakeIceTransportWrapper>(
69 std::make_unique<cricket::FakeIceTransport>(transport_name, component));
Zhi Huange818b6e2018-02-22 15:26:27 -080070 }
Qingsi Wang25ec8882019-11-15 12:33:05 -080071};
Zhi Huange818b6e2018-02-22 15:26:27 -080072
Qingsi Wang25ec8882019-11-15 12:33:05 -080073class FakeDtlsTransportFactory : public cricket::DtlsTransportFactory {
74 public:
Zhi Huange818b6e2018-02-22 15:26:27 -080075 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070076 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070077 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020078 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070079 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080080 }
81};
82
Zhi Huang365381f2018-04-13 16:44:34 -070083class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020084 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080085 public sigslot::has_slots<> {
86 public:
87 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Qingsi Wang25ec8882019-11-15 12:33:05 -080088 fake_ice_transport_factory_ = std::make_unique<FakeIceTransportFactory>();
89 fake_dtls_transport_factory_ = std::make_unique<FakeDtlsTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080090 }
91
92 void CreateJsepTransportController(
93 JsepTransportController::Config config,
94 rtc::Thread* signaling_thread = rtc::Thread::Current(),
95 rtc::Thread* network_thread = rtc::Thread::Current(),
96 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070097 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020098 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
99 int64_t packet_time_us) { RTC_NOTREACHED(); };
Qingsi Wang25ec8882019-11-15 12:33:05 -0800100 config.ice_transport_factory = fake_ice_transport_factory_.get();
101 config.dtls_transport_factory = fake_dtls_transport_factory_.get();
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200102 transport_controller_ = std::make_unique<JsepTransportController>(
Qingsi Wange8d54b92020-01-06 14:31:57 -0800103 signaling_thread, network_thread, port_allocator,
104 nullptr /* async_resolver_factory */, config);
Zhi Huange818b6e2018-02-22 15:26:27 -0800105 ConnectTransportControllerSignals();
106 }
107
108 void ConnectTransportControllerSignals() {
109 transport_controller_->SignalIceConnectionState.connect(
110 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000111 transport_controller_->SignalStandardizedIceConnectionState.connect(
112 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200113 transport_controller_->SignalConnectionState.connect(
114 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800115 transport_controller_->SignalIceGatheringState.connect(
116 this, &JsepTransportControllerTest::OnGatheringState);
117 transport_controller_->SignalIceCandidatesGathered.connect(
118 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800119 }
120
121 std::unique_ptr<cricket::SessionDescription>
122 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200123 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800124 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
125 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
126 nullptr);
127 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
128 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
129 nullptr);
130 return description;
131 }
132
133 std::unique_ptr<cricket::SessionDescription>
134 CreateSessionDescriptionWithBundleGroup() {
135 auto description = CreateSessionDescriptionWithoutBundle();
136 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
137 bundle_group.AddContentName(kAudioMid1);
138 bundle_group.AddContentName(kVideoMid1);
139 description->AddGroup(bundle_group);
140
141 return description;
142 }
143
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700144 std::unique_ptr<cricket::SessionDescription>
145 CreateSessionDescriptionWithBundledData() {
146 auto description = CreateSessionDescriptionWithoutBundle();
147 AddDataSection(description.get(), kDataMid1,
148 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
149 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
150 nullptr);
151 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
152 bundle_group.AddContentName(kAudioMid1);
153 bundle_group.AddContentName(kVideoMid1);
154 bundle_group.AddContentName(kDataMid1);
155 description->AddGroup(bundle_group);
156 return description;
157 }
158
Zhi Huange818b6e2018-02-22 15:26:27 -0800159 void AddAudioSection(cricket::SessionDescription* description,
160 const std::string& mid,
161 const std::string& ufrag,
162 const std::string& pwd,
163 cricket::IceMode ice_mode,
164 cricket::ConnectionRole conn_role,
165 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
166 std::unique_ptr<cricket::AudioContentDescription> audio(
167 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700168 // Set RTCP-mux to be true because the default policy is "mux required".
169 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800170 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200171 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800172 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
173 }
174
175 void AddVideoSection(cricket::SessionDescription* description,
176 const std::string& mid,
177 const std::string& ufrag,
178 const std::string& pwd,
179 cricket::IceMode ice_mode,
180 cricket::ConnectionRole conn_role,
181 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
182 std::unique_ptr<cricket::VideoContentDescription> video(
183 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700184 // Set RTCP-mux to be true because the default policy is "mux required".
185 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800186 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200187 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800188 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
189 }
190
191 void AddDataSection(cricket::SessionDescription* description,
192 const std::string& mid,
193 cricket::MediaProtocolType protocol_type,
194 const std::string& ufrag,
195 const std::string& pwd,
196 cricket::IceMode ice_mode,
197 cricket::ConnectionRole conn_role,
198 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200199 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
200 std::unique_ptr<cricket::SctpDataContentDescription> data(
201 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700202 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800203 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200204 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800205 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
206 }
207
208 void AddTransportInfo(cricket::SessionDescription* description,
209 const std::string& mid,
210 const std::string& ufrag,
211 const std::string& pwd,
212 cricket::IceMode ice_mode,
213 cricket::ConnectionRole conn_role,
214 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
215 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
216 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700217 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800218 }
219
220 cricket::TransportDescription transport_desc(std::vector<std::string>(),
221 ufrag, pwd, ice_mode,
222 conn_role, fingerprint.get());
223 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
224 }
225
226 cricket::IceConfig CreateIceConfig(
227 int receiving_timeout,
228 cricket::ContinualGatheringPolicy continual_gathering_policy) {
229 cricket::IceConfig config;
230 config.receiving_timeout = receiving_timeout;
231 config.continual_gathering_policy = continual_gathering_policy;
232 return config;
233 }
234
235 Candidate CreateCandidate(const std::string& transport_name, int component) {
236 Candidate c;
237 c.set_transport_name(transport_name);
238 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
239 c.set_component(component);
240 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
241 c.set_priority(1);
242 return c;
243 }
244
245 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
246 if (!network_thread_->IsCurrent()) {
247 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
248 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
249 });
250 return;
251 }
252
253 auto description = CreateSessionDescriptionWithBundleGroup();
254 EXPECT_TRUE(transport_controller_
255 ->SetLocalDescription(SdpType::kOffer, description.get())
256 .ok());
257
258 transport_controller_->MaybeStartGathering();
259 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
260 transport_controller_->GetDtlsTransport(kAudioMid1));
261 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
262 transport_controller_->GetDtlsTransport(kVideoMid1));
263 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
264 fake_audio_dtls->fake_ice_transport(),
265 CreateCandidate(kAudioMid1, /*component=*/1));
266 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
267 fake_video_dtls->fake_ice_transport(),
268 CreateCandidate(kVideoMid1, /*component=*/1));
269 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
270 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
271 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
272 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
273 fake_audio_dtls->SetReceiving(true);
274 fake_video_dtls->SetReceiving(true);
275 fake_audio_dtls->SetWritable(true);
276 fake_video_dtls->SetWritable(true);
277 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
278 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
279 }
280
281 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000282 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800283 if (!signaling_thread_->IsCurrent()) {
284 signaled_on_non_signaling_thread_ = true;
285 }
286 connection_state_ = state;
287 ++connection_state_signal_count_;
288 }
289
Alex Loiko9289eda2018-11-23 16:18:59 +0000290 void OnStandardizedIceConnectionState(
291 PeerConnectionInterface::IceConnectionState state) {
292 if (!signaling_thread_->IsCurrent()) {
293 signaled_on_non_signaling_thread_ = true;
294 }
295 ice_connection_state_ = state;
296 ++ice_connection_state_signal_count_;
297 }
298
Jonas Olsson635474e2018-10-18 15:58:17 +0200299 void OnCombinedConnectionState(
300 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100301 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
302 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200303 if (!signaling_thread_->IsCurrent()) {
304 signaled_on_non_signaling_thread_ = true;
305 }
306 combined_connection_state_ = state;
307 ++combined_connection_state_signal_count_;
308 }
309
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 void OnGatheringState(cricket::IceGatheringState state) {
311 if (!signaling_thread_->IsCurrent()) {
312 signaled_on_non_signaling_thread_ = true;
313 }
314 gathering_state_ = state;
315 ++gathering_state_signal_count_;
316 }
317
318 void OnCandidatesGathered(const std::string& transport_name,
319 const Candidates& candidates) {
320 if (!signaling_thread_->IsCurrent()) {
321 signaled_on_non_signaling_thread_ = true;
322 }
323 candidates_[transport_name].insert(candidates_[transport_name].end(),
324 candidates.begin(), candidates.end());
325 ++candidates_signal_count_;
326 }
327
Zhi Huang365381f2018-04-13 16:44:34 -0700328 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700329 bool OnTransportChanged(
330 const std::string& mid,
331 RtpTransportInternal* rtp_transport,
332 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700333 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700334 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100335 if (dtls_transport) {
336 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
337 } else {
338 changed_dtls_transport_by_mid_[mid] = nullptr;
339 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700340 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 }
342
343 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000344 cricket::IceConnectionState connection_state_ =
345 cricket::kIceConnectionConnecting;
346 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200347 PeerConnectionInterface::kIceConnectionNew;
348 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
349 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800350 bool receiving_ = false;
351 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
352 // transport_name => candidates
353 std::map<std::string, Candidates> candidates_;
354 // Counts of each signal emitted.
355 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000356 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200357 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800358 int receiving_signal_count_ = 0;
359 int gathering_state_signal_count_ = 0;
360 int candidates_signal_count_ = 0;
361
362 // |network_thread_| should be destroyed after |transport_controller_|
363 std::unique_ptr<rtc::Thread> network_thread_;
Qingsi Wang25ec8882019-11-15 12:33:05 -0800364 std::unique_ptr<FakeIceTransportFactory> fake_ice_transport_factory_;
365 std::unique_ptr<FakeDtlsTransportFactory> fake_dtls_transport_factory_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800366 rtc::Thread* const signaling_thread_ = nullptr;
367 bool signaled_on_non_signaling_thread_ = false;
368 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
369 // signaled correctly.
370 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
371 std::map<std::string, cricket::DtlsTransportInternal*>
372 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800373
374 // Transport controller needs to be destroyed first, because it may issue
375 // callbacks that modify the changed_*_by_mid in the destructor.
376 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800377};
378
379TEST_F(JsepTransportControllerTest, GetRtpTransport) {
380 CreateJsepTransportController(JsepTransportController::Config());
381 auto description = CreateSessionDescriptionWithoutBundle();
382 EXPECT_TRUE(transport_controller_
383 ->SetLocalDescription(SdpType::kOffer, description.get())
384 .ok());
385 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
386 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
387 EXPECT_NE(nullptr, audio_rtp_transport);
388 EXPECT_NE(nullptr, video_rtp_transport);
389 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
390 // Return nullptr for non-existing ones.
391 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
392}
393
394TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
395 JsepTransportController::Config config;
396 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
397 CreateJsepTransportController(config);
398 auto description = CreateSessionDescriptionWithoutBundle();
399 EXPECT_TRUE(transport_controller_
400 ->SetLocalDescription(SdpType::kOffer, description.get())
401 .ok());
402 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
403 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100404 EXPECT_NE(nullptr,
405 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800406 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
407 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100408 EXPECT_NE(nullptr,
409 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
410 // Lookup for all MIDs should return different transports (no bundle)
411 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
412 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800413 // Return nullptr for non-existing ones.
414 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
415 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100416 EXPECT_EQ(nullptr,
417 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100418 // Take a pointer to a transport, shut down the transport controller,
419 // and verify that the resulting container is empty.
420 auto dtls_transport =
421 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
422 webrtc::DtlsTransport* my_transport =
423 static_cast<DtlsTransport*>(dtls_transport.get());
424 EXPECT_NE(nullptr, my_transport->internal());
425 transport_controller_.reset();
426 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800427}
428
Zhi Huange830e682018-03-30 10:48:35 -0700429TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
430 JsepTransportController::Config config;
431 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
432 CreateJsepTransportController(config);
433 auto description = CreateSessionDescriptionWithoutBundle();
434 EXPECT_TRUE(transport_controller_
435 ->SetLocalDescription(SdpType::kOffer, description.get())
436 .ok());
437 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
438 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
439 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
440 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800441}
442
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700443TEST_F(JsepTransportControllerTest,
444 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
445 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
446 JsepTransportController::Config config;
447
448 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
449 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
450 config.media_transport_factory = &fake_media_transport_factory;
451 config.use_datagram_transport_for_data_channels = true;
452 CreateJsepTransportController(config);
453
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700454 auto description = CreateSessionDescriptionWithBundledData();
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700455 AddCryptoSettings(description.get());
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700456
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700457 absl::optional<cricket::OpaqueTransportParameters> params =
458 transport_controller_->GetTransportParameters(kAudioMid1);
459 for (auto& info : description->transport_infos()) {
460 info.description.opaque_parameters = params;
461 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700462 for (cricket::ContentInfo& content_info : description->contents()) {
463 if (content_info.media_description()->type() == cricket::MEDIA_TYPE_DATA) {
464 content_info.media_description()->set_alt_protocol(params->protocol);
465 }
466 }
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700467
468 EXPECT_TRUE(transport_controller_
469 ->SetLocalDescription(SdpType::kOffer, description.get())
470 .ok());
471 EXPECT_TRUE(transport_controller_
472 ->SetRemoteDescription(SdpType::kAnswer, description.get())
473 .ok());
474
475 FakeDatagramTransport* datagram_transport =
476 static_cast<FakeDatagramTransport*>(
477 transport_controller_->GetDataChannelTransport(kAudioMid1));
478
479 ASSERT_NE(nullptr, datagram_transport);
480
481 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
482 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
483 << "Datagram transport for media was not enabled, and so DTLS transport "
484 "should be created.";
485
486 // Datagram transport is not used for media, so no max packet size is
487 // specified.
488 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
489 .rtp_max_packet_size,
490 absl::nullopt);
491
492 // Since datagram transport is not used for RTP, setting it to writable should
493 // not make the RTP transport writable.
494 datagram_transport->set_state(MediaTransportState::kWritable);
495 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
496 ->IsWritable(/*rtcp=*/false));
497}
498
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700499// An offer that bundles different alt-protocols should be rejected.
500TEST_F(JsepTransportControllerTest, CannotBundleDifferentAltProtocols) {
501 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
502 JsepTransportController::Config config;
503 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
504 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
505 config.media_transport_factory = &fake_media_transport_factory;
506 config.use_datagram_transport = true;
507 config.use_datagram_transport_for_data_channels = true;
508 CreateJsepTransportController(config);
509
510 auto description = CreateSessionDescriptionWithBundledData();
511 AddCryptoSettings(description.get());
512
513 absl::optional<cricket::OpaqueTransportParameters> params =
514 transport_controller_->GetTransportParameters(kAudioMid1);
515 for (auto& info : description->transport_infos()) {
516 info.description.opaque_parameters = params;
517 }
518
519 // Append a different alt-protocol to each of the sections.
520 for (cricket::ContentInfo& content_info : description->contents()) {
521 content_info.media_description()->set_alt_protocol(params->protocol + "-" +
522 content_info.name);
523 }
524
525 EXPECT_FALSE(transport_controller_
526 ->SetLocalDescription(SdpType::kOffer, description.get())
527 .ok());
528 EXPECT_FALSE(transport_controller_
529 ->SetRemoteDescription(SdpType::kAnswer, description.get())
530 .ok());
531}
532
Zhi Huange818b6e2018-02-22 15:26:27 -0800533TEST_F(JsepTransportControllerTest, SetIceConfig) {
534 CreateJsepTransportController(JsepTransportController::Config());
535 auto description = CreateSessionDescriptionWithoutBundle();
536 EXPECT_TRUE(transport_controller_
537 ->SetLocalDescription(SdpType::kOffer, description.get())
538 .ok());
539
540 transport_controller_->SetIceConfig(
541 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
542 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
543 transport_controller_->GetDtlsTransport(kAudioMid1));
544 ASSERT_NE(nullptr, fake_audio_dtls);
545 EXPECT_EQ(kTimeout,
546 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
547 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
548
549 // Test that value stored in controller is applied to new transports.
550 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
551 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
552 nullptr);
553
554 EXPECT_TRUE(transport_controller_
555 ->SetLocalDescription(SdpType::kOffer, description.get())
556 .ok());
557 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
558 transport_controller_->GetDtlsTransport(kAudioMid2));
559 ASSERT_NE(nullptr, fake_audio_dtls);
560 EXPECT_EQ(kTimeout,
561 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
562 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
563}
564
565// Tests the getter and setter of the ICE restart flag.
566TEST_F(JsepTransportControllerTest, NeedIceRestart) {
567 CreateJsepTransportController(JsepTransportController::Config());
568 auto description = CreateSessionDescriptionWithoutBundle();
569 EXPECT_TRUE(transport_controller_
570 ->SetLocalDescription(SdpType::kOffer, description.get())
571 .ok());
572 EXPECT_TRUE(transport_controller_
573 ->SetRemoteDescription(SdpType::kAnswer, description.get())
574 .ok());
575
576 // Initially NeedsIceRestart should return false.
577 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
578 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
579 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
580 // true.
581 transport_controller_->SetNeedsIceRestartFlag();
582 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
583 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
584 // For a nonexistent transport, false should be returned.
585 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
586
587 // Reset the ice_ufrag/ice_pwd for audio.
588 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
589 audio_transport_info->description.ice_ufrag = kIceUfrag2;
590 audio_transport_info->description.ice_pwd = kIcePwd2;
591 EXPECT_TRUE(transport_controller_
592 ->SetLocalDescription(SdpType::kOffer, description.get())
593 .ok());
594 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
595 // return false for audio and true for video.
596 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
597 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
598}
599
600TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
601 CreateJsepTransportController(JsepTransportController::Config());
602 auto description = CreateSessionDescriptionWithBundleGroup();
603 EXPECT_TRUE(transport_controller_
604 ->SetLocalDescription(SdpType::kOffer, description.get())
605 .ok());
606 // After setting the local description, we should be able to start gathering
607 // candidates.
608 transport_controller_->MaybeStartGathering();
609 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
610 EXPECT_EQ(1, gathering_state_signal_count_);
611}
612
613TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
614 CreateJsepTransportController(JsepTransportController::Config());
615 auto description = CreateSessionDescriptionWithoutBundle();
616 transport_controller_->SetLocalDescription(SdpType::kOffer,
617 description.get());
618 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
619 description.get());
620 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
621 transport_controller_->GetDtlsTransport(kAudioMid1));
622 ASSERT_NE(nullptr, fake_audio_dtls);
623 Candidates candidates;
624 candidates.push_back(
625 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
626 EXPECT_TRUE(
627 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
628 EXPECT_EQ(1U,
629 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
630
631 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
632 EXPECT_EQ(0U,
633 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
634}
635
636TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
637 CreateJsepTransportController(JsepTransportController::Config());
638
639 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100640 rtc::RTCCertificate::Create(
641 rtc::SSLIdentity::Create("session1", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 15:26:27 -0800642 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
643
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200644 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800645 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
646 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
647 certificate1);
648
649 // Apply the local certificate.
650 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
651 // Apply the local description.
652 EXPECT_TRUE(transport_controller_
653 ->SetLocalDescription(SdpType::kOffer, description.get())
654 .ok());
655 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
656 EXPECT_TRUE(returned_certificate);
657 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
658 returned_certificate->identity()->certificate().ToPEMString());
659
660 // Should fail if called for a nonexistant transport.
661 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
662
663 // Shouldn't be able to change the identity once set.
664 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100665 rtc::RTCCertificate::Create(
666 rtc::SSLIdentity::Create("session2", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 15:26:27 -0800667 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
668}
669
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800670TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800671 CreateJsepTransportController(JsepTransportController::Config());
672 auto description = CreateSessionDescriptionWithBundleGroup();
673 EXPECT_TRUE(transport_controller_
674 ->SetLocalDescription(SdpType::kOffer, description.get())
675 .ok());
676 rtc::FakeSSLCertificate fake_certificate("fake_data");
677
678 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
679 transport_controller_->GetDtlsTransport(kAudioMid1));
680 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800681 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
682 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
683 ASSERT_TRUE(returned_cert_chain);
684 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800685 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800686 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800687
688 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800689 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800690}
691
692TEST_F(JsepTransportControllerTest, GetDtlsRole) {
693 CreateJsepTransportController(JsepTransportController::Config());
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100694 auto offer_certificate = rtc::RTCCertificate::Create(
695 rtc::SSLIdentity::Create("offer", rtc::KT_DEFAULT));
696 auto answer_certificate = rtc::RTCCertificate::Create(
697 rtc::SSLIdentity::Create("answer", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 15:26:27 -0800698 transport_controller_->SetLocalCertificate(offer_certificate);
699
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200700 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800701 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
702 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
703 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200704 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800705 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
706 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
707 answer_certificate);
708
709 EXPECT_TRUE(transport_controller_
710 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
711 .ok());
712
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200713 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800714 transport_controller_->GetDtlsRole(kAudioMid1);
715 // The DTLS role is not decided yet.
716 EXPECT_FALSE(role);
717 EXPECT_TRUE(transport_controller_
718 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
719 .ok());
720 role = transport_controller_->GetDtlsRole(kAudioMid1);
721
722 ASSERT_TRUE(role);
723 EXPECT_EQ(rtc::SSL_CLIENT, *role);
724}
725
726TEST_F(JsepTransportControllerTest, GetStats) {
727 CreateJsepTransportController(JsepTransportController::Config());
728 auto description = CreateSessionDescriptionWithBundleGroup();
729 EXPECT_TRUE(transport_controller_
730 ->SetLocalDescription(SdpType::kOffer, description.get())
731 .ok());
732
733 cricket::TransportStats stats;
734 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
735 EXPECT_EQ(kAudioMid1, stats.transport_name);
736 EXPECT_EQ(1u, stats.channel_stats.size());
737 // Return false for non-existing transport.
738 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
739}
740
741TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
742 CreateJsepTransportController(JsepTransportController::Config());
743 auto description = CreateSessionDescriptionWithoutBundle();
744 EXPECT_TRUE(transport_controller_
745 ->SetLocalDescription(SdpType::kOffer, description.get())
746 .ok());
747
748 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
749 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
750 fake_ice->SetCandidatesGatheringComplete();
751 fake_ice->SetConnectionCount(1);
752 // The connection stats will be failed if there is no active connection.
753 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000754 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100755 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000756 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
757 ice_connection_state_, kTimeout);
758 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100759 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
760 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200761 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800762}
763
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700764TEST_F(JsepTransportControllerTest,
765 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800766 CreateJsepTransportController(JsepTransportController::Config());
767 auto description = CreateSessionDescriptionWithoutBundle();
768 EXPECT_TRUE(transport_controller_
769 ->SetLocalDescription(SdpType::kOffer, description.get())
770 .ok());
771
772 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
773 transport_controller_->GetDtlsTransport(kAudioMid1));
774 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
775 transport_controller_->GetDtlsTransport(kVideoMid1));
776
777 // First, have one transport connect, and another fail, to ensure that
778 // the first transport connecting didn't trigger a "connected" state signal.
779 // We should only get a signal when all are connected.
780 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
781 fake_audio_dtls->SetWritable(true);
782 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
783 // Decrease the number of the connection to trigger the signal.
784 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
785 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
786 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
787
Alex Loiko9289eda2018-11-23 16:18:59 +0000788 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100789 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000790 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
791 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100792 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100793 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
794 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100795 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800796
Jonas Olsson635474e2018-10-18 15:58:17 +0200797 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
798 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800799 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
800 // the transport state to be STATE_CONNECTING.
801 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
802 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000803 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100804 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000805 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
806 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100807 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100808 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
809 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100810 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800811}
812
813TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
814 CreateJsepTransportController(JsepTransportController::Config());
815 auto description = CreateSessionDescriptionWithoutBundle();
816 EXPECT_TRUE(transport_controller_
817 ->SetLocalDescription(SdpType::kOffer, description.get())
818 .ok());
819
820 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
821 transport_controller_->GetDtlsTransport(kAudioMid1));
822 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
823 transport_controller_->GetDtlsTransport(kVideoMid1));
824
825 // First, have one transport connect, and another fail, to ensure that
826 // the first transport connecting didn't trigger a "connected" state signal.
827 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100828 fake_audio_dtls->fake_ice_transport()->SetTransportState(
829 IceTransportState::kCompleted,
830 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800831 fake_audio_dtls->SetWritable(true);
832 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100833
834 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
835 ice_connection_state_, kTimeout);
836 EXPECT_EQ(1, ice_connection_state_signal_count_);
837 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
838 combined_connection_state_, kTimeout);
839 EXPECT_EQ(1, combined_connection_state_signal_count_);
840
841 fake_video_dtls->fake_ice_transport()->SetTransportState(
842 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800843 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
844
Alex Loiko9289eda2018-11-23 16:18:59 +0000845 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100846 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000847 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
848 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100849 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100850 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
851 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100852 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800853
Jonas Olsson635474e2018-10-18 15:58:17 +0200854 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
855 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800856 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
857 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100858 fake_video_dtls->fake_ice_transport()->SetTransportState(
859 IceTransportState::kCompleted,
860 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800861 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000862 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100863 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000864 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
865 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100866 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100867 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
868 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100869 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800870}
871
872TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
873 CreateJsepTransportController(JsepTransportController::Config());
874 auto description = CreateSessionDescriptionWithoutBundle();
875 EXPECT_TRUE(transport_controller_
876 ->SetLocalDescription(SdpType::kOffer, description.get())
877 .ok());
878
879 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
880 transport_controller_->GetDtlsTransport(kAudioMid1));
881 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
882 // Should be in the gathering state as soon as any transport starts gathering.
883 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
884 EXPECT_EQ(1, gathering_state_signal_count_);
885}
886
887TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
888 CreateJsepTransportController(JsepTransportController::Config());
889 auto description = CreateSessionDescriptionWithoutBundle();
890 EXPECT_TRUE(transport_controller_
891 ->SetLocalDescription(SdpType::kOffer, description.get())
892 .ok());
893
894 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
895 transport_controller_->GetDtlsTransport(kAudioMid1));
896 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
897 transport_controller_->GetDtlsTransport(kVideoMid1));
898
899 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
900 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
901 EXPECT_EQ(1, gathering_state_signal_count_);
902
903 // Have one transport finish gathering, to make sure gathering
904 // completion wasn't signalled if only one transport finished gathering.
905 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
906 EXPECT_EQ(1, gathering_state_signal_count_);
907
908 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
909 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
910 EXPECT_EQ(1, gathering_state_signal_count_);
911
912 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
913 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
914 EXPECT_EQ(2, gathering_state_signal_count_);
915}
916
917// Test that when the last transport that hasn't finished connecting and/or
918// gathering is destroyed, the aggregate state jumps to "completed". This can
919// happen if, for example, we have an audio and video transport, the audio
920// transport completes, then we start bundling video on the audio transport.
921TEST_F(JsepTransportControllerTest,
922 SignalingWhenLastIncompleteTransportDestroyed) {
923 CreateJsepTransportController(JsepTransportController::Config());
924 auto description = CreateSessionDescriptionWithBundleGroup();
925 EXPECT_TRUE(transport_controller_
926 ->SetLocalDescription(SdpType::kOffer, description.get())
927 .ok());
928
929 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
930 transport_controller_->GetDtlsTransport(kAudioMid1));
931 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
932 transport_controller_->GetDtlsTransport(kVideoMid1));
933 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
934
935 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
936 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
937 EXPECT_EQ(1, gathering_state_signal_count_);
938
939 // Let the audio transport complete.
940 fake_audio_dtls->SetWritable(true);
941 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
942 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +0200943 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800944 EXPECT_EQ(1, gathering_state_signal_count_);
945
946 // Set the remote description and enable the bundle.
947 EXPECT_TRUE(transport_controller_
948 ->SetRemoteDescription(SdpType::kAnswer, description.get())
949 .ok());
950 // The BUNDLE should be enabled, the incomplete video transport should be
951 // deleted and the states shoud be updated.
952 fake_video_dtls = static_cast<FakeDtlsTransport*>(
953 transport_controller_->GetDtlsTransport(kVideoMid1));
954 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +0000955 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
956 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
957 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +0200958 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
959 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800960 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
961 EXPECT_EQ(2, gathering_state_signal_count_);
962}
963
964TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
965 CreateJsepTransportController(JsepTransportController::Config());
966 auto description = CreateSessionDescriptionWithBundleGroup();
967 EXPECT_TRUE(transport_controller_
968 ->SetLocalDescription(SdpType::kOffer, description.get())
969 .ok());
970 transport_controller_->MaybeStartGathering();
971
972 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
973 transport_controller_->GetDtlsTransport(kAudioMid1));
974 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
975 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
976 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
977 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
978}
979
980TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
981 network_thread_ = rtc::Thread::CreateWithSocketServer();
982 network_thread_->Start();
983 CreateJsepTransportController(JsepTransportController::Config(),
984 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +0100985 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -0800986 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
987
988 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +0000989 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -0800990 EXPECT_EQ(2, connection_state_signal_count_);
991
992 // new --> gathering --> complete
993 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
994 EXPECT_EQ(2, gathering_state_signal_count_);
995
996 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
997 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
998 EXPECT_EQ(2, candidates_signal_count_);
999
1000 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1001}
1002
1003// Older versions of Chrome expect the ICE role to be re-determined when an
1004// ICE restart occurs, and also don't perform conflict resolution correctly,
1005// so for now we can't safely stop doing this.
1006// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1007// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1008// enough population.
1009TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1010 CreateJsepTransportController(JsepTransportController::Config());
1011 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001012 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001013 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1014 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1015 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001016 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001017 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1018 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1019 nullptr);
1020
1021 EXPECT_TRUE(transport_controller_
1022 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1023 .ok());
1024 EXPECT_TRUE(transport_controller_
1025 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1026 .ok());
1027
1028 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1029 transport_controller_->GetDtlsTransport(kAudioMid1));
1030 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1031 fake_dtls->fake_ice_transport()->GetIceRole());
1032
1033 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001034 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001035 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1036 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1037 nullptr);
1038 EXPECT_TRUE(
1039 transport_controller_
1040 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1041 .ok());
1042 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1043 fake_dtls->fake_ice_transport()->GetIceRole());
1044}
1045
1046// Test that if the TransportController was created with the
1047// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1048// redetermined on an ICE restart.
1049TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1050 JsepTransportController::Config config;
1051 config.redetermine_role_on_ice_restart = false;
1052
1053 CreateJsepTransportController(config);
1054 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001055 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001056 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1057 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1058 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001059 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001060 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1061 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1062 nullptr);
1063
1064 EXPECT_TRUE(transport_controller_
1065 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1066 .ok());
1067 EXPECT_TRUE(transport_controller_
1068 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1069 .ok());
1070
1071 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1072 transport_controller_->GetDtlsTransport(kAudioMid1));
1073 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1074 fake_dtls->fake_ice_transport()->GetIceRole());
1075
1076 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001077 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001078 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1079 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1080 nullptr);
1081 EXPECT_TRUE(
1082 transport_controller_
1083 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1084 .ok());
1085 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1086 fake_dtls->fake_ice_transport()->GetIceRole());
1087}
1088
1089// Tests ICE-Lite mode in remote answer.
1090TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1091 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001092 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001093 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1094 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1095 nullptr);
1096 EXPECT_TRUE(transport_controller_
1097 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1098 .ok());
1099 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1100 transport_controller_->GetDtlsTransport(kAudioMid1));
1101 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1102 fake_dtls->fake_ice_transport()->GetIceRole());
1103 EXPECT_EQ(cricket::ICEMODE_FULL,
1104 fake_dtls->fake_ice_transport()->remote_ice_mode());
1105
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001106 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001107 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1108 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1109 nullptr);
1110 EXPECT_TRUE(transport_controller_
1111 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1112 .ok());
1113 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1114 fake_dtls->fake_ice_transport()->GetIceRole());
1115 EXPECT_EQ(cricket::ICEMODE_LITE,
1116 fake_dtls->fake_ice_transport()->remote_ice_mode());
1117}
1118
1119// Tests that the ICE role remains "controlling" if a subsequent offer that
1120// does an ICE restart is received from an ICE lite endpoint. Regression test
1121// for: https://crbug.com/710760
1122TEST_F(JsepTransportControllerTest,
1123 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1124 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001125 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001126 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1127 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1128 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001129 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001130 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1131 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1132 nullptr);
1133 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1134 // local side is the controlling.
1135 EXPECT_TRUE(transport_controller_
1136 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1137 .ok());
1138 EXPECT_TRUE(transport_controller_
1139 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1140 .ok());
1141 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1142 transport_controller_->GetDtlsTransport(kAudioMid1));
1143 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1144 fake_dtls->fake_ice_transport()->GetIceRole());
1145
1146 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001147 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001148 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1149 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1150 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001151 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001152 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1153 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1154 nullptr);
1155 EXPECT_TRUE(transport_controller_
1156 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1157 .ok());
1158 EXPECT_TRUE(transport_controller_
1159 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1160 .ok());
1161 fake_dtls = static_cast<FakeDtlsTransport*>(
1162 transport_controller_->GetDtlsTransport(kAudioMid1));
1163 // The local side is still the controlling role since the remote side is using
1164 // ICE-Lite.
1165 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1166 fake_dtls->fake_ice_transport()->GetIceRole());
1167}
1168
1169// Tests that the SDP has more than one audio/video m= sections.
1170TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1171 CreateJsepTransportController(JsepTransportController::Config());
1172 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1173 bundle_group.AddContentName(kAudioMid1);
1174 bundle_group.AddContentName(kAudioMid2);
1175 bundle_group.AddContentName(kVideoMid1);
1176 bundle_group.AddContentName(kDataMid1);
1177
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001178 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001179 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1180 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1181 nullptr);
1182 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1183 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1184 nullptr);
1185 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1186 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1187 nullptr);
1188 AddDataSection(local_offer.get(), kDataMid1,
1189 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1190 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1191 nullptr);
1192
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001193 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001194 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1195 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1196 nullptr);
1197 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1198 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1199 nullptr);
1200 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1201 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1202 nullptr);
1203 AddDataSection(remote_answer.get(), kDataMid1,
1204 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1205 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1206 nullptr);
1207
1208 local_offer->AddGroup(bundle_group);
1209 remote_answer->AddGroup(bundle_group);
1210
1211 EXPECT_TRUE(transport_controller_
1212 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1213 .ok());
1214 EXPECT_TRUE(transport_controller_
1215 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1216 .ok());
1217 // Verify that all the sections are bundled on kAudio1.
1218 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1219 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1220 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1221 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1222 EXPECT_EQ(transport1, transport2);
1223 EXPECT_EQ(transport1, transport3);
1224 EXPECT_EQ(transport1, transport4);
1225
Harald Alvestrandad88c882018-11-28 16:47:46 +01001226 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1227 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1228
Zhi Huange818b6e2018-02-22 15:26:27 -08001229 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1230 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1231 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1232 EXPECT_EQ(transport1, it->second);
1233 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1234 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1235 EXPECT_EQ(transport1, it->second);
1236 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1237 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1238 EXPECT_EQ(transport1, it->second);
1239 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1240 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1241 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001242}
1243
1244// Tests that only a subset of all the m= sections are bundled.
1245TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1246 CreateJsepTransportController(JsepTransportController::Config());
1247 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1248 bundle_group.AddContentName(kAudioMid1);
1249 bundle_group.AddContentName(kVideoMid1);
1250
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001251 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001252 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1253 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1254 nullptr);
1255 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1256 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1257 nullptr);
1258 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1259 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1260 nullptr);
1261
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001262 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001263 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1264 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1265 nullptr);
1266 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1267 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1268 nullptr);
1269 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1270 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1271 nullptr);
1272
1273 local_offer->AddGroup(bundle_group);
1274 remote_answer->AddGroup(bundle_group);
1275 EXPECT_TRUE(transport_controller_
1276 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1277 .ok());
1278 EXPECT_TRUE(transport_controller_
1279 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1280 .ok());
1281
1282 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1283 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1284 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1285 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1286 EXPECT_NE(transport1, transport2);
1287 EXPECT_EQ(transport1, transport3);
1288
1289 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1290 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1291 EXPECT_EQ(transport1, it->second);
1292 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001293 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001294}
1295
1296// Tests that the initial offer/answer only have data section and audio/video
1297// sections are added in the subsequent offer.
1298TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1299 CreateJsepTransportController(JsepTransportController::Config());
1300 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1301 bundle_group.AddContentName(kDataMid1);
1302
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001303 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001304 AddDataSection(local_offer.get(), kDataMid1,
1305 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1306 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1307 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001308 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001309 AddDataSection(remote_answer.get(), kDataMid1,
1310 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1311 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1312 nullptr);
1313 local_offer->AddGroup(bundle_group);
1314 remote_answer->AddGroup(bundle_group);
1315
1316 EXPECT_TRUE(transport_controller_
1317 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1318 .ok());
1319 EXPECT_TRUE(transport_controller_
1320 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1321 .ok());
1322 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1323
1324 // Add audio/video sections in subsequent offer.
1325 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1326 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1327 nullptr);
1328 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1329 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1330 nullptr);
1331 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1332 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1333 nullptr);
1334 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1335 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1336 nullptr);
1337
1338 // Reset the bundle group and do another offer/answer exchange.
1339 bundle_group.AddContentName(kAudioMid1);
1340 bundle_group.AddContentName(kVideoMid1);
1341 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1342 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1343 local_offer->AddGroup(bundle_group);
1344 remote_answer->AddGroup(bundle_group);
1345
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 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1354 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1355 EXPECT_EQ(data_transport, audio_transport);
1356 EXPECT_EQ(data_transport, video_transport);
1357}
1358
1359TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1360 CreateJsepTransportController(JsepTransportController::Config());
1361 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1362 bundle_group.AddContentName(kAudioMid1);
1363 bundle_group.AddContentName(kVideoMid1);
1364 bundle_group.AddContentName(kDataMid1);
1365
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001366 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001367 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1368 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1369 nullptr);
1370 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1371 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1372 nullptr);
1373 AddDataSection(local_offer.get(), kDataMid1,
1374 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1375 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1376 nullptr);
1377
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001378 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001379 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1380 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1381 nullptr);
1382 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1383 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1384 nullptr);
1385 AddDataSection(remote_answer.get(), kDataMid1,
1386 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1387 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1388 nullptr);
1389 // Reject video and data section.
1390 remote_answer->contents()[1].rejected = true;
1391 remote_answer->contents()[2].rejected = true;
1392
1393 local_offer->AddGroup(bundle_group);
1394 remote_answer->AddGroup(bundle_group);
1395
1396 EXPECT_TRUE(transport_controller_
1397 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1398 .ok());
1399 EXPECT_TRUE(transport_controller_
1400 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1401 .ok());
1402
1403 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1404 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1405 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1406 // Verify the signals are fired correctly.
1407 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1408 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1409 EXPECT_EQ(nullptr, it->second);
1410 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1411 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1412 EXPECT_EQ(nullptr, it2->second);
1413}
1414
1415// Tests that changing the bundled MID in subsequent offer/answer exchange is
1416// not supported.
1417// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1418// fixed
1419TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1420 CreateJsepTransportController(JsepTransportController::Config());
1421 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1422 bundle_group.AddContentName(kAudioMid1);
1423 bundle_group.AddContentName(kVideoMid1);
1424
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001425 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001426 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1427 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1428 nullptr);
1429 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1430 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1431 nullptr);
1432
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001433 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001434 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1435 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1436 nullptr);
1437 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1438 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1439 nullptr);
1440
1441 local_offer->AddGroup(bundle_group);
1442 remote_answer->AddGroup(bundle_group);
1443 EXPECT_TRUE(transport_controller_
1444 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1445 .ok());
1446 EXPECT_TRUE(transport_controller_
1447 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1448 .ok());
1449 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1450 transport_controller_->GetRtpTransport(kVideoMid1));
1451
1452 // Reorder the bundle group.
1453 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1454 bundle_group.AddContentName(kAudioMid1);
1455 // The answerer uses the new bundle group and now the bundle mid is changed to
1456 // |kVideo1|.
1457 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1458 remote_answer->AddGroup(bundle_group);
1459 EXPECT_TRUE(transport_controller_
1460 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1461 .ok());
1462 EXPECT_FALSE(transport_controller_
1463 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1464 .ok());
1465}
Zhi Huange830e682018-03-30 10:48:35 -07001466// Test that rejecting only the first m= section of a BUNDLE group is treated as
1467// an error, but rejecting all of them works as expected.
1468TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1469 CreateJsepTransportController(JsepTransportController::Config());
1470 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1471 bundle_group.AddContentName(kAudioMid1);
1472 bundle_group.AddContentName(kVideoMid1);
1473 bundle_group.AddContentName(kDataMid1);
1474
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001475 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001476 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1477 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1478 nullptr);
1479 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1480 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1481 nullptr);
1482 AddDataSection(local_offer.get(), kDataMid1,
1483 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1484 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1485 nullptr);
1486
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001487 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001488 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1489 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1490 nullptr);
1491 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1492 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1493 nullptr);
1494 AddDataSection(remote_answer.get(), kDataMid1,
1495 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1496 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1497 nullptr);
1498 // Reject audio content in answer.
1499 remote_answer->contents()[0].rejected = true;
1500
1501 local_offer->AddGroup(bundle_group);
1502 remote_answer->AddGroup(bundle_group);
1503
1504 EXPECT_TRUE(transport_controller_
1505 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1506 .ok());
1507 EXPECT_FALSE(transport_controller_
1508 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1509 .ok());
1510
1511 // Reject all the contents.
1512 remote_answer->contents()[1].rejected = true;
1513 remote_answer->contents()[2].rejected = true;
1514 EXPECT_TRUE(transport_controller_
1515 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1516 .ok());
1517 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1518 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1519 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1520}
1521
1522// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1523// is used.
1524TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1525 JsepTransportController::Config config;
1526 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1527 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001528 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001529 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1530 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1531 nullptr);
1532
1533 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1534 // Applying a non-RTCP-mux offer is expected to fail.
1535 EXPECT_FALSE(transport_controller_
1536 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1537 .ok());
1538}
1539
1540// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1541// is used.
1542TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1543 JsepTransportController::Config config;
1544 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1545 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001546 auto local_offer = std::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 EXPECT_TRUE(transport_controller_
1551 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1552 .ok());
1553
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001554 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001555 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1556 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1557 nullptr);
1558 // Applying a non-RTCP-mux answer is expected to fail.
1559 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1560 EXPECT_FALSE(transport_controller_
1561 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1562 .ok());
1563}
Zhi Huange818b6e2018-02-22 15:26:27 -08001564
Zhi Huangd2248f82018-04-10 14:41:03 -07001565// This tests that the BUNDLE group in answer should be a subset of the offered
1566// group.
1567TEST_F(JsepTransportControllerTest,
1568 AddContentToBundleGroupInAnswerNotSupported) {
1569 CreateJsepTransportController(JsepTransportController::Config());
1570 auto local_offer = CreateSessionDescriptionWithoutBundle();
1571 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1572
1573 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1574 offer_bundle_group.AddContentName(kAudioMid1);
1575 local_offer->AddGroup(offer_bundle_group);
1576
1577 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1578 answer_bundle_group.AddContentName(kAudioMid1);
1579 answer_bundle_group.AddContentName(kVideoMid1);
1580 remote_answer->AddGroup(answer_bundle_group);
1581 EXPECT_TRUE(transport_controller_
1582 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1583 .ok());
1584 EXPECT_FALSE(transport_controller_
1585 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1586 .ok());
1587}
1588
1589// This tests that the BUNDLE group with non-existing MID should be rejectd.
1590TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1591 CreateJsepTransportController(JsepTransportController::Config());
1592 auto local_offer = CreateSessionDescriptionWithoutBundle();
1593 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1594
1595 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1596 // The BUNDLE group is invalid because there is no data section in the
1597 // description.
1598 invalid_bundle_group.AddContentName(kDataMid1);
1599 local_offer->AddGroup(invalid_bundle_group);
1600 remote_answer->AddGroup(invalid_bundle_group);
1601
1602 EXPECT_FALSE(transport_controller_
1603 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1604 .ok());
1605 EXPECT_FALSE(transport_controller_
1606 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1607 .ok());
1608}
1609
1610// This tests that an answer shouldn't be able to remove an m= section from an
1611// established group without rejecting it.
1612TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1613 CreateJsepTransportController(JsepTransportController::Config());
1614
1615 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1616 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1617 EXPECT_TRUE(transport_controller_
1618 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1619 .ok());
1620 EXPECT_TRUE(transport_controller_
1621 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1622 .ok());
1623
1624 // Do an re-offer/answer.
1625 EXPECT_TRUE(transport_controller_
1626 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1627 .ok());
1628 auto new_answer = CreateSessionDescriptionWithoutBundle();
1629 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1630 // The answer removes video from the BUNDLE group without rejecting it is
1631 // invalid.
1632 new_bundle_group.AddContentName(kAudioMid1);
1633 new_answer->AddGroup(new_bundle_group);
1634
1635 // Applying invalid answer is expected to fail.
1636 EXPECT_FALSE(transport_controller_
1637 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1638 .ok());
1639
1640 // Rejected the video content.
1641 auto video_content = new_answer->GetContentByName(kVideoMid1);
1642 ASSERT_TRUE(video_content);
1643 video_content->rejected = true;
1644 EXPECT_TRUE(transport_controller_
1645 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1646 .ok());
1647}
1648
Steve Anton2bed3972019-01-04 17:04:30 -08001649// Test that the JsepTransportController can process a new local and remote
1650// description that changes the tagged BUNDLE group with the max-bundle policy
1651// specified.
1652// This is a regression test for bugs.webrtc.org/9954
1653TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1654 CreateJsepTransportController(JsepTransportController::Config());
1655
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001656 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08001657 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1658 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1659 nullptr);
1660 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1661 bundle_group.AddContentName(kAudioMid1);
1662 local_offer->AddGroup(bundle_group);
1663 EXPECT_TRUE(transport_controller_
1664 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1665 .ok());
1666
1667 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001668 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001669 EXPECT_TRUE(transport_controller_
1670 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1671 .ok());
1672
1673 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001674 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001675 local_reoffer->contents()[0].rejected = true;
1676 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1677 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1678 nullptr);
1679 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1680 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1681 new_bundle_group.AddContentName(kVideoMid1);
1682 local_reoffer->AddGroup(new_bundle_group);
1683
1684 EXPECT_TRUE(transport_controller_
1685 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1686 .ok());
1687
1688 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001689 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001690 EXPECT_TRUE(
1691 transport_controller_
1692 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1693 .ok());
1694}
1695
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001696constexpr char kFakeTransportParameters[] = "fake-params";
1697
1698// Test fixture that provides common setup and helpers for tests related to the
1699// datagram transport.
1700class JsepTransportControllerDatagramTest
1701 : public JsepTransportControllerTest,
1702 public testing::WithParamInterface<bool> {
1703 public:
1704 JsepTransportControllerDatagramTest()
1705 : JsepTransportControllerTest(),
1706 fake_media_transport_factory_(kFakeTransportParameters) {
1707 JsepTransportController::Config config;
1708 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1709 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1710 config.media_transport_factory = &fake_media_transport_factory_;
1711 config.use_datagram_transport = true;
1712 CreateJsepTransportController(config);
1713 }
1714
1715 // Whether the JsepTransportController under test acts as the offerer or
1716 // answerer in this test.
1717 bool IsOfferer() { return GetParam(); }
1718
1719 // Sets a description as local or remote based on type and current
1720 // perspective.
1721 RTCError SetDescription(SdpType type,
1722 const cricket::SessionDescription* description) {
1723 if (IsOfferer() == (type == SdpType::kOffer)) {
1724 return transport_controller_->SetLocalDescription(type, description);
1725 } else {
1726 return transport_controller_->SetRemoteDescription(type, description);
1727 }
1728 }
1729
1730 // Creates a session description with the settings necessary for datagram
1731 // transport (bundle + crypto) and the given |transport_params|.
1732 std::unique_ptr<cricket::SessionDescription>
1733 CreateSessionDescriptionForDatagramTransport(
1734 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
1735 auto description = CreateSessionDescriptionWithBundleGroup();
1736 AddCryptoSettings(description.get());
1737
1738 for (auto& info : description->transport_infos()) {
1739 info.description.opaque_parameters = transport_params;
1740 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07001741 if (transport_params) {
1742 for (auto& content_info : description->contents()) {
1743 content_info.media_description()->set_alt_protocol(
1744 transport_params->protocol);
1745 }
1746 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001747 return description;
1748 }
1749
1750 // Creates transport parameters with |protocol| and |parameters|
1751 // matching what |fake_media_transport_factory_| provides.
1752 cricket::OpaqueTransportParameters CreateTransportParameters() {
1753 cricket::OpaqueTransportParameters params;
1754 params.protocol = fake_media_transport_factory_.GetTransportName();
1755 params.parameters = "fake-params";
1756 return params;
1757 }
1758
1759 protected:
1760 FakeMediaTransportFactory fake_media_transport_factory_;
1761};
1762
1763TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
1764 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1765 if (IsOfferer()) {
1766 // Getting transport parameters is allowed before setting a description.
1767 // This is necessary so that the offerer can include these params.
1768 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1769 fake_params);
1770 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1771 fake_params);
1772 }
1773
1774 // Setting a description activates the datagram transport without changing
1775 // transport parameters.
1776 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1777 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1778
1779 // After setting an offer with transport parameters, those parameters are
1780 // reflected by the controller.
1781 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1782 fake_params);
1783 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1784 fake_params);
1785}
1786
1787TEST_P(JsepTransportControllerDatagramTest,
1788 OfferMissingDatagramTransportParams) {
1789 if (IsOfferer()) {
1790 // This test doesn't make sense from the offerer's perspective, as the offer
1791 // must contain datagram transport params if the offerer supports it.
1792 return;
1793 }
1794
1795 auto description =
1796 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1797 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1798
1799 // The offer didn't contain any datagram transport parameters, so the answer
1800 // won't either.
1801 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1802 absl::nullopt);
1803 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1804 absl::nullopt);
1805}
1806
1807TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
1808 if (IsOfferer()) {
1809 // This test doesn't make sense from the offerer's perspective, as the
1810 // offerer cannot offer itself the wrong transport.
1811 return;
1812 }
1813
1814 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1815 fake_params.protocol = "wrong-name";
1816
1817 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1818 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1819
1820 // The offerer and answerer support different datagram transports, so the
1821 // answerer rejects the offered parameters.
1822 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1823 absl::nullopt);
1824 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1825 absl::nullopt);
1826}
1827
Bjorn A Mellem0cda7b82020-01-28 17:06:55 -08001828TEST_P(JsepTransportControllerDatagramTest, IncompatibleAnswer) {
1829 // Transport will claim that no parameters are compatible, even if they match
1830 // exactly.
1831 fake_media_transport_factory_.set_transport_parameters_comparison(
1832 [](absl::string_view, absl::string_view) { return false; });
1833
1834 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1835 if (IsOfferer()) {
1836 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1837 fake_params);
1838 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1839 fake_params);
1840 }
1841
1842 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1843 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1844
1845 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1846 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1847
1848 // The offerer and answerer have incompatible parameters, so the answerer
1849 // rejects the offered parameters.
1850 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1851 absl::nullopt);
1852 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1853 absl::nullopt);
1854}
1855
1856TEST_P(JsepTransportControllerDatagramTest, CompatibleAnswer) {
1857 // Transport will claim that no parameters are compatible, even if they are
1858 // completely different.
1859 fake_media_transport_factory_.set_transport_parameters_comparison(
1860 [](absl::string_view, absl::string_view) { return true; });
1861
1862 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1863 if (IsOfferer()) {
1864 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1865 fake_params);
1866 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1867 fake_params);
1868 }
1869
1870 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1871 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1872
1873 cricket::OpaqueTransportParameters answer_params;
1874 answer_params.protocol = fake_params.protocol;
1875 answer_params.parameters = "something different from offer";
1876 auto answer = CreateSessionDescriptionForDatagramTransport(answer_params);
1877 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1878
1879 // The offerer and answerer have compatible parameters, so the answerer
1880 // accepts the offered parameters.
1881 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1882 fake_params);
1883 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1884 fake_params);
1885}
1886
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001887TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
1888 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1889 if (IsOfferer()) {
1890 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1891 fake_params);
1892 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1893 fake_params);
1894 }
1895
1896 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1897 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1898
1899 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1900 fake_params);
1901 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1902 fake_params);
1903
1904 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1905 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1906
1907 // The answer rejected datagram transport, so its parameters are empty.
1908 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1909 absl::nullopt);
1910 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1911 absl::nullopt);
1912}
1913
1914TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
1915 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1916 if (IsOfferer()) {
1917 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1918 fake_params);
1919 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1920 fake_params);
1921 }
1922
1923 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1924 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1925
1926 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1927 fake_params);
1928 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1929 fake_params);
1930
1931 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1932 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1933
1934 // The answer accepted datagram transport, so it is present.
1935 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1936 fake_params);
1937 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1938 fake_params);
1939}
1940
1941TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
1942 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1943 if (IsOfferer()) {
1944 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1945 fake_params);
1946 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1947 fake_params);
1948 }
1949
1950 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1951 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1952
1953 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1954 fake_params);
1955 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1956 fake_params);
1957
1958 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1959 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1960
1961 // The answer rejected datagram transport, but it's provisional, so the
1962 // transport is kept around for now.
1963 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1964 fake_params);
1965 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1966 fake_params);
1967}
1968
1969TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
1970 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1971 if (IsOfferer()) {
1972 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1973 fake_params);
1974 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1975 fake_params);
1976 }
1977
1978 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1979 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1980
1981 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1982 fake_params);
1983 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1984 fake_params);
1985
1986 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1987 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1988
1989 // The answer provisionally accepted datagram transport, so it's kept.
1990 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1991 fake_params);
1992 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1993 fake_params);
1994}
1995
1996TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
1997 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1998 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1999
2000 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2001 absl::nullopt);
2002 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2003 absl::nullopt);
2004
2005 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2006 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2007
2008 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2009 absl::nullopt);
2010 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2011 absl::nullopt);
2012
2013 // Attempting to add a datagram transport on a re-offer does not cause an
2014 // error, but also does not add a datagram transport.
2015 auto reoffer =
2016 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2017 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2018
2019 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2020 absl::nullopt);
2021 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2022 absl::nullopt);
2023}
2024
2025TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2026 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2027 if (IsOfferer()) {
2028 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2029 fake_params);
2030 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2031 fake_params);
2032 }
2033
2034 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2035 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2036
2037 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2038 fake_params);
2039 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2040 fake_params);
2041
2042 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2043 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2044
2045 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2046 fake_params);
2047 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2048 fake_params);
2049
2050 // Attempting to remove a datagram transport on a re-offer does not cause an
2051 // error, but also does not remove the datagram transport.
2052 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2053 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2054
2055 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2056 fake_params);
2057 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2058 fake_params);
2059}
2060
2061TEST_P(JsepTransportControllerDatagramTest,
2062 RenegotiationKeepsDatagramTransport) {
2063 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2064 if (IsOfferer()) {
2065 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2066 fake_params);
2067 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2068 fake_params);
2069 }
2070
2071 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2072 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2073
2074 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2075 fake_params);
2076 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2077 fake_params);
2078
2079 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2080 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2081
2082 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2083 fake_params);
2084 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2085 fake_params);
2086
2087 // Attempting to remove a datagram transport on a re-offer does not cause an
2088 // error, but also does not remove the datagram transport.
2089 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2090 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2091
2092 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2093 fake_params);
2094 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2095 fake_params);
2096
2097 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2098 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2099
2100 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2101 fake_params);
2102 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2103 fake_params);
2104}
2105
2106INSTANTIATE_TEST_SUITE_P(
2107 JsepTransportControllerDatagramTests,
2108 JsepTransportControllerDatagramTest,
2109 testing::Values(true, false),
2110 // The parameter value is the local perspective (offerer or answerer).
2111 [](const testing::TestParamInfo<bool>& info) {
2112 return info.param ? "Offerer" : "Answerer";
2113 });
2114
Zhi Huange818b6e2018-02-22 15:26:27 -08002115} // namespace webrtc