Rewrite WebRtcSession data channel tests as PeerConnection tests

Bug: webrtc:8222
Change-Id: I1382a0727b04dfd33e79992841d885f640b3a032
Reviewed-on: https://webrtc-review.googlesource.com/8281
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20398}
This commit is contained in:
Steve Anton 2017-10-23 11:41:54 -07:00 committed by Commit Bot
parent 6f25b090d4
commit da6c095b30
8 changed files with 408 additions and 233 deletions

View File

@ -324,6 +324,7 @@ if (rtc_include_tests) {
"test/fakedatachannelprovider.h",
"test/fakeperiodicvideocapturer.h",
"test/fakertccertificategenerator.h",
"test/fakesctptransport.h",
"test/faketransportcontroller.h",
"test/fakevideotrackrenderer.h",
"test/fakevideotracksource.h",
@ -393,6 +394,7 @@ if (rtc_include_tests) {
"mediastream_unittest.cc",
"peerconnection_bundle_unittest.cc",
"peerconnection_crypto_unittest.cc",
"peerconnection_datachannel_unittest.cc",
"peerconnection_ice_unittest.cc",
"peerconnection_integrationtest.cc",
"peerconnection_media_unittest.cc",

View File

@ -482,13 +482,7 @@ bool PeerConnection::Initialize(
factory_->CreateTransportController(
port_allocator_.get(),
configuration.redetermine_role_on_ice_restart)),
#ifdef HAVE_SCTP
std::unique_ptr<cricket::SctpTransportInternalFactory>(
new cricket::SctpTransportFactory(network_thread()))
#else
nullptr
#endif
));
factory_->CreateSctpTransportInternalFactory()));
session_ = owned_session_.get();
stats_.reset(new StatsCollector(this));

View File

@ -0,0 +1,301 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <tuple>
#include "api/peerconnectionproxy.h"
#include "media/base/fakemediaengine.h"
#include "pc/mediasession.h"
#include "pc/peerconnection.h"
#include "pc/peerconnectionfactory.h"
#include "pc/peerconnectionwrapper.h"
#ifdef WEBRTC_ANDROID
#include "pc/test/androidtestinitializer.h"
#endif
#include "pc/test/fakesctptransport.h"
#include "rtc_base/gunit.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/virtualsocketserver.h"
namespace webrtc {
using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
using ::testing::Values;
class PeerConnectionFactoryForDataChannelTest
: public rtc::RefCountedObject<PeerConnectionFactory> {
public:
PeerConnectionFactoryForDataChannelTest()
: rtc::RefCountedObject<PeerConnectionFactory>(
rtc::Thread::Current(),
rtc::Thread::Current(),
rtc::Thread::Current(),
rtc::MakeUnique<cricket::FakeMediaEngine>(),
CreateCallFactory(),
nullptr) {}
std::unique_ptr<cricket::SctpTransportInternalFactory>
CreateSctpTransportInternalFactory() {
auto factory = rtc::MakeUnique<FakeSctpTransportFactory>();
last_fake_sctp_transport_factory_ = factory.get();
return factory;
}
FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
};
class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
public:
using PeerConnectionWrapper::PeerConnectionWrapper;
FakeSctpTransportFactory* sctp_transport_factory() {
return sctp_transport_factory_;
}
void set_sctp_transport_factory(
FakeSctpTransportFactory* sctp_transport_factory) {
sctp_transport_factory_ = sctp_transport_factory;
}
rtc::Optional<std::string> sctp_content_name() {
return GetInternalPeerConnection()->sctp_content_name();
}
rtc::Optional<std::string> sctp_transport_name() {
return GetInternalPeerConnection()->sctp_transport_name();
}
PeerConnection* GetInternalPeerConnection() {
auto* pci = reinterpret_cast<
PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
return reinterpret_cast<PeerConnection*>(pci->internal());
}
private:
FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
};
class PeerConnectionDataChannelTest : public ::testing::Test {
protected:
typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
PeerConnectionDataChannelTest()
: vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
#ifdef WEBRTC_ANDROID
InitializeAndroidObjects();
#endif
}
WrapperPtr CreatePeerConnection() {
return CreatePeerConnection(RTCConfiguration());
}
WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
return CreatePeerConnection(config,
PeerConnectionFactoryInterface::Options());
}
WrapperPtr CreatePeerConnection(
const RTCConfiguration& config,
const PeerConnectionFactoryInterface::Options factory_options) {
rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
new PeerConnectionFactoryForDataChannelTest());
pc_factory->SetOptions(factory_options);
RTC_CHECK(pc_factory->Initialize());
auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
observer.get());
if (!pc) {
return nullptr;
}
auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForDataChannelTest>(
pc_factory, pc, std::move(observer));
RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
wrapper->set_sctp_transport_factory(
pc_factory->last_fake_sctp_transport_factory_);
return wrapper;
}
// Accepts the same arguments as CreatePeerConnection and adds a default data
// channel.
template <typename... Args>
WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
if (!wrapper) {
return nullptr;
}
EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
return wrapper;
}
// Changes the SCTP data channel port on the given session description.
void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
int port) {
cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
cricket::kGoogleSctpDataCodecName);
sctp_codec.SetParam(cricket::kCodecParamPort, port);
auto* data_content = cricket::GetFirstDataContent(desc);
RTC_DCHECK(data_content);
auto* data_desc = static_cast<cricket::DataContentDescription*>(
data_content->description);
data_desc->set_codecs({sctp_codec});
}
std::unique_ptr<rtc::VirtualSocketServer> vss_;
rtc::AutoSocketServerThread main_;
};
TEST_F(PeerConnectionDataChannelTest,
NoSctpTransportCreatedIfRtpDataChannelEnabled) {
RTCConfiguration config;
config.enable_rtp_data_channel = true;
auto caller = CreatePeerConnectionWithDataChannel(config);
ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
}
TEST_F(PeerConnectionDataChannelTest,
RtpDataChannelCreatedEvenIfSctpAvailable) {
RTCConfiguration config;
config.enable_rtp_data_channel = true;
PeerConnectionFactoryInterface::Options options;
options.disable_sctp_data_channels = false;
auto caller = CreatePeerConnectionWithDataChannel(config, options);
ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
}
// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
// before and after BUNDLE is negotiated.
TEST_F(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
// Initially these fields should be empty.
EXPECT_FALSE(caller->sctp_content_name());
EXPECT_FALSE(caller->sctp_transport_name());
// Create offer with audio/video/data.
// Default bundle policy is "balanced", so data should be using its own
// transport.
caller->AddAudioTrack("a");
caller->AddVideoTrack("v");
caller->pc()->CreateDataChannel("dc", nullptr);
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
ASSERT_TRUE(caller->sctp_content_name());
EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
ASSERT_TRUE(caller->sctp_transport_name());
EXPECT_EQ(cricket::CN_DATA, *caller->sctp_transport_name());
// Create answer that finishes BUNDLE negotiation, which means everything
// should be bundled on the first transport (audio).
RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
ASSERT_TRUE(
caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
ASSERT_TRUE(caller->sctp_content_name());
EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
ASSERT_TRUE(caller->sctp_transport_name());
EXPECT_EQ(cricket::CN_AUDIO, *caller->sctp_transport_name());
}
TEST_F(PeerConnectionDataChannelTest,
CreateOfferWithNoDataChannelsGivesNoDataSection) {
auto caller = CreatePeerConnection();
auto offer = caller->CreateOffer();
EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
}
TEST_F(PeerConnectionDataChannelTest,
CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
auto caller = CreatePeerConnectionWithDataChannel();
auto callee = CreatePeerConnection();
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
auto answer = callee->CreateAnswer();
ASSERT_TRUE(answer);
auto* data_content =
answer->description()->GetContentByName(cricket::CN_DATA);
ASSERT_TRUE(data_content);
EXPECT_FALSE(data_content->rejected);
EXPECT_TRUE(answer->description()->GetTransportInfoByName(cricket::CN_DATA));
}
TEST_F(PeerConnectionDataChannelTest,
CreateDataChannelWithDtlsDisabledSucceeds) {
RTCConfiguration config;
config.enable_dtls_srtp.emplace(false);
auto caller = CreatePeerConnection();
EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
}
TEST_F(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
PeerConnectionFactoryInterface::Options options;
options.disable_sctp_data_channels = true;
auto caller = CreatePeerConnection(RTCConfiguration(), options);
EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
}
// Test that if a callee has SCTP disabled and receives an offer with an SCTP
// data channel, the data section is rejected and no SCTP transport is created
// on the callee.
TEST_F(PeerConnectionDataChannelTest,
DataSectionRejectedIfCalleeHasSctpDisabled) {
auto caller = CreatePeerConnectionWithDataChannel();
PeerConnectionFactoryInterface::Options options;
options.disable_sctp_data_channels = true;
auto callee = CreatePeerConnection(RTCConfiguration(), options);
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
auto answer = callee->CreateAnswer();
auto* data_content =
answer->description()->GetContentByName(cricket::CN_DATA);
ASSERT_TRUE(data_content);
EXPECT_TRUE(data_content->rejected);
}
TEST_F(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
constexpr int kNewSendPort = 9998;
constexpr int kNewRecvPort = 7775;
auto caller = CreatePeerConnectionWithDataChannel();
auto callee = CreatePeerConnectionWithDataChannel();
auto offer = caller->CreateOffer();
ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
auto answer = callee->CreateAnswer();
ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
auto* callee_transport =
callee->sctp_transport_factory()->last_fake_sctp_transport();
ASSERT_TRUE(callee_transport);
EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
}
} // namespace webrtc

View File

@ -364,7 +364,12 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
void CreateDataChannel() { CreateDataChannel(nullptr); }
void CreateDataChannel(const webrtc::DataChannelInit* init) {
data_channel_ = pc()->CreateDataChannel(kDataChannelLabel, init);
CreateDataChannel(kDataChannelLabel, init);
}
void CreateDataChannel(const std::string& label,
const webrtc::DataChannelInit* init) {
data_channel_ = pc()->CreateDataChannel(label, init);
ASSERT_TRUE(data_channel_.get() != nullptr);
data_observer_.reset(new MockDataChannelObserver(data_channel_));
}
@ -2594,6 +2599,24 @@ TEST_F(PeerConnectionIntegrationTest, CalleeClosesSctpDataChannel) {
EXPECT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
}
TEST_F(PeerConnectionIntegrationTest, SctpDataChannelConfigSentToOtherSide) {
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
webrtc::DataChannelInit init;
init.id = 53;
init.maxRetransmits = 52;
caller()->CreateDataChannel("data-channel", &init);
caller()->AddAudioVideoMediaStream();
callee()->AddAudioVideoMediaStream();
caller()->CreateAndSetAndSignalOffer();
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
ASSERT_TRUE(callee()->data_channel());
EXPECT_EQ(init.id, callee()->data_channel()->id());
EXPECT_EQ("data-channel", callee()->data_channel()->label());
EXPECT_EQ(init.maxRetransmits, callee()->data_channel()->maxRetransmits());
EXPECT_FALSE(callee()->data_channel()->negotiated());
}
// Test usrsctp's ability to process unordered data stream, where data actually
// arrives out of order using simulated delays. Previously there have been some
// bugs in this area.

View File

@ -20,6 +20,7 @@
#include "api/turncustomizer.h"
#include "api/videosourceproxy.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "media/sctp/sctptransport.h"
#include "rtc_base/bind.h"
#include "rtc_base/checks.h"
#include "rtc_base/ptr_util.h"
@ -297,6 +298,15 @@ cricket::TransportController* PeerConnectionFactory::CreateTransportController(
redetermine_role_on_ice_restart, options_.crypto_options);
}
std::unique_ptr<cricket::SctpTransportInternalFactory>
PeerConnectionFactory::CreateSctpTransportInternalFactory() {
#ifdef HAVE_SCTP
return rtc::MakeUnique<cricket::SctpTransportFactory>(network_thread());
#else
return nullptr;
#endif
}
cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
return channel_manager_.get();
}

View File

@ -16,6 +16,7 @@
#include "api/mediastreaminterface.h"
#include "api/peerconnectioninterface.h"
#include "media/sctp/sctptransportinternal.h"
#include "pc/channelmanager.h"
#include "rtc_base/rtccertificategenerator.h"
#include "rtc_base/scoped_ref_ptr.h"
@ -89,6 +90,10 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface {
virtual cricket::TransportController* CreateTransportController(
cricket::PortAllocator* port_allocator,
bool redetermine_role_on_ice_restart);
virtual std::unique_ptr<cricket::SctpTransportInternalFactory>
CreateSctpTransportInternalFactory();
virtual cricket::ChannelManager* channel_manager();
virtual rtc::Thread* signaling_thread();
virtual rtc::Thread* worker_thread();

View File

@ -0,0 +1,64 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef PC_TEST_FAKESCTPTRANSPORT_H_
#define PC_TEST_FAKESCTPTRANSPORT_H_
#include <memory>
#include "media/sctp/sctptransportinternal.h"
// Used for tests in this file to verify that PeerConnection responds to signals
// from the SctpTransport correctly, and calls Start with the correct
// local/remote ports.
class FakeSctpTransport : public cricket::SctpTransportInternal {
public:
void SetTransportChannel(rtc::PacketTransportInternal* channel) override {}
bool Start(int local_port, int remote_port) override {
local_port_.emplace(local_port);
remote_port_.emplace(remote_port);
return true;
}
bool OpenStream(int sid) override { return true; }
bool ResetStream(int sid) override { return true; }
bool SendData(const cricket::SendDataParams& params,
const rtc::CopyOnWriteBuffer& payload,
cricket::SendDataResult* result = nullptr) override {
return true;
}
bool ReadyToSendData() override { return true; }
void set_debug_name_for_testing(const char* debug_name) override {}
int local_port() const { return *local_port_; }
int remote_port() const { return *remote_port_; }
private:
rtc::Optional<int> local_port_;
rtc::Optional<int> remote_port_;
};
class FakeSctpTransportFactory : public cricket::SctpTransportInternalFactory {
public:
std::unique_ptr<cricket::SctpTransportInternal> CreateSctpTransport(
rtc::PacketTransportInternal*) override {
last_fake_sctp_transport_ = new FakeSctpTransport();
return std::unique_ptr<cricket::SctpTransportInternal>(
last_fake_sctp_transport_);
}
FakeSctpTransport* last_fake_sctp_transport() {
return last_fake_sctp_transport_;
}
private:
FakeSctpTransport* last_fake_sctp_transport_ = nullptr;
};
#endif // PC_TEST_FAKESCTPTRANSPORT_H_

View File

@ -31,6 +31,7 @@
#include "pc/peerconnection.h"
#include "pc/sctputils.h"
#include "pc/test/fakertccertificategenerator.h"
#include "pc/test/fakesctptransport.h"
#include "pc/videotrack.h"
#include "pc/webrtcsession.h"
#include "pc/webrtcsessiondescriptionfactory.h"
@ -87,7 +88,6 @@ static const int kMediaContentIndex0 = 0;
// Media index of candidates belonging to the second media content.
static const int kMediaContentIndex1 = 1;
static const int kDefaultTimeout = 10000; // 10 seconds.
static const int kIceCandidatesTimeout = 10000;
static const char kStream1[] = "stream1";
@ -161,52 +161,6 @@ class MockIceObserver : public webrtc::IceObserver {
size_t num_candidates_removed_ = 0;
};
// Used for tests in this file to verify that WebRtcSession responds to signals
// from the SctpTransport correctly, and calls Start with the correct
// local/remote ports.
class FakeSctpTransport : public cricket::SctpTransportInternal {
public:
void SetTransportChannel(rtc::PacketTransportInternal* channel) override {}
bool Start(int local_port, int remote_port) override {
local_port_ = local_port;
remote_port_ = remote_port;
return true;
}
bool OpenStream(int sid) override { return true; }
bool ResetStream(int sid) override { return true; }
bool SendData(const cricket::SendDataParams& params,
const rtc::CopyOnWriteBuffer& payload,
cricket::SendDataResult* result = nullptr) override {
return true;
}
bool ReadyToSendData() override { return true; }
void set_debug_name_for_testing(const char* debug_name) override {}
int local_port() const { return local_port_; }
int remote_port() const { return remote_port_; }
private:
int local_port_ = -1;
int remote_port_ = -1;
};
class FakeSctpTransportFactory : public cricket::SctpTransportInternalFactory {
public:
std::unique_ptr<cricket::SctpTransportInternal> CreateSctpTransport(
rtc::PacketTransportInternal*) override {
last_fake_sctp_transport_ = new FakeSctpTransport();
return std::unique_ptr<cricket::SctpTransportInternal>(
last_fake_sctp_transport_);
}
FakeSctpTransport* last_fake_sctp_transport() {
return last_fake_sctp_transport_;
}
private:
FakeSctpTransport* last_fake_sctp_transport_ = nullptr;
};
class WebRtcSessionForTest : public webrtc::WebRtcSession {
public:
WebRtcSessionForTest(
@ -1077,184 +1031,6 @@ TEST_P(WebRtcSessionTest, TestCreateAnswerWithDifferentSslRoles) {
SetLocalDescriptionWithoutError(answer);
}
TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
configuration_.enable_rtp_data_channel = true;
Init();
SetLocalDescriptionWithDataChannel();
ASSERT_TRUE(data_engine_);
EXPECT_NE(nullptr, data_engine_->GetChannel(0));
}
TEST_P(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) {
configuration_.enable_rtp_data_channel = true;
options_.disable_sctp_data_channels = false;
InitWithDtls(GetParam());
SetLocalDescriptionWithDataChannel();
EXPECT_NE(nullptr, data_engine_->GetChannel(0));
}
// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
// before and after BUNDLE is negotiated.
TEST_P(WebRtcSessionTest, SctpContentAndTransportName) {
SetFactoryDtlsSrtp();
InitWithDtls(GetParam());
// Initially these fields should be empty.
EXPECT_FALSE(session_->sctp_content_name());
EXPECT_FALSE(session_->sctp_transport_name());
// Create offer with audio/video/data.
// Default bundle policy is "balanced", so data should be using its own
// transport.
SendAudioVideoStream1();
CreateDataChannel();
InitiateCall();
ASSERT_TRUE(session_->sctp_content_name());
ASSERT_TRUE(session_->sctp_transport_name());
EXPECT_EQ("data", *session_->sctp_content_name());
EXPECT_EQ("data", *session_->sctp_transport_name());
// Create answer that finishes BUNDLE negotiation, which means everything
// should be bundled on the first transport (audio).
cricket::MediaSessionOptions answer_options;
answer_options.bundle_enabled = true;
answer_options.data_channel_type = cricket::DCT_SCTP;
GetOptionsForAnswer(&answer_options);
SetRemoteDescriptionWithoutError(CreateRemoteAnswer(
session_->local_description(), answer_options, cricket::SEC_DISABLED));
ASSERT_TRUE(session_->sctp_content_name());
ASSERT_TRUE(session_->sctp_transport_name());
EXPECT_EQ("data", *session_->sctp_content_name());
EXPECT_EQ("audio", *session_->sctp_transport_name());
}
TEST_P(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
InitWithDtls(GetParam());
std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
EXPECT_TRUE(offer->description()->GetContentByName("data") == NULL);
EXPECT_TRUE(offer->description()->GetTransportInfoByName("data") == NULL);
}
TEST_P(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) {
SetFactoryDtlsSrtp();
InitWithDtls(GetParam());
// Create remote offer with SCTP.
cricket::MediaSessionOptions options;
options.data_channel_type = cricket::DCT_SCTP;
GetOptionsForRemoteOffer(&options);
JsepSessionDescription* offer =
CreateRemoteOffer(options, cricket::SEC_DISABLED);
SetRemoteDescriptionWithoutError(offer);
// Verifies the answer contains SCTP.
std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
EXPECT_TRUE(answer != NULL);
EXPECT_TRUE(answer->description()->GetContentByName("data") != NULL);
EXPECT_TRUE(answer->description()->GetTransportInfoByName("data") != NULL);
}
// Test that if DTLS is disabled, we don't end up with an SctpTransport
// created (or an RtpDataChannel).
TEST_P(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
configuration_.enable_dtls_srtp = rtc::Optional<bool>(false);
InitWithDtls(GetParam());
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(nullptr, data_engine_->GetChannel(0));
EXPECT_EQ(nullptr, fake_sctp_transport_factory_->last_fake_sctp_transport());
}
// Test that if DTLS is enabled, we end up with an SctpTransport created
// (and not an RtpDataChannel).
TEST_P(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
InitWithDtls(GetParam());
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(nullptr, data_engine_->GetChannel(0));
EXPECT_NE(nullptr, fake_sctp_transport_factory_->last_fake_sctp_transport());
}
// Test that if SCTP is disabled, we don't end up with an SctpTransport
// created (or an RtpDataChannel).
TEST_P(WebRtcSessionTest, TestDisableSctpDataChannels) {
options_.disable_sctp_data_channels = true;
InitWithDtls(GetParam());
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(nullptr, data_engine_->GetChannel(0));
EXPECT_EQ(nullptr, fake_sctp_transport_factory_->last_fake_sctp_transport());
}
TEST_P(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
const int new_send_port = 9998;
const int new_recv_port = 7775;
InitWithDtls(GetParam());
SetFactoryDtlsSrtp();
// By default, don't actually add the codecs to desc_factory_; they don't
// actually get serialized for SCTP in BuildMediaDescription(). Instead,
// let the session description get parsed. That'll get the proper codecs
// into the stream.
cricket::MediaSessionOptions options;
SessionDescriptionInterface* offer =
CreateRemoteOfferWithSctpPort("stream1", new_send_port, options);
// SetRemoteDescription will take the ownership of the offer.
SetRemoteDescriptionWithoutError(offer);
SessionDescriptionInterface* answer =
ChangeSDPSctpPort(new_recv_port, CreateAnswer());
ASSERT_TRUE(answer != NULL);
// Now set the local description, which'll take ownership of the answer.
SetLocalDescriptionWithoutError(answer);
// TEST PLAN: Set the port number to something new, set it in the SDP,
// and pass it all the way down.
EXPECT_EQ(nullptr, data_engine_->GetChannel(0));
CreateDataChannel();
ASSERT_NE(nullptr, fake_sctp_transport_factory_->last_fake_sctp_transport());
EXPECT_EQ(
new_recv_port,
fake_sctp_transport_factory_->last_fake_sctp_transport()->local_port());
EXPECT_EQ(
new_send_port,
fake_sctp_transport_factory_->last_fake_sctp_transport()->remote_port());
}
// Verifies that when a session's SctpTransport receives an OPEN message,
// WebRtcSession signals the SctpTransport creation request with the expected
// config.
TEST_P(WebRtcSessionTest, TestSctpDataChannelOpenMessage) {
InitWithDtls(GetParam());
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(nullptr, data_engine_->GetChannel(0));
ASSERT_NE(nullptr, fake_sctp_transport_factory_->last_fake_sctp_transport());
// Make the fake SCTP transport pretend it received an OPEN message.
webrtc::DataChannelInit config;
config.id = 1;
rtc::CopyOnWriteBuffer payload;
webrtc::WriteDataChannelOpenMessage("a", config, &payload);
cricket::ReceiveDataParams params;
params.ssrc = config.id;
params.type = cricket::DMT_CONTROL;
fake_sctp_transport_factory_->last_fake_sctp_transport()->SignalDataReceived(
params, payload);
EXPECT_EQ_WAIT("a", last_data_channel_label_, kDefaultTimeout);
EXPECT_EQ(config.id, last_data_channel_config_.id);
EXPECT_FALSE(last_data_channel_config_.negotiated);
EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker,
last_data_channel_config_.open_handshake_role);
}
#ifdef HAVE_QUIC
TEST_P(WebRtcSessionTest, TestNegotiateQuic) {
configuration_.enable_quic = true;