Rewrite WebRtcSession ICE integration tests as PeerConnection tests
Bug: webrtc:8222 Change-Id: I12d28b2016598f94602a273a82de70d6fc0e682f Reviewed-on: https://webrtc-review.googlesource.com/7020 Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Commit-Queue: Steve Anton <steveanton@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20318}
This commit is contained in:
parent
d6b4819e4a
commit
ede9ca5a24
@ -31,6 +31,7 @@
|
||||
#include "p2p/base/p2pconstants.h"
|
||||
#include "p2p/base/portinterface.h"
|
||||
#include "p2p/base/sessiondescription.h"
|
||||
#include "p2p/base/teststunserver.h"
|
||||
#include "p2p/base/testturncustomizer.h"
|
||||
#include "p2p/base/testturnserver.h"
|
||||
#include "p2p/client/basicportallocator.h"
|
||||
@ -45,6 +46,7 @@
|
||||
#include "pc/test/fakevideotrackrenderer.h"
|
||||
#include "pc/test/mockpeerconnectionobservers.h"
|
||||
#include "rtc_base/fakenetwork.h"
|
||||
#include "rtc_base/firewallsocketserver.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "rtc_base/virtualsocketserver.h"
|
||||
#include "test/gmock.h"
|
||||
@ -55,6 +57,9 @@ using cricket::FakeWebRtcVideoDecoderFactory;
|
||||
using cricket::FakeWebRtcVideoEncoder;
|
||||
using cricket::FakeWebRtcVideoEncoderFactory;
|
||||
using cricket::MediaContentDescription;
|
||||
using rtc::SocketAddress;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Values;
|
||||
using webrtc::DataBuffer;
|
||||
using webrtc::DataChannelInterface;
|
||||
using webrtc::DtmfSender;
|
||||
@ -94,6 +99,8 @@ static const char kDataChannelLabel[] = "data_channel";
|
||||
static const int kDefaultSrtpCryptoSuite = rtc::SRTP_AES128_CM_SHA1_32;
|
||||
static const int kDefaultSrtpCryptoSuiteGcm = rtc::SRTP_AEAD_AES_256_GCM;
|
||||
|
||||
static const SocketAddress kDefaultLocalAddress("192.168.1.1", 0);
|
||||
|
||||
// Helper function for constructing offer/answer options to initiate an ICE
|
||||
// restart.
|
||||
PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions() {
|
||||
@ -277,10 +284,16 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
generated_sdp_munger_ = munger;
|
||||
}
|
||||
|
||||
// Number of times the gathering state has transitioned to "gathering".
|
||||
// Useful for telling if an ICE restart occurred as expected.
|
||||
int transitions_to_gathering_state() const {
|
||||
return transitions_to_gathering_state_;
|
||||
// Every ICE connection state in order that has been seen by the observer.
|
||||
std::vector<PeerConnectionInterface::IceConnectionState>
|
||||
ice_connection_state_history() const {
|
||||
return ice_connection_state_history_;
|
||||
}
|
||||
|
||||
// Every ICE gathering state in order that has been seen by the observer.
|
||||
std::vector<PeerConnectionInterface::IceGatheringState>
|
||||
ice_gathering_state_history() const {
|
||||
return ice_gathering_state_history_;
|
||||
}
|
||||
|
||||
// TODO(deadbeef): Switch the majority of these tests to use AddTrack instead
|
||||
@ -538,6 +551,11 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
}
|
||||
}
|
||||
|
||||
rtc::FakeNetworkManager* network() const {
|
||||
return fake_network_manager_.get();
|
||||
}
|
||||
cricket::PortAllocator* port_allocator() const { return port_allocator_; }
|
||||
|
||||
private:
|
||||
explicit PeerConnectionWrapper(const std::string& debug_name)
|
||||
: debug_name_(debug_name) {}
|
||||
@ -554,10 +572,11 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
RTC_DCHECK(!peer_connection_factory_);
|
||||
|
||||
fake_network_manager_.reset(new rtc::FakeNetworkManager());
|
||||
fake_network_manager_->AddInterface(rtc::SocketAddress("192.168.1.1", 0));
|
||||
fake_network_manager_->AddInterface(kDefaultLocalAddress);
|
||||
|
||||
std::unique_ptr<cricket::PortAllocator> port_allocator(
|
||||
new cricket::BasicPortAllocator(fake_network_manager_.get()));
|
||||
port_allocator_ = port_allocator.get();
|
||||
fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
|
||||
if (!fake_audio_capture_module_) {
|
||||
return false;
|
||||
@ -612,6 +631,10 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
|
||||
void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
|
||||
|
||||
void set_signal_ice_candidates(bool signal) {
|
||||
signal_ice_candidates_ = signal;
|
||||
}
|
||||
|
||||
void EnableVideoDecoderFactory() {
|
||||
video_decoder_factory_enabled_ = true;
|
||||
fake_video_decoder_factory_->AddSupportedVideoCodecType(
|
||||
@ -818,20 +841,19 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
void OnIceConnectionChange(
|
||||
webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
|
||||
EXPECT_EQ(pc()->ice_connection_state(), new_state);
|
||||
ice_connection_state_history_.push_back(new_state);
|
||||
}
|
||||
void OnIceGatheringChange(
|
||||
webrtc::PeerConnectionInterface::IceGatheringState new_state) override {
|
||||
if (new_state == PeerConnectionInterface::kIceGatheringGathering) {
|
||||
++transitions_to_gathering_state_;
|
||||
}
|
||||
EXPECT_EQ(pc()->ice_gathering_state(), new_state);
|
||||
ice_gathering_state_history_.push_back(new_state);
|
||||
}
|
||||
void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override {
|
||||
LOG(LS_INFO) << debug_name_ << ": OnIceCandidate";
|
||||
|
||||
std::string ice_sdp;
|
||||
EXPECT_TRUE(candidate->ToString(&ice_sdp));
|
||||
if (signaling_message_receiver_ == nullptr) {
|
||||
if (signaling_message_receiver_ == nullptr || !signal_ice_candidates_) {
|
||||
// Remote party may be deleted.
|
||||
return;
|
||||
}
|
||||
@ -886,6 +908,7 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
|
||||
peer_connection_factory_;
|
||||
|
||||
cricket::PortAllocator* port_allocator_;
|
||||
// Needed to keep track of number of frames sent.
|
||||
rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
|
||||
// Needed to keep track of number of frames received.
|
||||
@ -903,6 +926,7 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
// For remote peer communication.
|
||||
SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
|
||||
int signaling_delay_ms_ = 0;
|
||||
bool signal_ice_candidates_ = true;
|
||||
|
||||
// Store references to the video capturers we've created, so that we can stop
|
||||
// them, if required.
|
||||
@ -919,7 +943,10 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
|
||||
|
||||
std::vector<std::unique_ptr<MockRtpReceiverObserver>> rtp_receiver_observers_;
|
||||
|
||||
int transitions_to_gathering_state_ = 0;
|
||||
std::vector<PeerConnectionInterface::IceConnectionState>
|
||||
ice_connection_state_history_;
|
||||
std::vector<PeerConnectionInterface::IceGatheringState>
|
||||
ice_gathering_state_history_;
|
||||
|
||||
rtc::AsyncInvoker invoker_;
|
||||
|
||||
@ -941,7 +968,8 @@ class PeerConnectionIntegrationTest : public testing::Test {
|
||||
public:
|
||||
PeerConnectionIntegrationTest()
|
||||
: ss_(new rtc::VirtualSocketServer()),
|
||||
network_thread_(new rtc::Thread(ss_.get())),
|
||||
fss_(new rtc::FirewallSocketServer(ss_.get())),
|
||||
network_thread_(new rtc::Thread(fss_.get())),
|
||||
worker_thread_(rtc::Thread::Create()) {
|
||||
RTC_CHECK(network_thread_->Start());
|
||||
RTC_CHECK(worker_thread_->Start());
|
||||
@ -1030,11 +1058,24 @@ class PeerConnectionIntegrationTest : public testing::Test {
|
||||
callee_->set_signaling_message_receiver(caller_.get());
|
||||
}
|
||||
|
||||
// Once called, SDP blobs will be automatically signaled between
|
||||
// PeerConnections. Note that ICE candidates will not be signaled unless they
|
||||
// are in the exchanged SDP blobs.
|
||||
void ConnectFakeSignalingForSdpOnly() {
|
||||
ConnectFakeSignaling();
|
||||
SetSignalIceCandidates(false);
|
||||
}
|
||||
|
||||
void SetSignalingDelayMs(int delay_ms) {
|
||||
caller_->set_signaling_delay_ms(delay_ms);
|
||||
callee_->set_signaling_delay_ms(delay_ms);
|
||||
}
|
||||
|
||||
void SetSignalIceCandidates(bool signal) {
|
||||
caller_->set_signal_ice_candidates(signal);
|
||||
callee_->set_signal_ice_candidates(signal);
|
||||
}
|
||||
|
||||
void EnableVideoDecoderFactory() {
|
||||
caller_->EnableVideoDecoderFactory();
|
||||
callee_->EnableVideoDecoderFactory();
|
||||
@ -1076,6 +1117,8 @@ class PeerConnectionIntegrationTest : public testing::Test {
|
||||
return old;
|
||||
}
|
||||
|
||||
rtc::FirewallSocketServer* firewall() const { return fss_.get(); }
|
||||
|
||||
// Expects the provided number of new frames to be received within |wait_ms|.
|
||||
// "New frames" meaning that it waits for the current frame counts to
|
||||
// *increase* by the provided values. For video, uses
|
||||
@ -1146,6 +1189,7 @@ class PeerConnectionIntegrationTest : public testing::Test {
|
||||
private:
|
||||
// |ss_| is used by |network_thread_| so it must be destroyed later.
|
||||
std::unique_ptr<rtc::VirtualSocketServer> ss_;
|
||||
std::unique_ptr<rtc::FirewallSocketServer> fss_;
|
||||
// |network_thread_| and |worker_thread_| are used by both
|
||||
// |caller_| and |callee_| so they must be destroyed
|
||||
// later.
|
||||
@ -2720,6 +2764,207 @@ TEST_F(PeerConnectionIntegrationTest, IceStatesReachCompletion) {
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
}
|
||||
|
||||
// Test that firewalling the ICE connection causes the clients to identify the
|
||||
// disconnected state and then removing the firewall causes them to reconnect.
|
||||
class PeerConnectionIntegrationIceStatesTest
|
||||
: public PeerConnectionIntegrationTest,
|
||||
public ::testing::WithParamInterface<std::tuple<std::string, uint32_t>> {
|
||||
protected:
|
||||
PeerConnectionIntegrationIceStatesTest() {
|
||||
port_allocator_flags_ = std::get<1>(GetParam());
|
||||
}
|
||||
|
||||
void StartStunServer(const SocketAddress& server_address) {
|
||||
stun_server_.reset(
|
||||
cricket::TestStunServer::Create(network_thread(), server_address));
|
||||
}
|
||||
|
||||
bool TestIPv6() {
|
||||
return (port_allocator_flags_ & cricket::PORTALLOCATOR_ENABLE_IPV6);
|
||||
}
|
||||
|
||||
void SetPortAllocatorFlags() {
|
||||
caller()->port_allocator()->set_flags(port_allocator_flags_);
|
||||
callee()->port_allocator()->set_flags(port_allocator_flags_);
|
||||
}
|
||||
|
||||
std::vector<SocketAddress> CallerAddresses() {
|
||||
std::vector<SocketAddress> addresses;
|
||||
addresses.push_back(SocketAddress("1.1.1.1", 0));
|
||||
if (TestIPv6()) {
|
||||
addresses.push_back(SocketAddress("1111:0:a:b:c:d:e:f", 0));
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
std::vector<SocketAddress> CalleeAddresses() {
|
||||
std::vector<SocketAddress> addresses;
|
||||
addresses.push_back(SocketAddress("2.2.2.2", 0));
|
||||
if (TestIPv6()) {
|
||||
addresses.push_back(SocketAddress("2222:0:a:b:c:d:e:f", 0));
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
void SetUpNetworkInterfaces() {
|
||||
// Remove the default interfaces added by the test infrastructure.
|
||||
caller()->network()->RemoveInterface(kDefaultLocalAddress);
|
||||
callee()->network()->RemoveInterface(kDefaultLocalAddress);
|
||||
|
||||
// Add network addresses for test.
|
||||
for (const auto& caller_address : CallerAddresses()) {
|
||||
caller()->network()->AddInterface(caller_address);
|
||||
}
|
||||
for (const auto& callee_address : CalleeAddresses()) {
|
||||
callee()->network()->AddInterface(callee_address);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t port_allocator_flags_;
|
||||
std::unique_ptr<cricket::TestStunServer> stun_server_;
|
||||
};
|
||||
|
||||
// Tests that the PeerConnection goes through all the ICE gathering/connection
|
||||
// states over the duration of the call. This includes Disconnected and Failed
|
||||
// states, induced by putting a firewall between the peers and waiting for them
|
||||
// to time out.
|
||||
TEST_P(PeerConnectionIntegrationIceStatesTest, VerifyIceStates) {
|
||||
rtc::ScopedFakeClock fake_clock;
|
||||
// Some things use a time of "0" as a special value, so we need to start out
|
||||
// the fake clock at a nonzero time.
|
||||
// TODO(deadbeef): Fix this.
|
||||
fake_clock.AdvanceTime(rtc::TimeDelta::FromSeconds(1));
|
||||
|
||||
const SocketAddress kStunServerAddress =
|
||||
SocketAddress("99.99.99.1", cricket::STUN_SERVER_PORT);
|
||||
StartStunServer(kStunServerAddress);
|
||||
|
||||
PeerConnectionInterface::RTCConfiguration config;
|
||||
PeerConnectionInterface::IceServer ice_stun_server;
|
||||
ice_stun_server.urls.push_back(
|
||||
"stun:" + kStunServerAddress.HostAsURIString() + ":" +
|
||||
kStunServerAddress.PortAsString());
|
||||
config.servers.push_back(ice_stun_server);
|
||||
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
SetPortAllocatorFlags();
|
||||
SetUpNetworkInterfaces();
|
||||
caller()->AddAudioVideoMediaStream();
|
||||
callee()->AddAudioVideoMediaStream();
|
||||
|
||||
// Initial state before anything happens.
|
||||
ASSERT_EQ(PeerConnectionInterface::kIceGatheringNew,
|
||||
caller()->ice_gathering_state());
|
||||
ASSERT_EQ(PeerConnectionInterface::kIceConnectionNew,
|
||||
caller()->ice_connection_state());
|
||||
|
||||
// Start the call by creating the offer, setting it as the local description,
|
||||
// then sending it to the peer who will respond with an answer. This happens
|
||||
// asynchronously so that we can watch the states as it runs in the
|
||||
// background.
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
|
||||
ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
|
||||
caller()->ice_connection_state(), kDefaultTimeout,
|
||||
fake_clock);
|
||||
|
||||
// Verify that the observer was notified of the intermediate transitions.
|
||||
EXPECT_THAT(caller()->ice_connection_state_history(),
|
||||
ElementsAre(PeerConnectionInterface::kIceConnectionChecking,
|
||||
PeerConnectionInterface::kIceConnectionConnected,
|
||||
PeerConnectionInterface::kIceConnectionCompleted));
|
||||
EXPECT_THAT(caller()->ice_gathering_state_history(),
|
||||
ElementsAre(PeerConnectionInterface::kIceGatheringGathering,
|
||||
PeerConnectionInterface::kIceGatheringComplete));
|
||||
|
||||
// Block connections to/from the caller and wait for ICE to become
|
||||
// disconnected.
|
||||
for (const auto& caller_address : CallerAddresses()) {
|
||||
firewall()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, caller_address);
|
||||
}
|
||||
LOG(LS_INFO) << "Firewall rules applied";
|
||||
ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
|
||||
caller()->ice_connection_state(), kDefaultTimeout,
|
||||
fake_clock);
|
||||
|
||||
// Let ICE re-establish by removing the firewall rules.
|
||||
firewall()->ClearRules();
|
||||
LOG(LS_INFO) << "Firewall rules cleared";
|
||||
ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
|
||||
caller()->ice_connection_state(), kDefaultTimeout,
|
||||
fake_clock);
|
||||
|
||||
// According to RFC7675, if there is no response within 30 seconds then the
|
||||
// peer should consider the other side to have rejected the connection. This
|
||||
// is signalled by the state transitioning to "failed".
|
||||
constexpr int kConsentTimeout = 30000;
|
||||
for (const auto& caller_address : CallerAddresses()) {
|
||||
firewall()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, caller_address);
|
||||
}
|
||||
LOG(LS_INFO) << "Firewall rules applied again";
|
||||
ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionFailed,
|
||||
caller()->ice_connection_state(), kConsentTimeout,
|
||||
fake_clock);
|
||||
}
|
||||
|
||||
// Tests that the best connection is set to the appropriate IPv4/IPv6 connection
|
||||
// and that the statistics in the metric observers are updated correctly.
|
||||
TEST_P(PeerConnectionIntegrationIceStatesTest, VerifyBestConnection) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
SetPortAllocatorFlags();
|
||||
SetUpNetworkInterfaces();
|
||||
caller()->AddAudioVideoMediaStream();
|
||||
callee()->AddAudioVideoMediaStream();
|
||||
|
||||
rtc::scoped_refptr<webrtc::FakeMetricsObserver> metrics_observer(
|
||||
new rtc::RefCountedObject<webrtc::FakeMetricsObserver>());
|
||||
caller()->pc()->RegisterUMAObserver(metrics_observer.get());
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
const int num_best_ipv4 = metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterAddressFamily, webrtc::kBestConnections_IPv4);
|
||||
const int num_best_ipv6 = metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterAddressFamily, webrtc::kBestConnections_IPv6);
|
||||
if (TestIPv6()) {
|
||||
// When IPv6 is enabled, we should prefer an IPv6 connection over an IPv4
|
||||
// connection.
|
||||
EXPECT_EQ(0u, num_best_ipv4);
|
||||
EXPECT_EQ(1u, num_best_ipv6);
|
||||
} else {
|
||||
EXPECT_EQ(1u, num_best_ipv4);
|
||||
EXPECT_EQ(0u, num_best_ipv6);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0u, metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterIceCandidatePairTypeUdp,
|
||||
webrtc::kIceCandidatePairHostHost));
|
||||
EXPECT_EQ(1u, metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterIceCandidatePairTypeUdp,
|
||||
webrtc::kIceCandidatePairHostPublicHostPublic));
|
||||
}
|
||||
|
||||
constexpr uint32_t kFlagsIPv4NoStun = cricket::PORTALLOCATOR_DISABLE_TCP |
|
||||
cricket::PORTALLOCATOR_DISABLE_STUN |
|
||||
cricket::PORTALLOCATOR_DISABLE_RELAY;
|
||||
constexpr uint32_t kFlagsIPv6NoStun =
|
||||
cricket::PORTALLOCATOR_DISABLE_TCP | cricket::PORTALLOCATOR_DISABLE_STUN |
|
||||
cricket::PORTALLOCATOR_ENABLE_IPV6 | cricket::PORTALLOCATOR_DISABLE_RELAY;
|
||||
constexpr uint32_t kFlagsIPv4Stun =
|
||||
cricket::PORTALLOCATOR_DISABLE_TCP | cricket::PORTALLOCATOR_DISABLE_RELAY;
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PeerConnectionIntegrationTest,
|
||||
PeerConnectionIntegrationIceStatesTest,
|
||||
Values(std::make_pair("IPv4 no STUN", kFlagsIPv4NoStun),
|
||||
std::make_pair("IPv6 no STUN", kFlagsIPv6NoStun),
|
||||
std::make_pair("IPv4 with STUN",
|
||||
kFlagsIPv4Stun)));
|
||||
|
||||
// This test sets up a call between two parties with audio and video.
|
||||
// During the call, the caller restarts ICE and the test verifies that
|
||||
// new ICE candidates are generated and audio and video still can flow, and the
|
||||
@ -3232,6 +3477,38 @@ TEST_F(PeerConnectionIntegrationTest, RtcEventLogOutputWriteCalled) {
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
}
|
||||
|
||||
// Test that if candidates are only signaled by applying full session
|
||||
// descriptions (instead of using AddIceCandidate), the peers can connect to
|
||||
// each other and exchange media.
|
||||
TEST_F(PeerConnectionIntegrationTest, MediaFlowsWhenCandidatesSetOnlyInSdp) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
// Each side will signal the session descriptions but not candidates.
|
||||
ConnectFakeSignalingForSdpOnly();
|
||||
|
||||
// Add audio video track and exchange the initial offer/answer with media
|
||||
// information only. This will start ICE gathering on each side.
|
||||
caller()->AddAudioVideoMediaStream();
|
||||
callee()->AddAudioVideoMediaStream();
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
|
||||
// Wait for all candidates to be gathered on both the caller and callee.
|
||||
ASSERT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete,
|
||||
caller()->ice_gathering_state(), kDefaultTimeout);
|
||||
ASSERT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete,
|
||||
callee()->ice_gathering_state(), kDefaultTimeout);
|
||||
|
||||
// The candidates will now be included in the session description, so
|
||||
// signaling them will start the ICE connection.
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
// Ensure that media flows in both directions.
|
||||
ExpectNewFramesReceivedWithWait(
|
||||
kDefaultExpectedAudioFrameCount, kDefaultExpectedVideoFrameCount,
|
||||
kDefaultExpectedAudioFrameCount, kDefaultExpectedVideoFrameCount,
|
||||
kMaxWaitForFramesMs);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // if !defined(THREAD_SANITIZER)
|
||||
|
||||
@ -77,9 +77,6 @@ typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
|
||||
|
||||
static const int kClientAddrPort = 0;
|
||||
static const char kClientAddrHost1[] = "11.11.11.11";
|
||||
static const char kClientIPv6AddrHost1[] =
|
||||
"2620:0:aaaa:bbbb:cccc:dddd:eeee:ffff";
|
||||
static const char kClientAddrHost2[] = "22.22.22.22";
|
||||
static const char kStunAddrHost[] = "99.99.99.1";
|
||||
|
||||
static const char kSessionVersion[] = "1";
|
||||
@ -370,9 +367,6 @@ class WebRtcSessionTest
|
||||
void AddInterface(const SocketAddress& addr) {
|
||||
network_manager_.AddInterface(addr);
|
||||
}
|
||||
void RemoveInterface(const SocketAddress& addr) {
|
||||
network_manager_.RemoveInterface(addr);
|
||||
}
|
||||
|
||||
// If |cert_generator| != null or |rtc_configuration| contains |certificates|
|
||||
// then DTLS will be enabled unless explicitly disabled by |rtc_configuration|
|
||||
@ -1057,99 +1051,6 @@ class WebRtcSessionTest
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Helper class to configure loopback network and verify Best
|
||||
// Connection using right IP protocol for TestLoopbackCall
|
||||
// method. LoopbackNetworkManager applies firewall rules to block
|
||||
// all ping traffic once ICE completed, and remove them to observe
|
||||
// ICE reconnected again. This LoopbackNetworkConfiguration struct
|
||||
// verifies the best connection is using the right IP protocol after
|
||||
// initial ICE convergences.
|
||||
|
||||
class LoopbackNetworkConfiguration {
|
||||
public:
|
||||
LoopbackNetworkConfiguration()
|
||||
: test_ipv6_network_(false),
|
||||
test_extra_ipv4_network_(false),
|
||||
best_connection_after_initial_ice_converged_(1, 0) {}
|
||||
|
||||
// Used to track the expected best connection count in each IP protocol.
|
||||
struct ExpectedBestConnection {
|
||||
ExpectedBestConnection(int ipv4_count, int ipv6_count)
|
||||
: ipv4_count_(ipv4_count),
|
||||
ipv6_count_(ipv6_count) {}
|
||||
|
||||
int ipv4_count_;
|
||||
int ipv6_count_;
|
||||
};
|
||||
|
||||
bool test_ipv6_network_;
|
||||
bool test_extra_ipv4_network_;
|
||||
ExpectedBestConnection best_connection_after_initial_ice_converged_;
|
||||
|
||||
void VerifyBestConnectionAfterIceConverge(
|
||||
const rtc::scoped_refptr<FakeMetricsObserver> metrics_observer) const {
|
||||
Verify(metrics_observer, best_connection_after_initial_ice_converged_);
|
||||
}
|
||||
|
||||
private:
|
||||
void Verify(const rtc::scoped_refptr<FakeMetricsObserver> metrics_observer,
|
||||
const ExpectedBestConnection& expected) const {
|
||||
EXPECT_EQ(
|
||||
metrics_observer->GetEnumCounter(webrtc::kEnumCounterAddressFamily,
|
||||
webrtc::kBestConnections_IPv4),
|
||||
expected.ipv4_count_);
|
||||
EXPECT_EQ(
|
||||
metrics_observer->GetEnumCounter(webrtc::kEnumCounterAddressFamily,
|
||||
webrtc::kBestConnections_IPv6),
|
||||
expected.ipv6_count_);
|
||||
// This is used in the loopback call so there is only single host to host
|
||||
// candidate pair.
|
||||
EXPECT_EQ(metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterIceCandidatePairTypeUdp,
|
||||
webrtc::kIceCandidatePairHostHost),
|
||||
0);
|
||||
EXPECT_EQ(metrics_observer->GetEnumCounter(
|
||||
webrtc::kEnumCounterIceCandidatePairTypeUdp,
|
||||
webrtc::kIceCandidatePairHostPublicHostPublic),
|
||||
1);
|
||||
}
|
||||
};
|
||||
|
||||
class LoopbackNetworkManager {
|
||||
public:
|
||||
LoopbackNetworkManager(WebRtcSessionTest* session,
|
||||
const LoopbackNetworkConfiguration& config)
|
||||
: config_(config) {
|
||||
session->AddInterface(
|
||||
rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
if (config_.test_extra_ipv4_network_) {
|
||||
session->AddInterface(
|
||||
rtc::SocketAddress(kClientAddrHost2, kClientAddrPort));
|
||||
}
|
||||
if (config_.test_ipv6_network_) {
|
||||
session->AddInterface(
|
||||
rtc::SocketAddress(kClientIPv6AddrHost1, kClientAddrPort));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyFirewallRules(rtc::FirewallSocketServer* fss) {
|
||||
fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY,
|
||||
rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
if (config_.test_extra_ipv4_network_) {
|
||||
fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY,
|
||||
rtc::SocketAddress(kClientAddrHost2, kClientAddrPort));
|
||||
}
|
||||
if (config_.test_ipv6_network_) {
|
||||
fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY,
|
||||
rtc::SocketAddress(kClientIPv6AddrHost1, kClientAddrPort));
|
||||
}
|
||||
}
|
||||
|
||||
void ClearRules(rtc::FirewallSocketServer* fss) { fss->ClearRules(); }
|
||||
|
||||
private:
|
||||
LoopbackNetworkConfiguration config_;
|
||||
};
|
||||
|
||||
// The method sets up a call from the session to itself, in a loopback
|
||||
// arrangement. It also uses a firewall rule to create a temporary
|
||||
@ -1195,50 +1096,8 @@ class WebRtcSessionTest
|
||||
observer_.ice_connection_state_, kIceCandidatesTimeout);
|
||||
}
|
||||
|
||||
void TestLoopbackCall(const LoopbackNetworkConfiguration& config) {
|
||||
LoopbackNetworkManager loopback_network_manager(this, config);
|
||||
SetupLoopbackCall();
|
||||
config.VerifyBestConnectionAfterIceConverge(metrics_observer_);
|
||||
// Adding firewall rule to block ping requests, which should cause
|
||||
// transport channel failure.
|
||||
|
||||
loopback_network_manager.ApplyFirewallRules(fss_.get());
|
||||
|
||||
LOG(LS_INFO) << "Firewall Rules applied";
|
||||
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
|
||||
observer_.ice_connection_state_,
|
||||
kIceCandidatesTimeout);
|
||||
|
||||
metrics_observer_->Reset();
|
||||
|
||||
// Clearing the rules, session should move back to completed state.
|
||||
loopback_network_manager.ClearRules(fss_.get());
|
||||
|
||||
LOG(LS_INFO) << "Firewall Rules cleared";
|
||||
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
|
||||
observer_.ice_connection_state_,
|
||||
kIceCandidatesTimeout);
|
||||
|
||||
// Now we block ping requests and wait until the ICE connection transitions
|
||||
// to the Failed state. This will take at least 30 seconds because it must
|
||||
// wait for the Port to timeout.
|
||||
int port_timeout = 30000;
|
||||
|
||||
loopback_network_manager.ApplyFirewallRules(fss_.get());
|
||||
LOG(LS_INFO) << "Firewall Rules applied again";
|
||||
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
|
||||
observer_.ice_connection_state_,
|
||||
kIceCandidatesTimeout + port_timeout);
|
||||
}
|
||||
|
||||
void TestLoopbackCall() {
|
||||
LoopbackNetworkConfiguration config;
|
||||
TestLoopbackCall(config);
|
||||
}
|
||||
|
||||
void TestPacketOptions() {
|
||||
LoopbackNetworkConfiguration config;
|
||||
LoopbackNetworkManager loopback_network_manager(this, config);
|
||||
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
|
||||
SetupLoopbackCall();
|
||||
|
||||
@ -2481,8 +2340,7 @@ TEST_F(WebRtcSessionTest, TestMaxBundleWithSetRemoteDescriptionFirst) {
|
||||
// disconnected non-bundle transport and then replacing it. The application
|
||||
// should not receive any changes in the ICE state.
|
||||
TEST_F(WebRtcSessionTest, TestAddChannelToConnectedBundle) {
|
||||
LoopbackNetworkConfiguration config;
|
||||
LoopbackNetworkManager loopback_network_manager(this, config);
|
||||
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
// Both BUNDLE and RTCP-mux need to be enabled for the ICE state to remain
|
||||
// connected. Disabling either of these two means that we need to wait for the
|
||||
// answer to find out if more transports are needed.
|
||||
@ -2721,37 +2579,6 @@ TEST_F(WebRtcSessionTest, TestSessionContentError) {
|
||||
SetLocalDescriptionExpectError("", "ERROR_CONTENT", offer);
|
||||
}
|
||||
|
||||
// Runs the loopback call test with BUNDLE and STUN disabled.
|
||||
TEST_F(WebRtcSessionTest, TestIceStatesBasic) {
|
||||
// Lets try with only UDP ports.
|
||||
allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
|
||||
cricket::PORTALLOCATOR_DISABLE_STUN |
|
||||
cricket::PORTALLOCATOR_DISABLE_RELAY);
|
||||
TestLoopbackCall();
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, TestIceStatesBasicIPv6) {
|
||||
allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
|
||||
cricket::PORTALLOCATOR_DISABLE_STUN |
|
||||
cricket::PORTALLOCATOR_ENABLE_IPV6 |
|
||||
cricket::PORTALLOCATOR_DISABLE_RELAY);
|
||||
|
||||
// best connection is IPv6 since it has higher network preference.
|
||||
LoopbackNetworkConfiguration config;
|
||||
config.test_ipv6_network_ = true;
|
||||
config.best_connection_after_initial_ice_converged_ =
|
||||
LoopbackNetworkConfiguration::ExpectedBestConnection(0, 1);
|
||||
|
||||
TestLoopbackCall(config);
|
||||
}
|
||||
|
||||
// Runs the loopback call test with BUNDLE and STUN enabled.
|
||||
TEST_F(WebRtcSessionTest, TestIceStatesBundle) {
|
||||
allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
|
||||
cricket::PORTALLOCATOR_DISABLE_RELAY);
|
||||
TestLoopbackCall();
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
|
||||
configuration_.enable_rtp_data_channel = true;
|
||||
Init();
|
||||
@ -2945,64 +2772,6 @@ TEST_F(WebRtcSessionTest, TestCombinedAudioVideoBweConstraint) {
|
||||
EXPECT_EQ(rtc::Optional<bool>(true), audio_options.combined_audio_video_bwe);
|
||||
}
|
||||
|
||||
// Tests that we can renegotiate new media content with ICE candidates in the
|
||||
// new remote SDP.
|
||||
TEST_P(WebRtcSessionTest, TestRenegotiateNewMediaWithCandidatesInSdp) {
|
||||
InitWithDtls(GetParam());
|
||||
SetFactoryDtlsSrtp();
|
||||
|
||||
SendAudioOnlyStream2();
|
||||
SessionDescriptionInterface* offer = CreateOffer();
|
||||
SetLocalDescriptionWithoutError(offer);
|
||||
|
||||
SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
|
||||
SetRemoteDescriptionWithoutError(answer);
|
||||
|
||||
cricket::MediaSessionOptions options;
|
||||
GetOptionsForRemoteOffer(&options);
|
||||
offer = CreateRemoteOffer(options, cricket::SEC_DISABLED);
|
||||
|
||||
cricket::Candidate candidate1;
|
||||
candidate1.set_address(rtc::SocketAddress("1.1.1.1", 5000));
|
||||
candidate1.set_component(1);
|
||||
JsepIceCandidate ice_candidate(kMediaContentName1, kMediaContentIndex1,
|
||||
candidate1);
|
||||
EXPECT_TRUE(offer->AddCandidate(&ice_candidate));
|
||||
SetRemoteDescriptionWithoutError(offer);
|
||||
|
||||
answer = CreateAnswer();
|
||||
SetLocalDescriptionWithoutError(answer);
|
||||
}
|
||||
|
||||
// Tests that we can renegotiate new media content with ICE candidates separated
|
||||
// from the remote SDP.
|
||||
TEST_P(WebRtcSessionTest, TestRenegotiateNewMediaWithCandidatesSeparated) {
|
||||
InitWithDtls(GetParam());
|
||||
SetFactoryDtlsSrtp();
|
||||
|
||||
SendAudioOnlyStream2();
|
||||
SessionDescriptionInterface* offer = CreateOffer();
|
||||
SetLocalDescriptionWithoutError(offer);
|
||||
|
||||
SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
|
||||
SetRemoteDescriptionWithoutError(answer);
|
||||
|
||||
cricket::MediaSessionOptions options;
|
||||
GetOptionsForRemoteOffer(&options);
|
||||
offer = CreateRemoteOffer(options, cricket::SEC_DISABLED);
|
||||
SetRemoteDescriptionWithoutError(offer);
|
||||
|
||||
cricket::Candidate candidate1;
|
||||
candidate1.set_address(rtc::SocketAddress("1.1.1.1", 5000));
|
||||
candidate1.set_component(1);
|
||||
JsepIceCandidate ice_candidate(kMediaContentName1, kMediaContentIndex1,
|
||||
candidate1);
|
||||
EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate));
|
||||
|
||||
answer = CreateAnswer();
|
||||
SetLocalDescriptionWithoutError(answer);
|
||||
}
|
||||
|
||||
#ifdef HAVE_QUIC
|
||||
TEST_P(WebRtcSessionTest, TestNegotiateQuic) {
|
||||
configuration_.enable_quic = true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user