diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn index d827de0378..fe1ade26d6 100644 --- a/webrtc/api/BUILD.gn +++ b/webrtc/api/BUILD.gn @@ -405,6 +405,7 @@ if (rtc_include_tests) { "peerconnectionfactory_unittest.cc", "peerconnectioninterface_unittest.cc", "proxy_unittest.cc", + "rtcstats_integrationtest.cc", "rtcstatscollector_unittest.cc", "rtpsenderreceiver_unittest.cc", "sctputils_unittest.cc", @@ -423,6 +424,7 @@ if (rtc_include_tests) { "test/mockpeerconnectionobservers.h", "test/peerconnectiontestwrapper.cc", "test/peerconnectiontestwrapper.h", + "test/rtcstatsobtainer.h", "test/testsdpstrings.h", "videocapturertracksource_unittest.cc", "videotrack_unittest.cc", diff --git a/webrtc/api/rtcstats_integrationtest.cc b/webrtc/api/rtcstats_integrationtest.cc new file mode 100644 index 0000000000..a74d19f07a --- /dev/null +++ b/webrtc/api/rtcstats_integrationtest.cc @@ -0,0 +1,537 @@ +/* + * Copyright 2016 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 +#include + +#include "webrtc/api/datachannelinterface.h" +#include "webrtc/api/peerconnectioninterface.h" +#include "webrtc/api/stats/rtcstats_objects.h" +#include "webrtc/api/stats/rtcstatsreport.h" +#include "webrtc/api/test/peerconnectiontestwrapper.h" +#include "webrtc/api/test/rtcstatsobtainer.h" +#include "webrtc/base/checks.h" +#include "webrtc/base/gunit.h" +#include "webrtc/base/physicalsocketserver.h" +#include "webrtc/base/refcountedobject.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/base/virtualsocketserver.h" + +namespace webrtc { + +namespace { + +const int64_t kGetStatsTimeoutMs = 10000; + +class RTCStatsIntegrationTest : public testing::Test { + public: + RTCStatsIntegrationTest() + : physical_socket_server_(), + virtual_socket_server_(&physical_socket_server_), + network_thread_(&virtual_socket_server_), + worker_thread_() { + RTC_CHECK(network_thread_.Start()); + RTC_CHECK(worker_thread_.Start()); + + caller_ = new rtc::RefCountedObject( + "caller", &network_thread_, &worker_thread_); + callee_ = new rtc::RefCountedObject( + "callee", &network_thread_, &worker_thread_); + } + + void StartCall() { + // Create PeerConnections and "connect" sigslots + PeerConnectionInterface::RTCConfiguration config; + PeerConnectionInterface::IceServer ice_server; + ice_server.uri = "stun:1.1.1.1:3478"; + config.servers.push_back(ice_server); + EXPECT_TRUE(caller_->CreatePc(nullptr, config)); + EXPECT_TRUE(callee_->CreatePc(nullptr, config)); + PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get()); + + // Get user media for audio and video + caller_->GetAndAddUserMedia(true, FakeConstraints(), + true, FakeConstraints()); + callee_->GetAndAddUserMedia(true, FakeConstraints(), + true, FakeConstraints()); + + // Create data channels + DataChannelInit init; + caller_->CreateDataChannel("data", init); + callee_->CreateDataChannel("data", init); + + // Negotiate and wait for call to establish + caller_->CreateOffer(nullptr); + caller_->WaitForCallEstablished(); + callee_->WaitForCallEstablished(); + } + + rtc::scoped_refptr GetStatsFromCaller() { + return GetStats(caller_->pc()); + } + + rtc::scoped_refptr GetStatsFromCallee() { + return GetStats(callee_->pc()); + } + + protected: + static rtc::scoped_refptr GetStats( + PeerConnectionInterface* pc) { + rtc::scoped_refptr stats_obtainer = + RTCStatsObtainer::Create(); + pc->GetStats(stats_obtainer); + EXPECT_TRUE_WAIT(stats_obtainer->report(), kGetStatsTimeoutMs); + return stats_obtainer->report(); + } + + // These objects use each other and must be constructed/destroyed in this + // order. Relationship: + // |physical_socket_server_| <- |virtual_socket_server_| <- |network_thread_| + rtc::PhysicalSocketServer physical_socket_server_; + rtc::VirtualSocketServer virtual_socket_server_; + rtc::Thread network_thread_; + rtc::Thread worker_thread_; + rtc::scoped_refptr caller_; + rtc::scoped_refptr callee_; +}; + +class RTCStatsVerifier { + public: + RTCStatsVerifier(const RTCStatsReport* report, const RTCStats* stats) + : report_(report), stats_(stats), all_tests_successful_(true) { + RTC_CHECK(report_); + RTC_CHECK(stats_); + for (const RTCStatsMemberInterface* member : stats_->Members()) { + untested_members_.insert(member); + } + } + + void MarkMemberTested( + const RTCStatsMemberInterface& member, bool test_successful) { + untested_members_.erase(&member); + all_tests_successful_ &= test_successful; + } + + void TestMemberIsDefined(const RTCStatsMemberInterface& member) { + EXPECT_TRUE(member.is_defined()) << + stats_->type() << "." << member.name() << "[" << stats_->id() << + "] was undefined."; + MarkMemberTested(member, member.is_defined()); + } + + void TestMemberIsUndefined(const RTCStatsMemberInterface& member) { + EXPECT_FALSE(member.is_defined()) << + stats_->type() << "." << member.name() << "[" << stats_->id() << + "] was defined (" << member.ValueToString() << ")."; + MarkMemberTested(member, !member.is_defined()); + } + + void TestMemberIsIDReference( + const RTCStatsMemberInterface& member, + const char* expected_type) { + TestMemberIsIDReference(member, expected_type, false); + } + + void TestMemberIsOptionalIDReference( + const RTCStatsMemberInterface& member, + const char* expected_type) { + TestMemberIsIDReference(member, expected_type, true); + } + + bool ExpectAllMembersSuccessfullyTested() { + if (untested_members_.empty()) + return all_tests_successful_; + for (const RTCStatsMemberInterface* member : untested_members_) { + EXPECT_TRUE(false) << + stats_->type() << "." << member->name() << "[" << stats_->id() << + "] was not tested."; + } + return false; + } + + private: + void TestMemberIsIDReference( + const RTCStatsMemberInterface& member, + const char* expected_type, + bool optional) { + if (optional && !member.is_defined()) { + MarkMemberTested(member, true); + return; + } + bool valid_reference = false; + if (member.is_defined()) { + if (member.type() == RTCStatsMemberInterface::kString) { + // A single ID. + const RTCStatsMember& id = + member.cast_to>(); + const RTCStats* referenced_stats = report_->Get(*id); + valid_reference = + referenced_stats && referenced_stats->type() == expected_type; + } else if (member.type() == RTCStatsMemberInterface::kSequenceString) { + // A vector of IDs. + valid_reference = true; + const RTCStatsMember>& ids = + member.cast_to>>(); + for (const std::string id : *ids) { + const RTCStats* referenced_stats = report_->Get(id); + if (!referenced_stats || referenced_stats->type() != expected_type) { + valid_reference = false; + break; + } + } + } + } + EXPECT_TRUE(valid_reference) << + stats_->type() << "." << member.name() << " is not a reference to an " << + "existing dictionary of type " << expected_type << " (" << + member.ValueToString() << ")."; + MarkMemberTested(member, valid_reference); + } + + rtc::scoped_refptr report_; + const RTCStats* stats_; + std::set untested_members_; + bool all_tests_successful_; +}; + +class RTCStatsReportVerifier { + public: + static std::set StatsTypes() { + std::set stats_types; + stats_types.insert(RTCCertificateStats::kType); + stats_types.insert(RTCCodecStats::kType); + stats_types.insert(RTCDataChannelStats::kType); + stats_types.insert(RTCIceCandidatePairStats::kType); + stats_types.insert(RTCLocalIceCandidateStats::kType); + stats_types.insert(RTCRemoteIceCandidateStats::kType); + stats_types.insert(RTCMediaStreamStats::kType); + stats_types.insert(RTCMediaStreamTrackStats::kType); + stats_types.insert(RTCPeerConnectionStats::kType); + stats_types.insert(RTCInboundRTPStreamStats::kType); + stats_types.insert(RTCOutboundRTPStreamStats::kType); + stats_types.insert(RTCTransportStats::kType); + return stats_types; + } + + explicit RTCStatsReportVerifier(const RTCStatsReport* report) + : report_(report) { + } + + void VerifyReport() { + std::set missing_stats = StatsTypes(); + bool verify_successful = true; + for (const RTCStats& stats : *report_) { + missing_stats.erase(stats.type()); + if (stats.type() == RTCCertificateStats::kType) { + verify_successful &= VerifyRTCCertificateStats( + stats.cast_to()); + } else if (stats.type() == RTCCodecStats::kType) { + verify_successful &= VerifyRTCCodecStats( + stats.cast_to()); + } else if (stats.type() == RTCDataChannelStats::kType) { + verify_successful &= VerifyRTCDataChannelStats( + stats.cast_to()); + } else if (stats.type() == RTCIceCandidatePairStats::kType) { + verify_successful &= VerifyRTCIceCandidatePairStats( + stats.cast_to()); + } else if (stats.type() == RTCLocalIceCandidateStats::kType) { + verify_successful &= VerifyRTCLocalIceCandidateStats( + stats.cast_to()); + } else if (stats.type() == RTCRemoteIceCandidateStats::kType) { + verify_successful &= VerifyRTCRemoteIceCandidateStats( + stats.cast_to()); + } else if (stats.type() == RTCMediaStreamStats::kType) { + verify_successful &= VerifyRTCMediaStreamStats( + stats.cast_to()); + } else if (stats.type() == RTCMediaStreamTrackStats::kType) { + verify_successful &= VerifyRTCMediaStreamTrackStats( + stats.cast_to()); + } else if (stats.type() == RTCPeerConnectionStats::kType) { + verify_successful &= VerifyRTCPeerConnectionStats( + stats.cast_to()); + } else if (stats.type() == RTCInboundRTPStreamStats::kType) { + verify_successful &= VerifyRTCInboundRTPStreamStats( + stats.cast_to()); + } else if (stats.type() == RTCOutboundRTPStreamStats::kType) { + verify_successful &= VerifyRTCOutboundRTPStreamStats( + stats.cast_to()); + } else if (stats.type() == RTCTransportStats::kType) { + verify_successful &= VerifyRTCTransportStats( + stats.cast_to()); + } else { + EXPECT_TRUE(false) << "Unrecognized stats type: " << stats.type(); + verify_successful = false; + } + } + if (!missing_stats.empty()) { + verify_successful = false; + for (const char* missing : missing_stats) { + EXPECT_TRUE(false) << "Missing expected stats type: " << missing; + } + } + EXPECT_TRUE(verify_successful) << + "One or more problems with the stats. This is the report:\n" << + report_->ToString(); + } + + bool VerifyRTCCertificateStats( + const RTCCertificateStats& certificate) { + RTCStatsVerifier verifier(report_, &certificate); + verifier.TestMemberIsDefined(certificate.fingerprint); + verifier.TestMemberIsDefined(certificate.fingerprint_algorithm); + verifier.TestMemberIsDefined(certificate.base64_certificate); + verifier.TestMemberIsOptionalIDReference( + certificate.issuer_certificate_id, RTCCertificateStats::kType); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCCodecStats( + const RTCCodecStats& codec) { + RTCStatsVerifier verifier(report_, &codec); + verifier.TestMemberIsDefined(codec.payload_type); + verifier.TestMemberIsDefined(codec.codec); + verifier.TestMemberIsDefined(codec.clock_rate); + verifier.TestMemberIsUndefined(codec.channels); + verifier.TestMemberIsUndefined(codec.parameters); + verifier.TestMemberIsUndefined(codec.implementation); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCDataChannelStats( + const RTCDataChannelStats& data_channel) { + RTCStatsVerifier verifier(report_, &data_channel); + verifier.TestMemberIsDefined(data_channel.label); + verifier.TestMemberIsDefined(data_channel.protocol); + verifier.TestMemberIsDefined(data_channel.datachannelid); + verifier.TestMemberIsDefined(data_channel.state); + verifier.TestMemberIsDefined(data_channel.messages_sent); + verifier.TestMemberIsDefined(data_channel.bytes_sent); + verifier.TestMemberIsDefined(data_channel.messages_received); + verifier.TestMemberIsDefined(data_channel.bytes_received); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCIceCandidatePairStats( + const RTCIceCandidatePairStats& candidate_pair) { + RTCStatsVerifier verifier(report_, &candidate_pair); + verifier.TestMemberIsUndefined(candidate_pair.transport_id); + verifier.TestMemberIsIDReference( + candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType); + verifier.TestMemberIsIDReference( + candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType); + verifier.TestMemberIsUndefined(candidate_pair.state); + verifier.TestMemberIsUndefined(candidate_pair.priority); + verifier.TestMemberIsUndefined(candidate_pair.nominated); + verifier.TestMemberIsDefined(candidate_pair.writable); + verifier.TestMemberIsUndefined(candidate_pair.readable); + verifier.TestMemberIsDefined(candidate_pair.bytes_sent); + verifier.TestMemberIsDefined(candidate_pair.bytes_received); + verifier.TestMemberIsUndefined(candidate_pair.total_rtt); + verifier.TestMemberIsDefined(candidate_pair.current_rtt); + verifier.TestMemberIsUndefined(candidate_pair.available_outgoing_bitrate); + verifier.TestMemberIsUndefined(candidate_pair.available_incoming_bitrate); + verifier.TestMemberIsUndefined(candidate_pair.requests_received); + verifier.TestMemberIsDefined(candidate_pair.requests_sent); + verifier.TestMemberIsDefined(candidate_pair.responses_received); + verifier.TestMemberIsDefined(candidate_pair.responses_sent); + verifier.TestMemberIsUndefined(candidate_pair.retransmissions_received); + verifier.TestMemberIsUndefined(candidate_pair.retransmissions_sent); + verifier.TestMemberIsUndefined(candidate_pair.consent_requests_received); + verifier.TestMemberIsUndefined(candidate_pair.consent_requests_sent); + verifier.TestMemberIsUndefined(candidate_pair.consent_responses_received); + verifier.TestMemberIsUndefined(candidate_pair.consent_responses_sent); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCIceCandidateStats( + const RTCIceCandidateStats& candidate) { + RTCStatsVerifier verifier(report_, &candidate); + verifier.TestMemberIsDefined(candidate.ip); + verifier.TestMemberIsDefined(candidate.port); + verifier.TestMemberIsDefined(candidate.protocol); + verifier.TestMemberIsDefined(candidate.candidate_type); + verifier.TestMemberIsDefined(candidate.priority); + verifier.TestMemberIsUndefined(candidate.url); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCLocalIceCandidateStats( + const RTCLocalIceCandidateStats& local_candidate) { + return VerifyRTCIceCandidateStats(local_candidate); + } + + bool VerifyRTCRemoteIceCandidateStats( + const RTCRemoteIceCandidateStats& remote_candidate) { + return VerifyRTCIceCandidateStats(remote_candidate); + } + + bool VerifyRTCMediaStreamStats( + const RTCMediaStreamStats& media_stream) { + RTCStatsVerifier verifier(report_, &media_stream); + verifier.TestMemberIsDefined(media_stream.stream_identifier); + verifier.TestMemberIsIDReference( + media_stream.track_ids, RTCMediaStreamTrackStats::kType); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCMediaStreamTrackStats( + const RTCMediaStreamTrackStats& media_stream_track) { + RTCStatsVerifier verifier(report_, &media_stream_track); + verifier.TestMemberIsDefined(media_stream_track.track_identifier); + verifier.TestMemberIsDefined(media_stream_track.remote_source); + verifier.TestMemberIsDefined(media_stream_track.ended); + verifier.TestMemberIsDefined(media_stream_track.detached); + verifier.TestMemberIsUndefined(media_stream_track.ssrc_ids); + // Video or audio media stream track? + if (media_stream_track.frame_width.is_defined()) { + // Video-only members + verifier.TestMemberIsDefined(media_stream_track.frame_width); + verifier.TestMemberIsDefined(media_stream_track.frame_height); + verifier.TestMemberIsUndefined(media_stream_track.frames_per_second); + verifier.TestMemberIsUndefined(media_stream_track.frames_sent); + verifier.TestMemberIsUndefined(media_stream_track.frames_received); + verifier.TestMemberIsUndefined(media_stream_track.frames_decoded); + verifier.TestMemberIsUndefined(media_stream_track.frames_dropped); + verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted); + verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost); + verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost); + // Audio-only members should be undefined + verifier.TestMemberIsUndefined(media_stream_track.audio_level); + verifier.TestMemberIsUndefined(media_stream_track.echo_return_loss); + verifier.TestMemberIsUndefined( + media_stream_track.echo_return_loss_enhancement); + } else { + // Video-only members should be undefined + verifier.TestMemberIsUndefined(media_stream_track.frame_width); + verifier.TestMemberIsUndefined(media_stream_track.frame_height); + verifier.TestMemberIsUndefined(media_stream_track.frames_per_second); + verifier.TestMemberIsUndefined(media_stream_track.frames_sent); + verifier.TestMemberIsUndefined(media_stream_track.frames_received); + verifier.TestMemberIsUndefined(media_stream_track.frames_decoded); + verifier.TestMemberIsUndefined(media_stream_track.frames_dropped); + verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted); + verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost); + verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost); + // Audio-only members + // TODO(hbos): Why are the audio track missing |audio_level|, + // |echo_return_loss| and |echo_return_loss_enhancement|? Is this a real + // problem or does it have to do with testing and not using real devices? + // crbug.com/627816 + verifier.MarkMemberTested(media_stream_track.audio_level, true); + verifier.MarkMemberTested(media_stream_track.echo_return_loss, true); + verifier.MarkMemberTested( + media_stream_track.echo_return_loss_enhancement, true); + } + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCPeerConnectionStats( + const RTCPeerConnectionStats& peer_connection) { + RTCStatsVerifier verifier(report_, &peer_connection); + verifier.TestMemberIsDefined(peer_connection.data_channels_opened); + verifier.TestMemberIsDefined(peer_connection.data_channels_closed); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + void VerifyRTCRTPStreamStats( + const RTCRTPStreamStats& stream, RTCStatsVerifier* verifier) { + verifier->TestMemberIsDefined(stream.ssrc); + verifier->TestMemberIsUndefined(stream.associate_stats_id); + verifier->TestMemberIsDefined(stream.is_remote); + verifier->TestMemberIsDefined(stream.media_type); + verifier->TestMemberIsUndefined(stream.media_track_id); + verifier->TestMemberIsIDReference( + stream.transport_id, RTCTransportStats::kType); + verifier->TestMemberIsDefined(stream.codec_id); + if (stream.media_type.is_defined() && *stream.media_type == "video") { + verifier->TestMemberIsDefined(stream.fir_count); + verifier->TestMemberIsDefined(stream.pli_count); + verifier->TestMemberIsDefined(stream.nack_count); + } else { + verifier->TestMemberIsUndefined(stream.fir_count); + verifier->TestMemberIsUndefined(stream.pli_count); + verifier->TestMemberIsUndefined(stream.nack_count); + } + verifier->TestMemberIsUndefined(stream.sli_count); + } + + bool VerifyRTCInboundRTPStreamStats( + const RTCInboundRTPStreamStats& inbound_stream) { + RTCStatsVerifier verifier(report_, &inbound_stream); + VerifyRTCRTPStreamStats(inbound_stream, &verifier); + verifier.TestMemberIsDefined(inbound_stream.packets_received); + verifier.TestMemberIsDefined(inbound_stream.bytes_received); + verifier.TestMemberIsUndefined(inbound_stream.packets_lost); + if (inbound_stream.media_type.is_defined() && + *inbound_stream.media_type == "video") { + verifier.TestMemberIsUndefined(inbound_stream.jitter); + } else { + verifier.TestMemberIsDefined(inbound_stream.jitter); + } + verifier.TestMemberIsDefined(inbound_stream.fraction_lost); + verifier.TestMemberIsUndefined(inbound_stream.packets_discarded); + verifier.TestMemberIsUndefined(inbound_stream.packets_repaired); + verifier.TestMemberIsUndefined(inbound_stream.burst_packets_lost); + verifier.TestMemberIsUndefined(inbound_stream.burst_packets_discarded); + verifier.TestMemberIsUndefined(inbound_stream.burst_loss_count); + verifier.TestMemberIsUndefined(inbound_stream.burst_discard_count); + verifier.TestMemberIsUndefined(inbound_stream.burst_loss_rate); + verifier.TestMemberIsUndefined(inbound_stream.burst_discard_rate); + verifier.TestMemberIsUndefined(inbound_stream.gap_loss_rate); + verifier.TestMemberIsUndefined(inbound_stream.gap_discard_rate); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCOutboundRTPStreamStats( + const RTCOutboundRTPStreamStats& outbound_stream) { + RTCStatsVerifier verifier(report_, &outbound_stream); + VerifyRTCRTPStreamStats(outbound_stream, &verifier); + verifier.TestMemberIsDefined(outbound_stream.packets_sent); + verifier.TestMemberIsDefined(outbound_stream.bytes_sent); + verifier.TestMemberIsUndefined(outbound_stream.target_bitrate); + verifier.TestMemberIsDefined(outbound_stream.round_trip_time); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + bool VerifyRTCTransportStats( + const RTCTransportStats& transport) { + RTCStatsVerifier verifier(report_, &transport); + verifier.TestMemberIsDefined(transport.bytes_sent); + verifier.TestMemberIsDefined(transport.bytes_received); + verifier.TestMemberIsOptionalIDReference( + transport.rtcp_transport_stats_id, RTCTransportStats::kType); + verifier.TestMemberIsDefined(transport.active_connection); + verifier.TestMemberIsDefined(transport.selected_candidate_pair_id); + verifier.TestMemberIsDefined(transport.local_certificate_id); + verifier.TestMemberIsDefined(transport.remote_certificate_id); + return verifier.ExpectAllMembersSuccessfullyTested(); + } + + private: + rtc::scoped_refptr report_; +}; + +TEST_F(RTCStatsIntegrationTest, GetStatsFromCaller) { + StartCall(); + + rtc::scoped_refptr report = GetStatsFromCaller(); + RTCStatsReportVerifier(report.get()).VerifyReport(); +} + +TEST_F(RTCStatsIntegrationTest, GetStatsFromCallee) { + StartCall(); + + rtc::scoped_refptr report = GetStatsFromCallee(); + RTCStatsReportVerifier(report.get()).VerifyReport(); +} + +} // namespace + +} // namespace webrtc diff --git a/webrtc/api/rtcstatscollector_unittest.cc b/webrtc/api/rtcstatscollector_unittest.cc index f27eb32980..e4c3118367 100644 --- a/webrtc/api/rtcstatscollector_unittest.cc +++ b/webrtc/api/rtcstatscollector_unittest.cc @@ -24,6 +24,7 @@ #include "webrtc/api/test/mock_datachannel.h" #include "webrtc/api/test/mock_peerconnection.h" #include "webrtc/api/test/mock_webrtcsession.h" +#include "webrtc/api/test/rtcstatsobtainer.h" #include "webrtc/base/checks.h" #include "webrtc/base/fakeclock.h" #include "webrtc/base/fakesslidentity.h" @@ -472,37 +473,6 @@ class FakeRTCStatsCollector : public RTCStatsCollector, int produced_on_network_thread_ = 0; }; -class StatsCallback : public RTCStatsCollectorCallback { - public: - static rtc::scoped_refptr Create( - rtc::scoped_refptr* report_ptr = nullptr) { - return rtc::scoped_refptr( - new rtc::RefCountedObject(report_ptr)); - } - - void OnStatsDelivered( - const rtc::scoped_refptr& report) override { - EXPECT_TRUE(thread_checker_.CalledOnValidThread()); - report_ = report; - if (report_ptr_) - *report_ptr_ = report_; - } - - rtc::scoped_refptr report() const { - EXPECT_TRUE(thread_checker_.CalledOnValidThread()); - return report_; - } - - protected: - explicit StatsCallback(rtc::scoped_refptr* report_ptr) - : report_ptr_(report_ptr) {} - - private: - rtc::ThreadChecker thread_checker_; - rtc::scoped_refptr report_; - rtc::scoped_refptr* report_ptr_; -}; - class RTCStatsCollectorTest : public testing::Test { public: RTCStatsCollectorTest() @@ -512,7 +482,7 @@ class RTCStatsCollectorTest : public testing::Test { } rtc::scoped_refptr GetStatsReport() { - rtc::scoped_refptr callback = StatsCallback::Create(); + rtc::scoped_refptr callback = RTCStatsObtainer::Create(); collector_->GetStatsReport(callback); EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs); int64_t after = rtc::TimeUTCMicros(); @@ -723,7 +693,7 @@ class RTCStatsCollectorTest : public testing::Test { TEST_F(RTCStatsCollectorTest, SingleCallback) { rtc::scoped_refptr result; - collector_->GetStatsReport(StatsCallback::Create(&result)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&result)); EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs); } @@ -731,9 +701,9 @@ TEST_F(RTCStatsCollectorTest, MultipleCallbacks) { rtc::scoped_refptr a; rtc::scoped_refptr b; rtc::scoped_refptr c; - collector_->GetStatsReport(StatsCallback::Create(&a)); - collector_->GetStatsReport(StatsCallback::Create(&b)); - collector_->GetStatsReport(StatsCallback::Create(&c)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&a)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&b)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&c)); EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); @@ -761,11 +731,11 @@ TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) { rtc::scoped_refptr a; rtc::scoped_refptr b; rtc::scoped_refptr c; - collector_->GetStatsReport(StatsCallback::Create(&a)); - collector_->GetStatsReport(StatsCallback::Create(&b)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&a)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&b)); // Cache is invalidated after 50 ms. test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51)); - collector_->GetStatsReport(StatsCallback::Create(&c)); + collector_->GetStatsReport(RTCStatsObtainer::Create(&c)); EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); diff --git a/webrtc/api/test/peerconnectiontestwrapper.h b/webrtc/api/test/peerconnectiontestwrapper.h index 3cdac492f1..6433e8fb05 100644 --- a/webrtc/api/test/peerconnectiontestwrapper.h +++ b/webrtc/api/test/peerconnectiontestwrapper.h @@ -43,6 +43,8 @@ class PeerConnectionTestWrapper const webrtc::MediaConstraintsInterface* constraints, const webrtc::PeerConnectionInterface::RTCConfiguration& config); + webrtc::PeerConnectionInterface* pc() { return peer_connection_.get(); } + rtc::scoped_refptr CreateDataChannel( const std::string& label, const webrtc::DataChannelInit& init); diff --git a/webrtc/api/test/rtcstatsobtainer.h b/webrtc/api/test/rtcstatsobtainer.h new file mode 100644 index 0000000000..aeae87cddd --- /dev/null +++ b/webrtc/api/test/rtcstatsobtainer.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016 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 WEBRTC_API_TEST_RTCSTATSOBTAINER_H_ +#define WEBRTC_API_TEST_RTCSTATSOBTAINER_H_ + +#include "webrtc/api/stats/rtcstatsreport.h" +#include "webrtc/base/gunit.h" + +namespace webrtc { + +class RTCStatsObtainer : public RTCStatsCollectorCallback { + public: + static rtc::scoped_refptr Create( + rtc::scoped_refptr* report_ptr = nullptr) { + return rtc::scoped_refptr( + new rtc::RefCountedObject(report_ptr)); + } + + void OnStatsDelivered( + const rtc::scoped_refptr& report) override { + EXPECT_TRUE(thread_checker_.CalledOnValidThread()); + report_ = report; + if (report_ptr_) + *report_ptr_ = report_; + } + + rtc::scoped_refptr report() const { + EXPECT_TRUE(thread_checker_.CalledOnValidThread()); + return report_; + } + + protected: + explicit RTCStatsObtainer( + rtc::scoped_refptr* report_ptr) + : report_ptr_(report_ptr) {} + + private: + rtc::ThreadChecker thread_checker_; + rtc::scoped_refptr report_; + rtc::scoped_refptr* report_ptr_; +}; + +} // namespace webrtc + +#endif // WEBRTC_API_TEST_RTCSTATSOBTAINER_H_