Source code

Revision control

Copy as Markdown

Other Tools

/*
* Copyright 2012 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_INTEGRATION_TEST_HELPERS_H_
#define PC_TEST_INTEGRATION_TEST_HELPERS_H_
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <functional>
#include <limits>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "api/candidate.h"
#include "api/data_channel_interface.h"
#include "api/dtls_transport_interface.h"
#include "api/environment/environment.h"
#include "api/ice_transport_interface.h"
#include "api/jsep.h"
#include "api/make_ref_counted.h"
#include "api/media_stream_interface.h"
#include "api/media_types.h"
#include "api/metronome/metronome.h"
#include "api/peer_connection_interface.h"
#include "api/rtc_error.h"
#include "api/rtc_event_log_output.h"
#include "api/rtp_header_extension_id.h"
#include "api/rtp_receiver_interface.h"
#include "api/rtp_sender_interface.h"
#include "api/rtp_transceiver_interface.h"
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "api/stats/rtc_stats_report.h"
#include "api/stats/rtcstats_objects.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "api/task_queue/task_queue_base.h"
#include "api/test/mock_async_dns_resolver.h"
#include "api/test/time_controller.h"
#include "api/units/time_delta.h"
#include "api/video/video_rotation.h"
#include "logging/rtc_event_log/fake_rtc_event_log_factory.h"
#include "media/base/stream_params.h"
#include "p2p/base/ice_transport_internal.h"
#include "p2p/base/port.h"
#include "p2p/base/port_allocator.h"
#include "p2p/test/fake_ice_transport.h"
#include "p2p/test/test_stun_server.h"
#include "p2p/test/test_turn_customizer.h"
#include "p2p/test/test_turn_server.h"
#include "pc/peer_connection.h"
#include "pc/peer_connection_factory.h"
#include "pc/session_description.h"
#include "pc/test/fake_audio_capture_module.h"
#include "pc/test/fake_periodic_video_source.h"
#include "pc/test/fake_video_track_renderer.h"
#include "pc/test/mock_peer_connection_observers.h"
#include "pc/video_track_source.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/fake_network.h"
#include "rtc_base/firewall_socket_server.h"
#include "rtc_base/logging.h"
#include "rtc_base/net_helper.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/socket_server.h"
#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/system/plan_b_only.h"
#include "rtc_base/thread.h"
#include "rtc_base/virtual_socket_server.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/run_loop.h"
#include "test/time_controller/simulated_time_controller.h"
#include "test/wait_until.h"
namespace webrtc {
namespace internal {
class PeerConnectionIntegrationTestBase;
} // namespace internal
using ::testing::_;
using ::testing::Combine;
using ::testing::Contains;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::InvokeArgument;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::UnorderedElementsAreArray;
using ::testing::Values;
using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
constexpr TimeDelta kDefaultTimeout = TimeDelta::Millis(10000);
constexpr TimeDelta kLongTimeout = TimeDelta::Millis(60000);
constexpr TimeDelta kMaxWaitForStats = TimeDelta::Millis(3000);
constexpr TimeDelta kMaxWaitForActivation = TimeDelta::Millis(5000);
constexpr TimeDelta kMaxWaitForFrames = TimeDelta::Millis(10000);
// Default number of audio/video frames to wait for before considering a test
// successful.
static const int kDefaultExpectedAudioFrameCount = 3;
static const int kDefaultExpectedVideoFrameCount = 3;
static const char kDataChannelLabel[] = "data_channel";
// SRTP cipher name negotiated by the tests. This must be updated if the
// default changes.
static const int kDefaultSrtpCryptoSuite = kSrtpAes128CmSha1_80;
static const int kDefaultSrtpCryptoSuiteGcm = kSrtpAeadAes256Gcm;
static const SocketAddress kDefaultLocalAddress("192.168.1.1", 0);
// Helper function for constructing offer/answer options to initiate an ICE
// restart.
PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions();
// Remove all stream information (SSRCs, track IDs, etc.) and "msid-semantic"
// attribute from received SDP, simulating a legacy endpoint.
void RemoveSsrcsAndMsids(std::unique_ptr<SessionDescriptionInterface>& desc);
// Removes all stream information besides the stream ids, simulating an
// endpoint that only signals a=msid lines to convey stream_ids.
void RemoveSsrcsAndKeepMsids(
std::unique_ptr<SessionDescriptionInterface>& desc);
// Set SdpType.
void SetSdpType(std::unique_ptr<SessionDescriptionInterface>& sdp,
SdpType sdpType);
// Replaces the stream's primary SSRC and updates the first SSRC of all
// ssrc-groups.
void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc);
int FindFirstMediaStatsIndexByKind(
const std::string& kind,
const std::vector<const RTCInboundRtpStreamStats*>& inbound_rtps);
// Tests whether a session description contains conflicting descriptions
// for a payload type within a bundle.
RTCError ValidateBundledPayloadTypes(const SessionDescription& description);
class TaskQueueMetronome : public Metronome {
public:
explicit TaskQueueMetronome(TimeDelta tick_period);
~TaskQueueMetronome() override;
// Metronome implementation.
void RequestCallOnNextTick(absl::AnyInvocable<void() &&> callback) override;
TimeDelta TickPeriod() const override;
private:
const TimeDelta tick_period_;
SequenceChecker sequence_checker_{SequenceChecker::kDetached};
std::vector<absl::AnyInvocable<void() &&>> callbacks_;
ScopedTaskSafetyDetached safety_;
};
class SignalingMessageReceiver {
public:
virtual void ReceiveSdpMessage(SdpType type, const std::string& msg) = 0;
virtual void ReceiveIceMessage(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& msg) = 0;
protected:
SignalingMessageReceiver() {}
virtual ~SignalingMessageReceiver() {}
};
class MockRtpReceiverObserver : public RtpReceiverObserverInterface {
public:
explicit MockRtpReceiverObserver(webrtc::MediaType media_type)
: expected_media_type_(media_type) {}
void OnFirstPacketReceived(webrtc::MediaType media_type) override {
ASSERT_EQ(expected_media_type_, media_type);
first_packet_received_ = true;
}
void OnFirstPacketReceivedAfterReceptiveChange(
webrtc::MediaType media_type) override {
ASSERT_EQ(expected_media_type_, media_type);
first_packet_received_after_receptive_change_ = true;
}
bool first_packet_received() const { return first_packet_received_; }
bool first_packet_received_after_receptive_change() const {
return first_packet_received_after_receptive_change_;
}
~MockRtpReceiverObserver() override {}
private:
bool first_packet_received_ = false;
bool first_packet_received_after_receptive_change_ = false;
webrtc::MediaType expected_media_type_;
};
class MockRtpSenderObserver : public RtpSenderObserverInterface {
public:
explicit MockRtpSenderObserver(webrtc::MediaType media_type)
: expected_media_type_(media_type) {}
void OnFirstPacketSent(webrtc::MediaType media_type) override {
ASSERT_EQ(expected_media_type_, media_type);
first_packet_sent_ = true;
}
bool first_packet_sent() const { return first_packet_sent_; }
~MockRtpSenderObserver() override {}
private:
bool first_packet_sent_ = false;
webrtc::MediaType expected_media_type_;
};
// Helper class that wraps a peer connection, observes it, and can accept
// signaling messages from another wrapper.
//
// Uses a fake network, fake A/V capture, and optionally fake
// encoders/decoders, though they aren't used by default since they don't
// advertise support of any codecs.
// TODO(steveanton): See how this could become a subclass of
// PeerConnectionWrapper defined in peerconnectionwrapper.h.
class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
public SignalingMessageReceiver {
public:
explicit PeerConnectionIntegrationWrapper(
const std::string& debug_name,
Environment env,
internal::PeerConnectionIntegrationTestBase* test);
PeerConnectionFactoryInterface* pc_factory() const {
return peer_connection_factory_.get();
}
PeerConnectionInterface* pc() const { return peer_connection_.get(); }
// Return the PC implementation, so that non-public interfaces
// can be used in tests.
PeerConnection* pc_internal() const;
// If a signaling message receiver is set (via ConnectFakeSignaling), this
// will set the whole offer/answer exchange in motion. Just need to wait for
// the signaling state to reach "stable".
void CreateAndSetAndSignalOffer();
// Sets the options to be used when CreateAndSetAndSignalOffer is called, or
// when a remote offer is received (via fake signaling) and an answer is
// generated. By default, uses default options.
void SetOfferAnswerOptions(
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
offer_answer_options_ = options;
}
// Set a callback to be invoked when SDP is received via the fake signaling
// channel, which provides an opportunity to munge (modify) the SDP. This is
// used to test SDP being applied that a PeerConnection would normally not
// generate, but a non-JSEP endpoint might.
void SetReceivedSdpMunger(
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
munger) {
received_sdp_munger_ = std::move(munger);
}
// Similar to the above, but this is run on SDP immediately after it's
// generated.
void SetGeneratedSdpMunger(
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
munger) {
generated_sdp_munger_ = std::move(munger);
}
// Set a callback to be invoked when a remote offer is received via the fake
// signaling channel. This provides an opportunity to change the
// PeerConnection state before an answer is created and sent to the caller.
void SetRemoteOfferHandler(std::function<void()> handler) {
remote_offer_handler_ = std::move(handler);
}
void SetRemoteAsyncResolver(MockAsyncDnsResolver* resolver) {
remote_async_dns_resolver_ = resolver;
}
// 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_;
}
void clear_ice_connection_state_history() {
ice_connection_state_history_.clear();
}
// Every standardized ICE connection state in order that has been seen by the
// observer.
std::vector<PeerConnectionInterface::IceConnectionState>
standardized_ice_connection_state_history() const {
return standardized_ice_connection_state_history_;
}
// Every PeerConnection state in order that has been seen by the observer.
std::vector<PeerConnectionInterface::PeerConnectionState>
peer_connection_state_history() const {
return peer_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_;
}
std::vector<CandidatePairChangeEvent> ice_candidate_pair_change_history()
const {
return ice_candidate_pair_change_history_;
}
// Every PeerConnection signaling state in order that has been seen by the
// observer.
std::vector<PeerConnectionInterface::SignalingState>
peer_connection_signaling_state_history() const {
return peer_connection_signaling_state_history_;
}
void AddAudioVideoTracks();
scoped_refptr<RtpSenderInterface> AddAudioTrack() {
return AddTrack(CreateLocalAudioTrack());
}
scoped_refptr<RtpSenderInterface> AddVideoTrack() {
return AddTrack(CreateLocalVideoTrack());
}
scoped_refptr<AudioTrackInterface> CreateLocalAudioTrack();
scoped_refptr<VideoTrackInterface> CreateLocalVideoTrack();
scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackWithConfig(
FakePeriodicVideoSource::Config config);
scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackWithRotation(
VideoRotation rotation);
scoped_refptr<RtpSenderInterface> AddTrack(
scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids = {});
std::vector<scoped_refptr<RtpReceiverInterface>> GetReceiversOfType(
webrtc::MediaType media_type);
scoped_refptr<RtpTransceiverInterface> GetFirstTransceiverOfType(
webrtc::MediaType media_type);
bool SignalingStateStable();
bool IceGatheringStateComplete();
void CreateDataChannel();
void CreateDataChannel(const DataChannelInit* init);
void CreateDataChannel(const std::string& label, const DataChannelInit* init);
// Return the last observed data channel.
DataChannelInterface* data_channel();
// Return all data channels.
std::vector<scoped_refptr<DataChannelInterface>>& data_channels() {
return data_channels_;
}
MockDataChannelObserver* data_observer() const;
std::vector<std::unique_ptr<MockDataChannelObserver>>& data_observers() {
return data_observers_;
}
std::unique_ptr<SessionDescriptionInterface> CreateAnswerForTest();
int audio_frames_received() const;
// Takes minimum of video frames received for each track.
//
// Can be used like:
// EXPECT_GE(expected_frames, min_video_frames_received_per_track());
//
// To ensure that all video tracks received at least a certain number of
// frames.
int min_video_frames_received_per_track() const;
// Returns a MockStatsObserver in a state after stats gathering finished,
// which can be used to access the gathered stats.
scoped_refptr<MockStatsObserver> OldGetStatsForTrack(
MediaStreamTrackInterface* track);
// Version that doesn't take a track "filter", and gathers all stats.
scoped_refptr<MockStatsObserver> OldGetStats();
// Synchronously gets stats and returns them. If it times out, fails the test
// and returns null.
// TODO(bugs.webrtc.org/501310910): Unify NewGetStats implementations by
// making RunLoop an interface that can be implemented for simulated time too.
// TODO(tommi) - Remove this method in favor of the one that supports RunLoop.
scoped_refptr<const RTCStatsReport> NewGetStats(
WaitUntilSettings settings = {});
scoped_refptr<const RTCStatsReport> NewGetStats(test::RunLoop& run_loop);
std::string DtlsCipher();
std::string SrtpCipher();
int rendered_width();
int rendered_height();
double rendered_aspect_ratio();
VideoRotation rendered_rotation();
int local_rendered_width();
int local_rendered_height();
double local_rendered_aspect_ratio();
PLAN_B_ONLY size_t number_of_remote_streams();
PLAN_B_ONLY StreamCollectionInterface* remote_streams() const;
PLAN_B_ONLY StreamCollectionInterface* local_streams();
PeerConnectionInterface::SignalingState signaling_state();
PeerConnectionInterface::IceConnectionState ice_connection_state();
PeerConnectionInterface::IceConnectionState
standardized_ice_connection_state();
PeerConnectionInterface::IceGatheringState ice_gathering_state();
// Returns a MockRtpReceiverObserver for each RtpReceiver returned by
// GetReceivers. They're updated automatically when a remote offer/answer
// from the fake signaling channel is applied, or when
// ResetRtpReceiverObservers below is called.
const std::vector<std::unique_ptr<MockRtpReceiverObserver>>&
rtp_receiver_observers() {
return rtp_receiver_observers_;
}
void ResetRtpReceiverObservers();
const std::vector<std::unique_ptr<MockRtpSenderObserver>>&
rtp_sender_observers() {
return rtp_sender_observers_;
}
void ResetRtpSenderObservers();
FakeNetworkManager* network_manager() const { return fake_network_manager_; }
FakeRtcEventLogFactory* event_log_factory() const {
return event_log_factory_;
}
Candidate last_candidate_gathered() const;
const IceCandidate* last_gathered_ice_candidate() const {
return last_gathered_ice_candidate_.get();
}
const IceCandidateErrorEvent& error_event() const { return error_event_; }
// Sets the mDNS responder for the owned fake network manager and keeps a
// reference to the responder.
void SetMdnsResponder(std::unique_ptr<FakeMdnsResponder> mdns_responder);
// Returns null on failure.
std::unique_ptr<SessionDescriptionInterface> CreateOfferAndWait();
bool Rollback();
// Functions for querying stats.
void StartWatchingDelayStats();
void UpdateDelayStats(std::string tag, int desc_size);
bool AudioDelayStatsPercentageChecked() const {
return audio_delay_stats_percentage_checked_;
}
// Sets number of candidates expected
void ExpectCandidates(int candidate_count) {
candidates_expected_ = candidate_count;
}
bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc);
void NegotiateCorruptionDetectionHeader();
uint32_t GetCorruptionScoreCount();
uint32_t GetReceivedFrameCount();
void set_connection_change_callback(
std::function<void(PeerConnectionInterface::PeerConnectionState)> func) {
connection_change_callback_ = std::move(func);
}
std::optional<int> tls_version();
std::optional<DtlsTransportTlsRole> dtls_transport_role();
DtlsTransportInformation dtls_transport_information();
// Setting the local description and sending the SDP message over the fake
// signaling channel are combined into the same method because the SDP
// message needs to be sent as soon as SetLocalDescription finishes, without
// waiting for the observer to be called. This ensures that ICE candidates
// don't outrace the description.
bool SetLocalDescriptionAndSendSdpMessage(
std::unique_ptr<SessionDescriptionInterface> desc);
public:
bool Init(const PeerConnectionFactory::Options* options,
const PeerConnectionInterface::RTCConfiguration* config,
PeerConnectionDependencies dependencies,
SocketServer* socket_server,
Thread* network_thread,
Thread* worker_thread,
std::unique_ptr<FakeRtcEventLogFactory> event_log_factory,
bool reset_encoder_factory,
bool reset_decoder_factory,
bool create_media_engine);
scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
const PeerConnectionInterface::RTCConfiguration* config,
PeerConnectionDependencies dependencies);
void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
void set_signal_ice_candidates(bool signal) {
signal_ice_candidates_ = signal;
}
scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackInternal(
FakePeriodicVideoSource::Config config);
void HandleIncomingOffer(const std::string& msg);
void HandleIncomingAnswer(SdpType type, const std::string& msg);
// Returns null on failure.
std::unique_ptr<SessionDescriptionInterface> CreateAnswer();
// This is a work around to remove unused fake_video_renderers from
// transceivers that have either stopped or are no longer receiving.
void RemoveUnusedVideoRenderers();
// Simulate sending a blob of SDP with delay `signaling_delay_ms_` (0 by
// default).
void SendSdpMessage(SdpType type, const std::string& msg);
void RelaySdpMessageIfReceiverExists(SdpType type, const std::string& msg);
// Simulate trickling an ICE candidate with delay `signaling_delay_ms_` (0 by
// default).
void SendIceMessage(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& msg);
void RelayIceMessageIfReceiverExists(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& msg);
// SignalingMessageReceiver callbacks.
public:
void set_signaling_message_receiver(
SignalingMessageReceiver* signaling_message_receiver) {
signaling_message_receiver_ = signaling_message_receiver;
}
void ReceiveSdpMessage(SdpType type, const std::string& msg) override;
void ReceiveIceMessage(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& msg) override;
private:
// PeerConnectionObserver callbacks.
void OnSignalingChange(
PeerConnectionInterface::SignalingState new_state) override;
void OnAddTrack(
scoped_refptr<RtpReceiverInterface> receiver,
const std::vector<scoped_refptr<MediaStreamInterface>>& streams) override;
void OnRemoveTrack(scoped_refptr<RtpReceiverInterface> receiver) override;
void OnRenegotiationNeeded() override;
void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) override;
void OnStandardizedIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) override;
void OnConnectionChange(
PeerConnectionInterface::PeerConnectionState new_state) override;
void OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) override;
void OnIceSelectedCandidatePairChanged(
const CandidatePairChangeEvent& event) override {
ice_candidate_pair_change_history_.push_back(event);
}
void OnIceCandidate(const IceCandidate* candidate) override;
void OnIceCandidateError(const std::string& address,
int port,
const std::string& url,
int error_code,
const std::string& error_text) override;
void OnIceCandidateRemoved(const IceCandidate* candidate) override {}
void OnDataChannel(scoped_refptr<DataChannelInterface> data_channel) override;
bool IdExists(const RtpHeaderExtensions& extensions, RtpHeaderExtensionId id);
private:
std::string debug_name_;
const Environment env_;
// Network manager is owned by the `peer_connection_factory_`.
FakeNetworkManager* fake_network_manager_ = nullptr;
Thread* network_thread_;
// Reference to the mDNS responder owned by `fake_network_manager_` after set.
FakeMdnsResponder* mdns_responder_ = nullptr;
scoped_refptr<PeerConnectionInterface> peer_connection_;
scoped_refptr<PeerConnectionFactoryInterface> peer_connection_factory_;
// Needed to keep track of number of frames sent.
scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
// Needed to keep track of number of frames received.
std::map<std::string, std::unique_ptr<FakeVideoTrackRenderer>>
fake_video_renderers_;
// Needed to ensure frames aren't received for removed tracks.
std::vector<std::unique_ptr<FakeVideoTrackRenderer>>
removed_fake_video_renderers_;
// For remote peer communication.
SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
int signaling_delay_ms_ = 0;
bool signal_ice_candidates_ = true;
std::unique_ptr<IceCandidate> last_gathered_ice_candidate_;
IceCandidateErrorEvent error_event_;
// Store references to the video sources we've created, so that we can stop
// them, if required.
std::vector<scoped_refptr<VideoTrackSource>> video_track_sources_;
// `local_video_renderer_` attached to the first created local video track.
std::unique_ptr<FakeVideoTrackRenderer> local_video_renderer_;
SdpSemantics sdp_semantics_;
PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options_;
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
received_sdp_munger_;
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
generated_sdp_munger_;
std::function<void()> remote_offer_handler_;
MockAsyncDnsResolver* remote_async_dns_resolver_ = nullptr;
// Result variables for the mock DNS resolver
NiceMock<MockAsyncDnsResolverResult> remote_async_dns_resolver_result_;
SocketAddress remote_async_dns_resolved_addr_;
// All data channels either created or observed on this peerconnection
std::vector<scoped_refptr<DataChannelInterface>> data_channels_;
std::vector<std::unique_ptr<MockDataChannelObserver>> data_observers_;
std::vector<std::unique_ptr<MockRtpReceiverObserver>> rtp_receiver_observers_;
std::vector<std::unique_ptr<MockRtpSenderObserver>> rtp_sender_observers_;
std::vector<PeerConnectionInterface::IceConnectionState>
ice_connection_state_history_;
std::vector<PeerConnectionInterface::IceConnectionState>
standardized_ice_connection_state_history_;
std::vector<PeerConnectionInterface::PeerConnectionState>
peer_connection_state_history_;
std::vector<PeerConnectionInterface::IceGatheringState>
ice_gathering_state_history_;
std::vector<CandidatePairChangeEvent> ice_candidate_pair_change_history_;
std::vector<PeerConnectionInterface::SignalingState>
peer_connection_signaling_state_history_;
FakeRtcEventLogFactory* event_log_factory_;
// Number of ICE candidates expected. The default is no limit.
int candidates_expected_ = std::numeric_limits<int>::max();
// Variables for tracking delay stats on an audio track
int audio_packets_stat_ = 0;
double audio_delay_stat_ = 0.0;
uint64_t audio_samples_stat_ = 0;
uint64_t audio_concealed_stat_ = 0;
std::string rtp_stats_id_;
bool audio_delay_stats_percentage_checked_ = false;
std::function<void(PeerConnectionInterface::PeerConnectionState)>
connection_change_callback_ = nullptr;
ScopedTaskSafety task_safety_;
internal::PeerConnectionIntegrationTestBase* test_ = nullptr;
};
class MockRtcEventLogOutput : public RtcEventLogOutput {
public:
~MockRtcEventLogOutput() override = default;
MOCK_METHOD(bool, IsActive, (), (const, override));
MOCK_METHOD(bool, Write, (absl::string_view), (override));
};
// This helper object is used for both specifying how many audio/video frames
// are expected to be received for a caller/callee. It provides helper functions
// to specify these expectations. The object initially starts in a state of no
// expectations.
class MediaExpectations {
public:
enum ExpectFrames {
kExpectSomeFrames,
kExpectNoFrames,
kNoExpectation,
};
void ExpectBidirectionalAudioAndVideo() {
ExpectBidirectionalAudio();
ExpectBidirectionalVideo();
}
void ExpectBidirectionalAudio() {
CallerExpectsSomeAudio();
CalleeExpectsSomeAudio();
}
void ExpectNoAudio() {
CallerExpectsNoAudio();
CalleeExpectsNoAudio();
}
void ExpectBidirectionalVideo() {
CallerExpectsSomeVideo();
CalleeExpectsSomeVideo();
}
void ExpectNoVideo() {
CallerExpectsNoVideo();
CalleeExpectsNoVideo();
}
void CallerExpectsSomeAudioAndVideo() {
CallerExpectsSomeAudio();
CallerExpectsSomeVideo();
}
void CalleeExpectsSomeAudioAndVideo() {
CalleeExpectsSomeAudio();
CalleeExpectsSomeVideo();
}
// Caller's audio functions.
void CallerExpectsSomeAudio(
int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
caller_audio_expectation_ = kExpectSomeFrames;
caller_audio_frames_expected_ = expected_audio_frames;
}
void CallerExpectsNoAudio() {
caller_audio_expectation_ = kExpectNoFrames;
caller_audio_frames_expected_ = 0;
}
// Caller's video functions.
void CallerExpectsSomeVideo(
int expected_video_frames = kDefaultExpectedVideoFrameCount) {
caller_video_expectation_ = kExpectSomeFrames;
caller_video_frames_expected_ = expected_video_frames;
}
void CallerExpectsNoVideo() {
caller_video_expectation_ = kExpectNoFrames;
caller_video_frames_expected_ = 0;
}
// Callee's audio functions.
void CalleeExpectsSomeAudio(
int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
callee_audio_expectation_ = kExpectSomeFrames;
callee_audio_frames_expected_ = expected_audio_frames;
}
void CalleeExpectsNoAudio() {
callee_audio_expectation_ = kExpectNoFrames;
callee_audio_frames_expected_ = 0;
}
// Callee's video functions.
void CalleeExpectsSomeVideo(
int expected_video_frames = kDefaultExpectedVideoFrameCount) {
callee_video_expectation_ = kExpectSomeFrames;
callee_video_frames_expected_ = expected_video_frames;
}
void CalleeExpectsNoVideo() {
callee_video_expectation_ = kExpectNoFrames;
callee_video_frames_expected_ = 0;
}
ExpectFrames caller_audio_expectation_ = kNoExpectation;
ExpectFrames caller_video_expectation_ = kNoExpectation;
ExpectFrames callee_audio_expectation_ = kNoExpectation;
ExpectFrames callee_video_expectation_ = kNoExpectation;
int caller_audio_frames_expected_ = 0;
int caller_video_frames_expected_ = 0;
int callee_audio_frames_expected_ = 0;
int callee_video_frames_expected_ = 0;
};
class MockIceTransport : public IceTransportInterface {
public:
MockIceTransport(const std::string& name, int component)
: internal_(std::make_unique<FakeIceTransportInternal>(name,
component,
nullptr)) {}
~MockIceTransport() override = default;
IceTransportInternal* internal() override { return internal_.get(); }
private:
std::unique_ptr<FakeIceTransportInternal> internal_;
};
class MockIceTransportFactory : public IceTransportFactory {
public:
~MockIceTransportFactory() override = default;
scoped_refptr<IceTransportInterface> CreateIceTransport(
const std::string& transport_name,
int component,
IceTransportInit init) override {
RecordIceTransportCreated();
return make_ref_counted<MockIceTransport>(transport_name, component);
}
MOCK_METHOD(void, RecordIceTransportCreated, ());
};
// Tests two PeerConnections connecting to each other end-to-end, using a
// virtual network, fake A/V capture and fake encoder/decoders. The
// PeerConnections share the threads/socket servers, but use separate versions
// of everything else (including "PeerConnectionFactory"s).
namespace internal {
class PeerConnectionIntegrationTestBase : public ::testing::Test {
public:
static constexpr char kCallerName[] = "Caller";
static constexpr char kCalleeName[] = "Callee";
explicit PeerConnectionIntegrationTestBase(Environment env,
SdpSemantics sdp_semantics);
PeerConnectionIntegrationTestBase(Environment env,
SdpSemantics sdp_semantics,
TimeController* time_controller);
~PeerConnectionIntegrationTestBase() override;
virtual std::unique_ptr<PeerConnectionIntegrationWrapper>
CreatePeerConnectionWrapperInternal(const std::string& debug_name,
Environment env);
virtual Waiter GetWaiter(WaitUntilSettings overrides = {}) = 0;
virtual TimeController* time_controller() { return nullptr; }
virtual std::unique_ptr<Thread> CreateThread(absl::string_view name) = 0;
bool SignalingStateStable() {
return caller_->SignalingStateStable() && callee_->SignalingStateStable();
}
bool PeerConnectionStateIs(
PeerConnectionInterface::PeerConnectionState state) {
return caller_->pc()->peer_connection_state() == state &&
callee_->pc()->peer_connection_state() == state;
}
bool DtlsConnected();
// Sets field trials to pass to created PeerConnectionWrapper.
// Must be called before PeerConnectionWrappers are created.
void SetFieldTrials(absl::string_view field_trials);
// Sets field trials to pass to created PeerConnectionWrapper key:ed on
// debug_name. Must be called before PeerConnectionWrappers are created.
void SetFieldTrials(absl::string_view debug_name,
absl::string_view field_trials);
// When `event_log_factory` is null, the default implementation of the event
// log factory will be used.
std::unique_ptr<PeerConnectionIntegrationWrapper> CreatePeerConnectionWrapper(
const std::string& debug_name,
const PeerConnectionFactory::Options* options,
const RTCConfiguration* config,
PeerConnectionDependencies dependencies,
std::unique_ptr<FakeRtcEventLogFactory> event_log_factory,
bool reset_encoder_factory,
bool reset_decoder_factory,
bool create_media_engine = true);
std::unique_ptr<PeerConnectionIntegrationWrapper>
CreatePeerConnectionWrapperWithFakeRtcEventLog(
const std::string& debug_name,
const PeerConnectionFactory::Options* options,
const RTCConfiguration* config,
PeerConnectionDependencies dependencies);
bool CreatePeerConnectionWrappers() {
return CreatePeerConnectionWrappersWithConfig(
PeerConnectionInterface::RTCConfiguration(),
PeerConnectionInterface::RTCConfiguration());
}
bool CreatePeerConnectionWrappersWithSdpSemantics(
SdpSemantics caller_semantics,
SdpSemantics callee_semantics);
bool CreatePeerConnectionWrappersWithConfig(
const PeerConnectionInterface::RTCConfiguration& caller_config,
const PeerConnectionInterface::RTCConfiguration& callee_config,
bool create_media_engine = true);
bool CreatePeerConnectionWrappersWithConfigAndDeps(
const PeerConnectionInterface::RTCConfiguration& caller_config,
PeerConnectionDependencies caller_dependencies,
const PeerConnectionInterface::RTCConfiguration& callee_config,
PeerConnectionDependencies callee_dependencies);
bool CreatePeerConnectionWrappersWithOptions(
const PeerConnectionFactory::Options& caller_options,
const PeerConnectionFactory::Options& callee_options);
bool CreatePeerConnectionWrappersWithFakeRtcEventLog();
std::unique_ptr<PeerConnectionIntegrationWrapper>
CreatePeerConnectionWrapperWithAlternateKey();
bool CreateOneDirectionalPeerConnectionWrappers(bool caller_to_callee);
bool CreatePeerConnectionWrappersWithoutMediaEngine();
TestTurnServer* CreateTurnServer(
SocketAddress internal_address,
SocketAddress external_address,
ProtocolType type = ProtocolType::PROTO_UDP,
const std::string& common_name = "test turn server");
TestTurnCustomizer* CreateTurnCustomizer();
// Checks that the function counters for a TestTurnCustomizer are greater than
// 0.
void ExpectTurnCustomizerCountersIncremented(
TestTurnCustomizer* turn_customizer);
// Once called, SDP blobs and ICE candidates will be automatically signaled
// between PeerConnections.
void ConnectFakeSignaling();
// 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();
void SetSignalingDelayMs(int delay_ms);
void SetSignalIceCandidates(bool signal);
// Messages may get lost on the unreliable DataChannel, so we send multiple
// times to avoid test flakiness.
void SendRtpDataWithRetries(DataChannelInterface* dc,
const std::string& data,
int retries);
Thread* network_thread() { return network_thread_.get(); }
VirtualSocketServer* virtual_socket_server() { return ss_.get(); }
PeerConnectionIntegrationWrapper* caller() { return caller_.get(); }
// Destroy peer connections.
// This can be used to ensure that all pointers to on-stack mocks
// get dropped before exit.
void DestroyPeerConnections();
void DestroyTurnServers();
void DestroyThreads();
// Set the `caller_` to the `wrapper` passed in and return the
// original `caller_`.
PeerConnectionIntegrationWrapper* SetCallerPcWrapperAndReturnCurrent(
std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper);
PeerConnectionIntegrationWrapper* callee() { return callee_.get(); }
// Set the `callee_` to the `wrapper` passed in and return the
// original `callee_`.
PeerConnectionIntegrationWrapper* SetCalleePcWrapperAndReturnCurrent(
std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper);
FirewallSocketServer* firewall() const { return fss_.get(); }
// Expects the provided number of new frames to be received within
// kMaxWaitForFramesMs. The new expected frames are specified in
// `media_expectations`. Returns false if any of the expectations were
// not met.
bool ExpectNewFrames(const MediaExpectations& media_expectations);
void ClosePeerConnections();
void TestNegotiatedCipherSuite(const RTCConfiguration& caller_config,
const RTCConfiguration& callee_config,
int expected_cipher_suite);
void TestGcmNegotiationUsesCipherSuite(bool local_gcm_enabled,
bool remote_gcm_enabled,
bool aes_ctr_enabled,
int expected_cipher_suite);
protected:
void OverrideLoggingLevelForTest(LoggingSeverity new_severity);
SdpSemantics sdp_semantics_;
const Environment env_;
virtual void ExecuteTask(TaskQueueBase& task_queue,
absl::AnyInvocable<void()> task) = 0;
private:
// Support for optionally changing the default logging level for the duration
// of the test. Scoped wider than other member variables to also affect
// logging that's done in destructors.
class ScopedSetLoggingLevel;
std::unique_ptr<ScopedSetLoggingLevel> overridden_logging_level_;
// `ss_` is used by `network_thread_` so it must be destroyed later.
std::unique_ptr<VirtualSocketServer> ss_;
std::unique_ptr<FirewallSocketServer> fss_;
// `network_thread_` and `worker_thread_` are used by both
// `caller_` and `callee_` so they must be destroyed
// later.
std::unique_ptr<Thread> network_thread_;
std::unique_ptr<Thread> worker_thread_;
// The turn servers and turn customizers should be accessed & deleted on the
// network thread to avoid a race with the socket read/write that occurs
// on the network thread.
std::vector<std::unique_ptr<TestTurnServer>> turn_servers_;
std::vector<std::unique_ptr<TestTurnCustomizer>> turn_customizers_;
std::unique_ptr<PeerConnectionIntegrationWrapper> caller_;
std::unique_ptr<PeerConnectionIntegrationWrapper> callee_;
std::string field_trials_;
std::map<std::string, std::string> field_trials_overrides_;
};
} // namespace internal
class PeerConnectionIntegrationBaseTest
: public internal::PeerConnectionIntegrationTestBase {
public:
explicit PeerConnectionIntegrationBaseTest(SdpSemantics sdp_semantics);
~PeerConnectionIntegrationBaseTest() override;
test::RunLoop& run_loop() { return run_loop_; }
void ExecuteTask(TaskQueueBase& task_queue,
absl::AnyInvocable<void()> task) override;
Waiter GetWaiter(WaitUntilSettings overrides = {}) override;
std::unique_ptr<Thread> CreateThread(absl::string_view name) override;
protected:
test::RunLoop run_loop_;
};
class PeerConnectionIntegrationTestWithSimulatedTime
: public internal::PeerConnectionIntegrationTestBase {
public:
explicit PeerConnectionIntegrationTestWithSimulatedTime(
SdpSemantics sdp_semantics);
void ExecuteTask(TaskQueueBase& task_queue,
absl::AnyInvocable<void()> task) override;
Waiter GetWaiter(WaitUntilSettings overrides = {}) override;
TimeController* time_controller() { return time_controller_.get(); }
std::unique_ptr<Thread> CreateThread(absl::string_view name) override;
~PeerConnectionIntegrationTestWithSimulatedTime() override;
private:
PeerConnectionIntegrationTestWithSimulatedTime(
SdpSemantics sdp_semantics,
std::unique_ptr<GlobalSimulatedTimeController> time_controller);
protected:
std::unique_ptr<GlobalSimulatedTimeController> time_controller_;
};
template <typename Base>
class PeerConnectionIntegrationIceStatesTestBase
: public Base,
public ::testing::WithParamInterface<
std::tuple<SdpSemantics, std::tuple<std::string, uint32_t>>> {
protected:
PeerConnectionIntegrationIceStatesTestBase()
: Base(std::get<0>(this->GetParam())) {
port_allocator_flags_ = std::get<1>(std::get<1>(this->GetParam()));
}
void StartStunServer(const SocketAddress& server_address) {
stun_server_ = TestStunServer::Create(
this->env_, server_address, *this->firewall(), *this->network_thread());
}
bool TestIPv6() {
return (port_allocator_flags_ & PORTALLOCATOR_ENABLE_IPV6);
}
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.
this->caller()->network_manager()->RemoveInterface(kDefaultLocalAddress);
this->callee()->network_manager()->RemoveInterface(kDefaultLocalAddress);
// Add network addresses for test.
for (const auto& caller_address : CallerAddresses()) {
this->caller()->network_manager()->AddInterface(caller_address);
}
for (const auto& callee_address : CalleeAddresses()) {
this->callee()->network_manager()->AddInterface(callee_address);
}
}
uint32_t port_allocator_flags() const { return port_allocator_flags_; }
private:
uint32_t port_allocator_flags_;
TestStunServer::StunServerPtr stun_server_;
};
} // namespace webrtc
#endif // PC_TEST_INTEGRATION_TEST_HELPERS_H_