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:
parent
6f25b090d4
commit
da6c095b30
@ -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",
|
||||
|
||||
@ -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));
|
||||
|
||||
301
pc/peerconnection_datachannel_unittest.cc
Normal file
301
pc/peerconnection_datachannel_unittest.cc
Normal 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
|
||||
@ -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.
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
64
pc/test/fakesctptransport.h
Normal file
64
pc/test/fakesctptransport.h
Normal 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_
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user