From db346a7cbe511641e11307dc4cbbc8fc0c323845 Mon Sep 17 00:00:00 2001 From: hbos Date: Tue, 29 Nov 2016 01:57:01 -0800 Subject: [PATCH] RTCStatsIntegrationTest added. This is an integration test using peerconnectiontestwrapper.h to set up and end to end test using a real PeerConnection implementation. These tests will complement rtcstatscollector_unittest.cc which collects all stats using mocks. The integration test is set up so that all stats types are returned by GetStats and verifies that expected dictionary members are defined. The test could in the future be updated to include sanity checks for the values of members. There is a sanity check that references to other stats dictionaries yield existing stats of the appropriate type, but other than that members are only tested for if they are defined not. StatsCallback of rtcstatscollector_unittest.cc is moved so that it can be reused and renamed to RTCStatsObtainer. TODO: Audio stream track stats members are missing in the test. Find out if this is because of a real problem or because of testing without real devices. Do this before closing crbug.com/627816. BUG=chromium:627816 Review-Url: https://codereview.webrtc.org/2521663002 Cr-Commit-Position: refs/heads/master@{#15287} --- webrtc/api/BUILD.gn | 2 + webrtc/api/rtcstats_integrationtest.cc | 537 ++++++++++++++++++++ webrtc/api/rtcstatscollector_unittest.cc | 48 +- webrtc/api/test/peerconnectiontestwrapper.h | 2 + webrtc/api/test/rtcstatsobtainer.h | 53 ++ 5 files changed, 603 insertions(+), 39 deletions(-) create mode 100644 webrtc/api/rtcstats_integrationtest.cc create mode 100644 webrtc/api/test/rtcstatsobtainer.h 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_