blob: 808668b35c88fe26ccbb30fe7c05ecda7e1cd96d [file] [log] [blame]
hbosd565b732016-08-30 14:04:35 -07001/*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
hbos74e1a4f2016-09-15 23:33:01 -070011#include "webrtc/api/rtcstatscollector.h"
hbosd565b732016-08-30 14:04:35 -070012
13#include <memory>
hbosda389e32016-10-25 10:55:08 -070014#include <ostream>
hbosd565b732016-08-30 14:04:35 -070015#include <string>
16#include <vector>
17
18#include "webrtc/api/jsepsessiondescription.h"
hbos74e1a4f2016-09-15 23:33:01 -070019#include "webrtc/api/stats/rtcstats_objects.h"
20#include "webrtc/api/stats/rtcstatsreport.h"
hbosd565b732016-08-30 14:04:35 -070021#include "webrtc/api/test/mock_datachannel.h"
22#include "webrtc/api/test/mock_peerconnection.h"
23#include "webrtc/api/test/mock_webrtcsession.h"
24#include "webrtc/base/checks.h"
hbos0e6758d2016-08-31 07:57:36 -070025#include "webrtc/base/fakeclock.h"
hbos6ab97ce2016-10-03 14:16:56 -070026#include "webrtc/base/fakesslidentity.h"
hbosd565b732016-08-30 14:04:35 -070027#include "webrtc/base/gunit.h"
28#include "webrtc/base/logging.h"
hbosab9f6e42016-10-07 02:18:47 -070029#include "webrtc/base/socketaddress.h"
hbosc82f2e12016-09-05 01:36:50 -070030#include "webrtc/base/thread_checker.h"
hbos0e6758d2016-08-31 07:57:36 -070031#include "webrtc/base/timedelta.h"
32#include "webrtc/base/timeutils.h"
skvlad11a9cbf2016-10-07 11:53:05 -070033#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
hbosd565b732016-08-30 14:04:35 -070034#include "webrtc/media/base/fakemediaengine.h"
hbos6ded1902016-11-01 01:50:46 -070035#include "webrtc/media/base/test/mock_mediachannel.h"
hbos2fa7c672016-10-24 04:00:05 -070036#include "webrtc/p2p/base/p2pconstants.h"
hbosab9f6e42016-10-07 02:18:47 -070037#include "webrtc/p2p/base/port.h"
hbosd565b732016-08-30 14:04:35 -070038
hbos6ab97ce2016-10-03 14:16:56 -070039using testing::_;
40using testing::Invoke;
hbosd565b732016-08-30 14:04:35 -070041using testing::Return;
hbos6ded1902016-11-01 01:50:46 -070042using testing::ReturnNull;
hbosd565b732016-08-30 14:04:35 -070043using testing::ReturnRef;
hbos6ded1902016-11-01 01:50:46 -070044using testing::SetArgPointee;
hbosd565b732016-08-30 14:04:35 -070045
46namespace webrtc {
47
hbosda389e32016-10-25 10:55:08 -070048// These are used by gtest code, such as if |EXPECT_EQ| fails.
49void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
50 *os << stats.ToString();
51}
52
53void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
54 *os << stats.ToString();
55}
56
57void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
58 *os << stats.ToString();
59}
60
61void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
62 *os << stats.ToString();
63}
64
65void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
66 *os << stats.ToString();
67}
68
69void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
70 *os << stats.ToString();
71}
72
hboseeafe942016-11-01 03:00:17 -070073void PrintTo(const RTCInboundRTPStreamStats& stats, ::std::ostream* os) {
74 *os << stats.ToString();
75}
76
hbos6ded1902016-11-01 01:50:46 -070077void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) {
78 *os << stats.ToString();
79}
80
hbosda389e32016-10-25 10:55:08 -070081void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
82 *os << stats.ToString();
83}
84
hbosc82f2e12016-09-05 01:36:50 -070085namespace {
86
87const int64_t kGetStatsReportTimeoutMs = 1000;
88
hbos6ab97ce2016-10-03 14:16:56 -070089struct CertificateInfo {
90 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
91 std::vector<std::string> ders;
92 std::vector<std::string> pems;
93 std::vector<std::string> fingerprints;
94};
95
96std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
97 const std::vector<std::string>& ders) {
98 RTC_CHECK(!ders.empty());
99 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
100 info->ders = ders;
101 for (const std::string& der : ders) {
102 info->pems.push_back(rtc::SSLIdentity::DerToPem(
103 "CERTIFICATE",
104 reinterpret_cast<const unsigned char*>(der.c_str()),
105 der.length()));
106 }
107 info->certificate =
108 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
109 new rtc::FakeSSLIdentity(rtc::FakeSSLCertificate(info->pems))));
110 // Strip header/footer and newline characters of PEM strings.
111 for (size_t i = 0; i < info->pems.size(); ++i) {
112 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27,
113 "", 0, &info->pems[i]);
114 rtc::replace_substrs("-----END CERTIFICATE-----", 25,
115 "", 0, &info->pems[i]);
116 rtc::replace_substrs("\n", 1,
117 "", 0, &info->pems[i]);
118 }
119 // Fingerprint of leaf certificate.
120 std::unique_ptr<rtc::SSLFingerprint> fp(
121 rtc::SSLFingerprint::Create("sha-1",
122 &info->certificate->ssl_certificate()));
123 EXPECT_TRUE(fp);
124 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
125 // Fingerprints of the rest of the chain.
126 std::unique_ptr<rtc::SSLCertChain> chain =
127 info->certificate->ssl_certificate().GetChain();
128 if (chain) {
129 for (size_t i = 0; i < chain->GetSize(); i++) {
130 fp.reset(rtc::SSLFingerprint::Create("sha-1", &chain->Get(i)));
131 EXPECT_TRUE(fp);
132 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
133 }
134 }
135 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
136 return info;
137}
138
hbosab9f6e42016-10-07 02:18:47 -0700139std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
140 const std::string& hostname,
141 int port,
142 const std::string& protocol,
143 const std::string& candidate_type,
144 uint32_t priority) {
145 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
146 candidate->set_address(rtc::SocketAddress(hostname, port));
147 candidate->set_protocol(protocol);
148 candidate->set_type(candidate_type);
149 candidate->set_priority(priority);
150 return candidate;
151}
152
hbosc82f2e12016-09-05 01:36:50 -0700153class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver {
hbosd565b732016-08-30 14:04:35 -0700154 public:
hbosc82f2e12016-09-05 01:36:50 -0700155 RTCStatsCollectorTestHelper()
hbosd565b732016-08-30 14:04:35 -0700156 : worker_thread_(rtc::Thread::Current()),
157 network_thread_(rtc::Thread::Current()),
hbos6ded1902016-11-01 01:50:46 -0700158 media_engine_(new cricket::FakeMediaEngine()),
skvlad11a9cbf2016-10-07 11:53:05 -0700159 channel_manager_(
hbos6ded1902016-11-01 01:50:46 -0700160 new cricket::ChannelManager(media_engine_,
skvlad11a9cbf2016-10-07 11:53:05 -0700161 worker_thread_,
162 network_thread_)),
hbosd565b732016-08-30 14:04:35 -0700163 media_controller_(
164 MediaControllerInterface::Create(cricket::MediaConfig(),
165 worker_thread_,
skvlad11a9cbf2016-10-07 11:53:05 -0700166 channel_manager_.get(),
167 &event_log_)),
hbosd565b732016-08-30 14:04:35 -0700168 session_(media_controller_.get()),
169 pc_() {
hbos6ab97ce2016-10-03 14:16:56 -0700170 // Default return values for mocks.
hbosd565b732016-08-30 14:04:35 -0700171 EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_));
172 EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly(
173 ReturnRef(data_channels_));
hbos6ded1902016-11-01 01:50:46 -0700174 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
175 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
hbos6ab97ce2016-10-03 14:16:56 -0700176 EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false));
hbosab9f6e42016-10-07 02:18:47 -0700177 EXPECT_CALL(session_, GetLocalCertificate(_, _)).WillRepeatedly(
178 Return(false));
179 EXPECT_CALL(session_, GetRemoteSSLCertificate_ReturnsRawPointer(_))
180 .WillRepeatedly(Return(nullptr));
hbosd565b732016-08-30 14:04:35 -0700181 }
182
hbosfdafab82016-09-14 06:02:13 -0700183 rtc::ScopedFakeClock& fake_clock() { return fake_clock_; }
hbos6ded1902016-11-01 01:50:46 -0700184 rtc::Thread* worker_thread() { return worker_thread_; }
185 rtc::Thread* network_thread() { return network_thread_; }
186 cricket::FakeMediaEngine* media_engine() { return media_engine_; }
hbosd565b732016-08-30 14:04:35 -0700187 MockWebRtcSession& session() { return session_; }
188 MockPeerConnection& pc() { return pc_; }
189 std::vector<rtc::scoped_refptr<DataChannel>>& data_channels() {
190 return data_channels_;
191 }
192
193 // SetSessionDescriptionObserver overrides.
194 void OnSuccess() override {}
195 void OnFailure(const std::string& error) override {
196 RTC_NOTREACHED() << error;
197 }
198
199 private:
hbosfdafab82016-09-14 06:02:13 -0700200 rtc::ScopedFakeClock fake_clock_;
skvlad11a9cbf2016-10-07 11:53:05 -0700201 webrtc::RtcEventLogNullImpl event_log_;
hbosd565b732016-08-30 14:04:35 -0700202 rtc::Thread* const worker_thread_;
203 rtc::Thread* const network_thread_;
hbos6ded1902016-11-01 01:50:46 -0700204 cricket::FakeMediaEngine* media_engine_;
hbosd565b732016-08-30 14:04:35 -0700205 std::unique_ptr<cricket::ChannelManager> channel_manager_;
206 std::unique_ptr<webrtc::MediaControllerInterface> media_controller_;
207 MockWebRtcSession session_;
208 MockPeerConnection pc_;
209
210 std::vector<rtc::scoped_refptr<DataChannel>> data_channels_;
211};
212
hbosc82f2e12016-09-05 01:36:50 -0700213class RTCTestStats : public RTCStats {
hbosd565b732016-08-30 14:04:35 -0700214 public:
hbosfc5e0502016-10-06 02:06:10 -0700215 WEBRTC_RTCSTATS_DECL();
216
hbosc82f2e12016-09-05 01:36:50 -0700217 RTCTestStats(const std::string& id, int64_t timestamp_us)
218 : RTCStats(id, timestamp_us),
219 dummy_stat("dummyStat") {}
220
hbosc82f2e12016-09-05 01:36:50 -0700221 RTCStatsMember<int32_t> dummy_stat;
222};
223
hbosfc5e0502016-10-06 02:06:10 -0700224WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats",
225 &dummy_stat);
hbosc82f2e12016-09-05 01:36:50 -0700226
227// Overrides the stats collection to verify thread usage and that the resulting
228// partial reports are merged.
229class FakeRTCStatsCollector : public RTCStatsCollector,
230 public RTCStatsCollectorCallback {
231 public:
232 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
233 PeerConnection* pc,
234 int64_t cache_lifetime_us) {
235 return rtc::scoped_refptr<FakeRTCStatsCollector>(
236 new rtc::RefCountedObject<FakeRTCStatsCollector>(
237 pc, cache_lifetime_us));
238 }
239
240 // RTCStatsCollectorCallback implementation.
241 void OnStatsDelivered(
242 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
243 EXPECT_TRUE(signaling_thread_->IsCurrent());
244 rtc::CritScope cs(&lock_);
245 delivered_report_ = report;
246 }
247
248 void VerifyThreadUsageAndResultsMerging() {
249 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
250 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
251 }
252
253 bool HasVerifiedResults() {
254 EXPECT_TRUE(signaling_thread_->IsCurrent());
255 rtc::CritScope cs(&lock_);
256 if (!delivered_report_)
257 return false;
258 EXPECT_EQ(produced_on_signaling_thread_, 1);
259 EXPECT_EQ(produced_on_worker_thread_, 1);
260 EXPECT_EQ(produced_on_network_thread_, 1);
261
262 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
263 EXPECT_TRUE(delivered_report_->Get("WorkerThreadStats"));
264 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
265
266 produced_on_signaling_thread_ = 0;
267 produced_on_worker_thread_ = 0;
268 produced_on_network_thread_ = 0;
269 delivered_report_ = nullptr;
270 return true;
hbosd565b732016-08-30 14:04:35 -0700271 }
272
273 protected:
hbosc82f2e12016-09-05 01:36:50 -0700274 FakeRTCStatsCollector(
275 PeerConnection* pc,
276 int64_t cache_lifetime)
277 : RTCStatsCollector(pc, cache_lifetime),
278 signaling_thread_(pc->session()->signaling_thread()),
279 worker_thread_(pc->session()->worker_thread()),
280 network_thread_(pc->session()->network_thread()) {
281 }
282
283 void ProducePartialResultsOnSignalingThread(int64_t timestamp_us) override {
284 EXPECT_TRUE(signaling_thread_->IsCurrent());
285 {
286 rtc::CritScope cs(&lock_);
287 EXPECT_FALSE(delivered_report_);
288 ++produced_on_signaling_thread_;
289 }
290
291 rtc::scoped_refptr<RTCStatsReport> signaling_report =
hbos6ded1902016-11-01 01:50:46 -0700292 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700293 signaling_report->AddStats(std::unique_ptr<const RTCStats>(
294 new RTCTestStats("SignalingThreadStats", timestamp_us)));
295 AddPartialResults(signaling_report);
296 }
297 void ProducePartialResultsOnWorkerThread(int64_t timestamp_us) override {
298 EXPECT_TRUE(worker_thread_->IsCurrent());
299 {
300 rtc::CritScope cs(&lock_);
301 EXPECT_FALSE(delivered_report_);
302 ++produced_on_worker_thread_;
303 }
304
hbos6ded1902016-11-01 01:50:46 -0700305 rtc::scoped_refptr<RTCStatsReport> worker_report =
306 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700307 worker_report->AddStats(std::unique_ptr<const RTCStats>(
308 new RTCTestStats("WorkerThreadStats", timestamp_us)));
309 AddPartialResults(worker_report);
310 }
311 void ProducePartialResultsOnNetworkThread(int64_t timestamp_us) override {
312 EXPECT_TRUE(network_thread_->IsCurrent());
313 {
314 rtc::CritScope cs(&lock_);
315 EXPECT_FALSE(delivered_report_);
316 ++produced_on_network_thread_;
317 }
318
319 rtc::scoped_refptr<RTCStatsReport> network_report =
hbos6ded1902016-11-01 01:50:46 -0700320 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700321 network_report->AddStats(std::unique_ptr<const RTCStats>(
322 new RTCTestStats("NetworkThreadStats", timestamp_us)));
323 AddPartialResults(network_report);
324 }
325
326 private:
327 rtc::Thread* const signaling_thread_;
328 rtc::Thread* const worker_thread_;
329 rtc::Thread* const network_thread_;
330
331 rtc::CriticalSection lock_;
332 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
333 int produced_on_signaling_thread_ = 0;
334 int produced_on_worker_thread_ = 0;
335 int produced_on_network_thread_ = 0;
hbosd565b732016-08-30 14:04:35 -0700336};
337
hbosc82f2e12016-09-05 01:36:50 -0700338class StatsCallback : public RTCStatsCollectorCallback {
339 public:
340 static rtc::scoped_refptr<StatsCallback> Create(
341 rtc::scoped_refptr<const RTCStatsReport>* report_ptr = nullptr) {
342 return rtc::scoped_refptr<StatsCallback>(
343 new rtc::RefCountedObject<StatsCallback>(report_ptr));
344 }
345
346 void OnStatsDelivered(
347 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
348 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
349 report_ = report;
350 if (report_ptr_)
351 *report_ptr_ = report_;
352 }
353
354 rtc::scoped_refptr<const RTCStatsReport> report() const {
355 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
356 return report_;
357 }
358
359 protected:
360 explicit StatsCallback(rtc::scoped_refptr<const RTCStatsReport>* report_ptr)
361 : report_ptr_(report_ptr) {}
362
363 private:
364 rtc::ThreadChecker thread_checker_;
365 rtc::scoped_refptr<const RTCStatsReport> report_;
366 rtc::scoped_refptr<const RTCStatsReport>* report_ptr_;
367};
368
369class RTCStatsCollectorTest : public testing::Test {
370 public:
371 RTCStatsCollectorTest()
372 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()),
373 collector_(RTCStatsCollector::Create(
374 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) {
375 }
376
377 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
378 rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create();
379 collector_->GetStatsReport(callback);
380 EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs);
hboscc555c52016-10-18 12:48:31 -0700381 int64_t after = rtc::TimeUTCMicros();
382 for (const RTCStats& stats : *callback->report()) {
383 EXPECT_LE(stats.timestamp_us(), after);
384 }
hbosc82f2e12016-09-05 01:36:50 -0700385 return callback->report();
386 }
387
hbosc47a0c32016-10-11 14:54:49 -0700388 const RTCIceCandidateStats* ExpectReportContainsCandidate(
hbosab9f6e42016-10-07 02:18:47 -0700389 const rtc::scoped_refptr<const RTCStatsReport>& report,
390 const cricket::Candidate& candidate,
391 bool is_local) {
hbosc47a0c32016-10-11 14:54:49 -0700392 const RTCStats* stats = report->Get("RTCIceCandidate_" + candidate.id());
hbosab9f6e42016-10-07 02:18:47 -0700393 EXPECT_TRUE(stats);
394 const RTCIceCandidateStats* candidate_stats;
395 if (is_local)
396 candidate_stats = &stats->cast_to<RTCLocalIceCandidateStats>();
397 else
398 candidate_stats = &stats->cast_to<RTCRemoteIceCandidateStats>();
399 EXPECT_EQ(*candidate_stats->ip, candidate.address().ipaddr().ToString());
400 EXPECT_EQ(*candidate_stats->port,
401 static_cast<int32_t>(candidate.address().port()));
402 EXPECT_EQ(*candidate_stats->protocol, candidate.protocol());
403 EXPECT_EQ(*candidate_stats->candidate_type,
hboscc555c52016-10-18 12:48:31 -0700404 CandidateTypeToRTCIceCandidateTypeForTesting(candidate.type()));
hbosab9f6e42016-10-07 02:18:47 -0700405 EXPECT_EQ(*candidate_stats->priority,
406 static_cast<int32_t>(candidate.priority()));
407 // TODO(hbos): Define candidate_stats->url. crbug.com/632723
408 EXPECT_FALSE(candidate_stats->url.is_defined());
hbosc47a0c32016-10-11 14:54:49 -0700409 return candidate_stats;
410 }
411
412 void ExpectReportContainsCandidatePair(
413 const rtc::scoped_refptr<const RTCStatsReport>& report,
414 const cricket::TransportStats& transport_stats) {
415 for (const auto& channel_stats : transport_stats.channel_stats) {
416 for (const cricket::ConnectionInfo& info :
417 channel_stats.connection_infos) {
418 const std::string& id = "RTCIceCandidatePair_" +
419 info.local_candidate.id() + "_" + info.remote_candidate.id();
420 const RTCStats* stats = report->Get(id);
hbos2fa7c672016-10-24 04:00:05 -0700421 ASSERT_TRUE(stats);
hbosc47a0c32016-10-11 14:54:49 -0700422 const RTCIceCandidatePairStats& candidate_pair_stats =
423 stats->cast_to<RTCIceCandidatePairStats>();
424
425 // TODO(hbos): Define all the undefined |candidate_pair_stats| stats.
426 // The EXPECT_FALSE are for the undefined stats, see also todos listed
hbos5d79a7c2016-10-24 09:27:10 -0700427 // in rtcstats_objects.h. crbug.com/633550
hbosc47a0c32016-10-11 14:54:49 -0700428 EXPECT_FALSE(candidate_pair_stats.transport_id.is_defined());
429 const RTCIceCandidateStats* local_candidate =
430 ExpectReportContainsCandidate(report, info.local_candidate, true);
431 EXPECT_EQ(*candidate_pair_stats.local_candidate_id,
432 local_candidate->id());
433 const RTCIceCandidateStats* remote_candidate =
434 ExpectReportContainsCandidate(report, info.remote_candidate, false);
435 EXPECT_EQ(*candidate_pair_stats.remote_candidate_id,
436 remote_candidate->id());
437
438 EXPECT_FALSE(candidate_pair_stats.state.is_defined());
439 EXPECT_FALSE(candidate_pair_stats.priority.is_defined());
440 EXPECT_FALSE(candidate_pair_stats.nominated.is_defined());
441 EXPECT_EQ(*candidate_pair_stats.writable, info.writable);
442 EXPECT_FALSE(candidate_pair_stats.readable.is_defined());
443 EXPECT_EQ(*candidate_pair_stats.bytes_sent,
444 static_cast<uint64_t>(info.sent_total_bytes));
445 EXPECT_EQ(*candidate_pair_stats.bytes_received,
446 static_cast<uint64_t>(info.recv_total_bytes));
447 EXPECT_FALSE(candidate_pair_stats.total_rtt.is_defined());
448 EXPECT_EQ(*candidate_pair_stats.current_rtt,
449 static_cast<double>(info.rtt) / 1000.0);
450 EXPECT_FALSE(
451 candidate_pair_stats.available_outgoing_bitrate.is_defined());
452 EXPECT_FALSE(
453 candidate_pair_stats.available_incoming_bitrate.is_defined());
454 EXPECT_FALSE(candidate_pair_stats.requests_received.is_defined());
455 EXPECT_EQ(*candidate_pair_stats.requests_sent,
456 static_cast<uint64_t>(info.sent_ping_requests_total));
457 EXPECT_EQ(*candidate_pair_stats.responses_received,
458 static_cast<uint64_t>(info.recv_ping_responses));
459 EXPECT_EQ(*candidate_pair_stats.responses_sent,
460 static_cast<uint64_t>(info.sent_ping_responses));
461 EXPECT_FALSE(
462 candidate_pair_stats.retransmissions_received.is_defined());
463 EXPECT_FALSE(candidate_pair_stats.retransmissions_sent.is_defined());
464 EXPECT_FALSE(
465 candidate_pair_stats.consent_requests_received.is_defined());
466 EXPECT_FALSE(candidate_pair_stats.consent_requests_sent.is_defined());
467 EXPECT_FALSE(
468 candidate_pair_stats.consent_responses_received.is_defined());
469 EXPECT_FALSE(candidate_pair_stats.consent_responses_sent.is_defined());
470 }
471 }
hbosab9f6e42016-10-07 02:18:47 -0700472 }
473
hbos6ab97ce2016-10-03 14:16:56 -0700474 void ExpectReportContainsCertificateInfo(
475 const rtc::scoped_refptr<const RTCStatsReport>& report,
476 const CertificateInfo& cert_info) {
477 for (size_t i = 0; i < cert_info.fingerprints.size(); ++i) {
478 const RTCStats* stats = report->Get(
479 "RTCCertificate_" + cert_info.fingerprints[i]);
hbos2fa7c672016-10-24 04:00:05 -0700480 ASSERT_TRUE(stats);
hbos6ab97ce2016-10-03 14:16:56 -0700481 const RTCCertificateStats& cert_stats =
482 stats->cast_to<const RTCCertificateStats>();
483 EXPECT_EQ(*cert_stats.fingerprint, cert_info.fingerprints[i]);
484 EXPECT_EQ(*cert_stats.fingerprint_algorithm, "sha-1");
485 EXPECT_EQ(*cert_stats.base64_certificate, cert_info.pems[i]);
486 if (i + 1 < cert_info.fingerprints.size()) {
487 EXPECT_EQ(*cert_stats.issuer_certificate_id,
488 "RTCCertificate_" + cert_info.fingerprints[i + 1]);
489 } else {
490 EXPECT_FALSE(cert_stats.issuer_certificate_id.is_defined());
491 }
492 }
493 }
494
hbos2fa7c672016-10-24 04:00:05 -0700495 void ExpectReportContainsTransportStats(
496 const rtc::scoped_refptr<const RTCStatsReport>& report,
497 const cricket::TransportStats& transport,
498 const CertificateInfo* local_certinfo,
499 const CertificateInfo* remote_certinfo) {
500 std::string rtcp_transport_stats_id;
501 for (const auto& channel_stats : transport.channel_stats) {
502 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
503 rtcp_transport_stats_id = "RTCTransport_" + transport.transport_name +
504 "_" + rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTCP);
505 }
506 }
507 for (const auto& channel_stats : transport.channel_stats) {
508 const cricket::ConnectionInfo* best_connection_info = nullptr;
509 const RTCStats* stats = report->Get(
510 "RTCTransport_" + transport.transport_name + "_" +
511 rtc::ToString<>(channel_stats.component));
512 ASSERT_TRUE(stats);
513 const RTCTransportStats& transport_stats =
514 stats->cast_to<const RTCTransportStats>();
515 uint64_t bytes_sent = 0;
516 uint64_t bytes_received = 0;
517 for (const cricket::ConnectionInfo& info :
518 channel_stats.connection_infos) {
519 bytes_sent += info.sent_total_bytes;
520 bytes_received += info.recv_total_bytes;
521 if (info.best_connection)
522 best_connection_info = &info;
523 }
524 EXPECT_EQ(*transport_stats.bytes_sent, bytes_sent);
525 EXPECT_EQ(*transport_stats.bytes_received, bytes_received);
526 if (best_connection_info) {
527 EXPECT_EQ(*transport_stats.active_connection, true);
528 // TODO(hbos): Instead of testing how the ID looks, test that the
529 // corresponding pair's IP addresses are equal to the IP addresses of
530 // the |best_connection_info| data. crbug.com/653873
531 EXPECT_EQ(*transport_stats.selected_candidate_pair_id,
532 "RTCIceCandidatePair_" +
533 best_connection_info->local_candidate.id() + "_" +
534 best_connection_info->remote_candidate.id());
535 EXPECT_TRUE(report->Get(*transport_stats.selected_candidate_pair_id));
536 } else {
537 EXPECT_EQ(*transport_stats.active_connection, false);
538 EXPECT_FALSE(transport_stats.selected_candidate_pair_id.is_defined());
539 }
540 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
541 !rtcp_transport_stats_id.empty()) {
542 EXPECT_EQ(*transport_stats.rtcp_transport_stats_id,
543 rtcp_transport_stats_id);
544 } else {
545 EXPECT_FALSE(transport_stats.rtcp_transport_stats_id.is_defined());
546 }
547 if (local_certinfo && remote_certinfo) {
548 EXPECT_EQ(*transport_stats.local_certificate_id,
549 "RTCCertificate_" + local_certinfo->fingerprints[0]);
550 EXPECT_EQ(*transport_stats.remote_certificate_id,
551 "RTCCertificate_" + remote_certinfo->fingerprints[0]);
552 EXPECT_TRUE(report->Get(*transport_stats.local_certificate_id));
553 EXPECT_TRUE(report->Get(*transport_stats.remote_certificate_id));
554 } else {
555 EXPECT_FALSE(transport_stats.local_certificate_id.is_defined());
556 EXPECT_FALSE(transport_stats.remote_certificate_id.is_defined());
557 }
558 }
559 }
560
hboscc555c52016-10-18 12:48:31 -0700561 void ExpectReportContainsDataChannel(
562 const rtc::scoped_refptr<const RTCStatsReport>& report,
563 const DataChannel& data_channel) {
564 const RTCStats* stats = report->Get("RTCDataChannel_" +
565 rtc::ToString<>(data_channel.id()));
566 EXPECT_TRUE(stats);
567 const RTCDataChannelStats& data_channel_stats =
568 stats->cast_to<const RTCDataChannelStats>();
569 EXPECT_EQ(*data_channel_stats.label, data_channel.label());
570 EXPECT_EQ(*data_channel_stats.protocol, data_channel.protocol());
571 EXPECT_EQ(*data_channel_stats.datachannelid, data_channel.id());
572 EXPECT_EQ(*data_channel_stats.state,
573 DataStateToRTCDataChannelStateForTesting(data_channel.state()));
574 EXPECT_EQ(*data_channel_stats.messages_sent, data_channel.messages_sent());
575 EXPECT_EQ(*data_channel_stats.bytes_sent, data_channel.bytes_sent());
576 EXPECT_EQ(*data_channel_stats.messages_received,
577 data_channel.messages_received());
578 EXPECT_EQ(*data_channel_stats.bytes_received,
579 data_channel.bytes_received());
580 }
581
hbosc82f2e12016-09-05 01:36:50 -0700582 protected:
583 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_;
584 rtc::scoped_refptr<RTCStatsCollector> collector_;
585};
586
587TEST_F(RTCStatsCollectorTest, SingleCallback) {
588 rtc::scoped_refptr<const RTCStatsReport> result;
589 collector_->GetStatsReport(StatsCallback::Create(&result));
590 EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs);
591}
592
593TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
594 rtc::scoped_refptr<const RTCStatsReport> a;
595 rtc::scoped_refptr<const RTCStatsReport> b;
596 rtc::scoped_refptr<const RTCStatsReport> c;
597 collector_->GetStatsReport(StatsCallback::Create(&a));
598 collector_->GetStatsReport(StatsCallback::Create(&b));
599 collector_->GetStatsReport(StatsCallback::Create(&c));
600 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs);
601 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs);
602 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs);
603 EXPECT_EQ(a.get(), b.get());
604 EXPECT_EQ(b.get(), c.get());
605}
606
607TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
hbosd565b732016-08-30 14:04:35 -0700608 // Caching should ensure |a| and |b| are the same report.
hbosc82f2e12016-09-05 01:36:50 -0700609 rtc::scoped_refptr<const RTCStatsReport> a = GetStatsReport();
610 rtc::scoped_refptr<const RTCStatsReport> b = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700611 EXPECT_EQ(a.get(), b.get());
612 // Invalidate cache by clearing it.
hbosc82f2e12016-09-05 01:36:50 -0700613 collector_->ClearCachedStatsReport();
614 rtc::scoped_refptr<const RTCStatsReport> c = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700615 EXPECT_NE(b.get(), c.get());
616 // Invalidate cache by advancing time.
hbosfdafab82016-09-14 06:02:13 -0700617 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51));
hbosc82f2e12016-09-05 01:36:50 -0700618 rtc::scoped_refptr<const RTCStatsReport> d = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700619 EXPECT_TRUE(d);
620 EXPECT_NE(c.get(), d.get());
621}
622
hbosc82f2e12016-09-05 01:36:50 -0700623TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
hbosc82f2e12016-09-05 01:36:50 -0700624 rtc::scoped_refptr<const RTCStatsReport> a;
625 rtc::scoped_refptr<const RTCStatsReport> b;
626 rtc::scoped_refptr<const RTCStatsReport> c;
627 collector_->GetStatsReport(StatsCallback::Create(&a));
628 collector_->GetStatsReport(StatsCallback::Create(&b));
629 // Cache is invalidated after 50 ms.
hbosfdafab82016-09-14 06:02:13 -0700630 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51));
hbosc82f2e12016-09-05 01:36:50 -0700631 collector_->GetStatsReport(StatsCallback::Create(&c));
632 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs);
633 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs);
634 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs);
635 EXPECT_EQ(a.get(), b.get());
636 // The act of doing |AdvanceTime| processes all messages. If this was not the
637 // case we might not require |c| to be fresher than |b|.
638 EXPECT_NE(c.get(), b.get());
639}
640
hbos6ab97ce2016-10-03 14:16:56 -0700641TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
642 std::unique_ptr<CertificateInfo> local_certinfo =
643 CreateFakeCertificateAndInfoFromDers(
644 std::vector<std::string>({ "(local) single certificate" }));
645 std::unique_ptr<CertificateInfo> remote_certinfo =
646 CreateFakeCertificateAndInfoFromDers(
647 std::vector<std::string>({ "(remote) single certificate" }));
648
649 // Mock the session to return the local and remote certificates.
650 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
651 [this](SessionStats* stats) {
652 stats->transport_stats["transport"].transport_name = "transport";
653 return true;
654 }));
655 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
656 Invoke([this, &local_certinfo](const std::string& transport_name,
657 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
658 if (transport_name == "transport") {
659 *certificate = local_certinfo->certificate;
660 return true;
661 }
662 return false;
663 }));
664 EXPECT_CALL(test_->session(),
665 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
666 [this, &remote_certinfo](const std::string& transport_name) {
667 if (transport_name == "transport")
668 return remote_certinfo->certificate->ssl_certificate().GetReference();
669 return static_cast<rtc::SSLCertificate*>(nullptr);
670 }));
671
672 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
673 ExpectReportContainsCertificateInfo(report, *local_certinfo.get());
674 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
675}
676
677TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
678 std::unique_ptr<CertificateInfo> audio_local_certinfo =
679 CreateFakeCertificateAndInfoFromDers(
680 std::vector<std::string>({ "(local) audio" }));
681 audio_local_certinfo = CreateFakeCertificateAndInfoFromDers(
682 audio_local_certinfo->ders);
683 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
684 CreateFakeCertificateAndInfoFromDers(
685 std::vector<std::string>({ "(remote) audio" }));
686 audio_remote_certinfo = CreateFakeCertificateAndInfoFromDers(
687 audio_remote_certinfo->ders);
688
689 std::unique_ptr<CertificateInfo> video_local_certinfo =
690 CreateFakeCertificateAndInfoFromDers(
691 std::vector<std::string>({ "(local) video" }));
692 video_local_certinfo = CreateFakeCertificateAndInfoFromDers(
693 video_local_certinfo->ders);
694 std::unique_ptr<CertificateInfo> video_remote_certinfo =
695 CreateFakeCertificateAndInfoFromDers(
696 std::vector<std::string>({ "(remote) video" }));
697 video_remote_certinfo = CreateFakeCertificateAndInfoFromDers(
698 video_remote_certinfo->ders);
699
700 // Mock the session to return the local and remote certificates.
701 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
702 [this](SessionStats* stats) {
703 stats->transport_stats["audio"].transport_name = "audio";
704 stats->transport_stats["video"].transport_name = "video";
705 return true;
706 }));
707 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
708 Invoke([this, &audio_local_certinfo, &video_local_certinfo](
709 const std::string& transport_name,
710 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
711 if (transport_name == "audio") {
712 *certificate = audio_local_certinfo->certificate;
713 return true;
714 }
715 if (transport_name == "video") {
716 *certificate = video_local_certinfo->certificate;
717 return true;
718 }
719 return false;
720 }));
721 EXPECT_CALL(test_->session(),
722 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
723 [this, &audio_remote_certinfo, &video_remote_certinfo](
724 const std::string& transport_name) {
725 if (transport_name == "audio") {
726 return audio_remote_certinfo->certificate->ssl_certificate()
727 .GetReference();
728 }
729 if (transport_name == "video") {
730 return video_remote_certinfo->certificate->ssl_certificate()
731 .GetReference();
732 }
733 return static_cast<rtc::SSLCertificate*>(nullptr);
734 }));
735
736 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
737 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo.get());
738 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo.get());
739 ExpectReportContainsCertificateInfo(report, *video_local_certinfo.get());
740 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo.get());
741}
742
743TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
744 std::vector<std::string> local_ders;
745 local_ders.push_back("(local) this");
746 local_ders.push_back("(local) is");
747 local_ders.push_back("(local) a");
748 local_ders.push_back("(local) chain");
749 std::unique_ptr<CertificateInfo> local_certinfo =
750 CreateFakeCertificateAndInfoFromDers(local_ders);
751 std::vector<std::string> remote_ders;
752 remote_ders.push_back("(remote) this");
753 remote_ders.push_back("(remote) is");
754 remote_ders.push_back("(remote) another");
755 remote_ders.push_back("(remote) chain");
756 std::unique_ptr<CertificateInfo> remote_certinfo =
757 CreateFakeCertificateAndInfoFromDers(remote_ders);
758
759 // Mock the session to return the local and remote certificates.
760 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
761 [this](SessionStats* stats) {
762 stats->transport_stats["transport"].transport_name = "transport";
763 return true;
764 }));
765 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
766 Invoke([this, &local_certinfo](const std::string& transport_name,
767 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
768 if (transport_name == "transport") {
769 *certificate = local_certinfo->certificate;
770 return true;
771 }
772 return false;
773 }));
774 EXPECT_CALL(test_->session(),
775 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
776 [this, &remote_certinfo](const std::string& transport_name) {
777 if (transport_name == "transport")
778 return remote_certinfo->certificate->ssl_certificate().GetReference();
779 return static_cast<rtc::SSLCertificate*>(nullptr);
780 }));
781
782 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
783 ExpectReportContainsCertificateInfo(report, *local_certinfo.get());
784 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
785}
786
hboscc555c52016-10-18 12:48:31 -0700787TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
788 test_->data_channels().push_back(
789 new MockDataChannel(0, DataChannelInterface::kConnecting));
790 test_->data_channels().push_back(
791 new MockDataChannel(1, DataChannelInterface::kOpen));
792 test_->data_channels().push_back(
793 new MockDataChannel(2, DataChannelInterface::kClosing));
794 test_->data_channels().push_back(
795 new MockDataChannel(3, DataChannelInterface::kClosed));
796
797 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
798 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
799 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
800 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
801 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
802
803 test_->data_channels().clear();
804 test_->data_channels().push_back(
805 new MockDataChannel(0, DataChannelInterface::kConnecting,
806 1, 2, 3, 4));
807 test_->data_channels().push_back(
808 new MockDataChannel(1, DataChannelInterface::kOpen,
809 5, 6, 7, 8));
810 test_->data_channels().push_back(
811 new MockDataChannel(2, DataChannelInterface::kClosing,
812 9, 10, 11, 12));
813 test_->data_channels().push_back(
814 new MockDataChannel(3, DataChannelInterface::kClosed,
815 13, 14, 15, 16));
816
817 collector_->ClearCachedStatsReport();
818 report = GetStatsReport();
819 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
820 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
821 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
822 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
823}
824
hbosab9f6e42016-10-07 02:18:47 -0700825TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
826 // Candidates in the first transport stats.
827 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
828 "1.2.3.4", 5,
829 "a_local_host's protocol",
830 cricket::LOCAL_PORT_TYPE,
831 0);
832 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
833 "6.7.8.9", 10,
834 "remote_srflx's protocol",
835 cricket::STUN_PORT_TYPE,
836 1);
837 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
838 "11.12.13.14", 15,
839 "a_local_prflx's protocol",
840 cricket::PRFLX_PORT_TYPE,
841 2);
842 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
843 "16.17.18.19", 20,
844 "a_remote_relay's protocol",
845 cricket::RELAY_PORT_TYPE,
846 3);
847 // Candidates in the second transport stats.
848 std::unique_ptr<cricket::Candidate> b_local = CreateFakeCandidate(
849 "42.42.42.42", 42,
850 "b_local's protocol",
851 cricket::LOCAL_PORT_TYPE,
852 42);
853 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
854 "42.42.42.42", 42,
855 "b_remote's protocol",
856 cricket::LOCAL_PORT_TYPE,
857 42);
858
859 SessionStats session_stats;
860
861 cricket::TransportChannelStats a_transport_channel_stats;
862 a_transport_channel_stats.connection_infos.push_back(
863 cricket::ConnectionInfo());
864 a_transport_channel_stats.connection_infos[0].local_candidate =
865 *a_local_host.get();
866 a_transport_channel_stats.connection_infos[0].remote_candidate =
867 *a_remote_srflx.get();
868 a_transport_channel_stats.connection_infos.push_back(
869 cricket::ConnectionInfo());
870 a_transport_channel_stats.connection_infos[1].local_candidate =
871 *a_local_prflx.get();
872 a_transport_channel_stats.connection_infos[1].remote_candidate =
873 *a_remote_relay.get();
874 session_stats.transport_stats["a"].channel_stats.push_back(
875 a_transport_channel_stats);
876
877 cricket::TransportChannelStats b_transport_channel_stats;
878 b_transport_channel_stats.connection_infos.push_back(
879 cricket::ConnectionInfo());
880 b_transport_channel_stats.connection_infos[0].local_candidate =
881 *b_local.get();
882 b_transport_channel_stats.connection_infos[0].remote_candidate =
883 *b_remote.get();
884 session_stats.transport_stats["b"].channel_stats.push_back(
885 b_transport_channel_stats);
886
887 // Mock the session to return the desired candidates.
888 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
889 [this, &session_stats](SessionStats* stats) {
890 *stats = session_stats;
891 return true;
892 }));
893
894 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
895 ExpectReportContainsCandidate(report, *a_local_host.get(), true);
896 ExpectReportContainsCandidate(report, *a_remote_srflx.get(), false);
897 ExpectReportContainsCandidate(report, *a_local_prflx.get(), true);
898 ExpectReportContainsCandidate(report, *a_remote_relay.get(), false);
899 ExpectReportContainsCandidate(report, *b_local.get(), true);
900 ExpectReportContainsCandidate(report, *b_remote.get(), false);
901}
902
hbosc47a0c32016-10-11 14:54:49 -0700903TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
904 std::unique_ptr<cricket::Candidate> local_candidate = CreateFakeCandidate(
905 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
906 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
907 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
908
909 SessionStats session_stats;
910
911 cricket::ConnectionInfo connection_info;
912 connection_info.local_candidate = *local_candidate.get();
913 connection_info.remote_candidate = *remote_candidate.get();
914 connection_info.writable = true;
915 connection_info.sent_total_bytes = 42;
916 connection_info.recv_total_bytes = 1234;
917 connection_info.rtt = 1337;
918 connection_info.sent_ping_requests_total = 1010;
919 connection_info.recv_ping_responses = 4321;
920 connection_info.sent_ping_responses = 1000;
921
922 cricket::TransportChannelStats transport_channel_stats;
923 transport_channel_stats.connection_infos.push_back(connection_info);
924 session_stats.transport_stats["transport"].transport_name = "transport";
925 session_stats.transport_stats["transport"].channel_stats.push_back(
926 transport_channel_stats);
927
928 // Mock the session to return the desired candidates.
929 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
930 [this, &session_stats](SessionStats* stats) {
931 *stats = session_stats;
932 return true;
933 }));
934
935 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
936 ExpectReportContainsCandidatePair(
937 report, session_stats.transport_stats["transport"]);
938}
939
hbosd565b732016-08-30 14:04:35 -0700940TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosc82f2e12016-09-05 01:36:50 -0700941 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700942 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(),
943 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats.";
944 const RTCStats* stats = report->Get("RTCPeerConnection");
945 EXPECT_TRUE(stats);
hbosd565b732016-08-30 14:04:35 -0700946 {
947 // Expected stats with no data channels
948 const RTCPeerConnectionStats& pcstats =
949 stats->cast_to<RTCPeerConnectionStats>();
950 EXPECT_EQ(*pcstats.data_channels_opened, static_cast<uint32_t>(0));
951 EXPECT_EQ(*pcstats.data_channels_closed, static_cast<uint32_t>(0));
952 }
953
954 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700955 new MockDataChannel(0, DataChannelInterface::kConnecting));
hbosd565b732016-08-30 14:04:35 -0700956 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700957 new MockDataChannel(1, DataChannelInterface::kOpen));
hbosd565b732016-08-30 14:04:35 -0700958 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700959 new MockDataChannel(2, DataChannelInterface::kClosing));
hbosd565b732016-08-30 14:04:35 -0700960 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700961 new MockDataChannel(3, DataChannelInterface::kClosed));
hbosd565b732016-08-30 14:04:35 -0700962
hbosc82f2e12016-09-05 01:36:50 -0700963 collector_->ClearCachedStatsReport();
964 report = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700965 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(),
966 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats.";
967 stats = report->Get("RTCPeerConnection");
hbos2fa7c672016-10-24 04:00:05 -0700968 ASSERT_TRUE(stats);
hbosd565b732016-08-30 14:04:35 -0700969 {
970 // Expected stats with the above four data channels
971 // TODO(hbos): When the |RTCPeerConnectionStats| is the number of data
972 // channels that have been opened and closed, not the numbers currently
973 // open/closed, we would expect opened >= closed and (opened - closed) to be
974 // the number currently open. crbug.com/636818.
975 const RTCPeerConnectionStats& pcstats =
976 stats->cast_to<RTCPeerConnectionStats>();
977 EXPECT_EQ(*pcstats.data_channels_opened, static_cast<uint32_t>(1));
978 EXPECT_EQ(*pcstats.data_channels_closed, static_cast<uint32_t>(3));
979 }
980}
981
hboseeafe942016-11-01 03:00:17 -0700982TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
983 MockVoiceMediaChannel* voice_media_channel = new MockVoiceMediaChannel();
984 cricket::VoiceChannel voice_channel(
985 test_->worker_thread(), test_->network_thread(), test_->media_engine(),
986 voice_media_channel, nullptr, "VoiceContentName", false);
987
988 cricket::VoiceMediaInfo voice_media_info;
989 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
990 voice_media_info.receivers[0].local_stats.push_back(
991 cricket::SsrcReceiverInfo());
992 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
993 voice_media_info.receivers[0].packets_rcvd = 2;
994 voice_media_info.receivers[0].bytes_rcvd = 3;
995 voice_media_info.receivers[0].jitter_ms = 4500;
996 voice_media_info.receivers[0].fraction_lost = 5.5f;
997 EXPECT_CALL(*voice_media_channel, GetStats(_))
998 .WillOnce(DoAll(SetArgPointee<0>(voice_media_info), Return(true)));
999
1000 SessionStats session_stats;
1001 session_stats.proxy_to_transport["VoiceContentName"] = "TransportName";
1002 session_stats.transport_stats["TransportName"].transport_name =
1003 "TransportName";
1004
1005 // Make sure the associated |RTCTransportStats| is created.
1006 cricket::TransportChannelStats channel_stats;
1007 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1008 session_stats.transport_stats["TransportName"].channel_stats.push_back(
1009 channel_stats);
1010
1011 EXPECT_CALL(test_->session(), GetTransportStats(_))
1012 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true)));
1013 EXPECT_CALL(test_->session(), voice_channel())
1014 .WillRepeatedly(Return(&voice_channel));
1015
1016 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1017
1018 RTCInboundRTPStreamStats expected_audio(
1019 "RTCInboundRTPAudioStream_1", report->timestamp_us());
1020 expected_audio.ssrc = "1";
1021 expected_audio.is_remote = false;
1022 expected_audio.media_type = "audio";
1023 expected_audio.transport_id = "RTCTransport_TransportName_" +
1024 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1025 expected_audio.packets_received = 2;
1026 expected_audio.bytes_received = 3;
1027 expected_audio.jitter = 4.5;
1028 expected_audio.fraction_lost = 5.5;
1029
1030 ASSERT(report->Get(expected_audio.id()));
1031 const RTCInboundRTPStreamStats& audio = report->Get(
1032 expected_audio.id())->cast_to<RTCInboundRTPStreamStats>();
1033 EXPECT_EQ(audio, expected_audio);
1034
1035 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
1036}
1037
1038TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
1039 MockVideoMediaChannel* video_media_channel = new MockVideoMediaChannel();
1040 cricket::VideoChannel video_channel(
1041 test_->worker_thread(), test_->network_thread(), video_media_channel,
1042 nullptr, "VideoContentName", false);
1043
1044 cricket::VideoMediaInfo video_media_info;
1045 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
1046 video_media_info.receivers[0].local_stats.push_back(
1047 cricket::SsrcReceiverInfo());
1048 video_media_info.receivers[0].local_stats[0].ssrc = 1;
1049 video_media_info.receivers[0].packets_rcvd = 2;
1050 video_media_info.receivers[0].bytes_rcvd = 3;
1051 video_media_info.receivers[0].fraction_lost = 4.5f;
1052 EXPECT_CALL(*video_media_channel, GetStats(_))
1053 .WillOnce(DoAll(SetArgPointee<0>(video_media_info), Return(true)));
1054
1055 SessionStats session_stats;
1056 session_stats.proxy_to_transport["VideoContentName"] = "TransportName";
1057 session_stats.transport_stats["TransportName"].transport_name =
1058 "TransportName";
1059
1060 // Make sure the associated |RTCTransportStats| is created.
1061 cricket::TransportChannelStats channel_stats;
1062 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1063 session_stats.transport_stats["TransportName"].channel_stats.push_back(
1064 channel_stats);
1065
1066 EXPECT_CALL(test_->session(), GetTransportStats(_))
1067 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true)));
1068 EXPECT_CALL(test_->session(), video_channel())
1069 .WillRepeatedly(Return(&video_channel));
1070
1071 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1072
1073 RTCInboundRTPStreamStats expected_audio(
1074 "RTCInboundRTPVideoStream_1", report->timestamp_us());
1075 expected_audio.ssrc = "1";
1076 expected_audio.is_remote = false;
1077 expected_audio.media_type = "video";
1078 expected_audio.transport_id = "RTCTransport_TransportName_" +
1079 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1080 expected_audio.packets_received = 2;
1081 expected_audio.bytes_received = 3;
1082 expected_audio.fraction_lost = 4.5;
1083
1084 ASSERT(report->Get(expected_audio.id()));
1085 const RTCInboundRTPStreamStats& audio = report->Get(
1086 expected_audio.id())->cast_to<RTCInboundRTPStreamStats>();
1087 EXPECT_EQ(audio, expected_audio);
1088
1089 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
1090}
1091
hbos6ded1902016-11-01 01:50:46 -07001092TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
1093 MockVoiceMediaChannel* voice_media_channel = new MockVoiceMediaChannel();
1094 cricket::VoiceChannel voice_channel(
1095 test_->worker_thread(), test_->network_thread(), test_->media_engine(),
1096 voice_media_channel, nullptr, "VoiceContentName", false);
1097
1098 cricket::VoiceMediaInfo voice_media_info;
1099 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
1100 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
1101 voice_media_info.senders[0].local_stats[0].ssrc = 1;
1102 voice_media_info.senders[0].packets_sent = 2;
1103 voice_media_info.senders[0].bytes_sent = 3;
hboseeafe942016-11-01 03:00:17 -07001104 voice_media_info.senders[0].rtt_ms = 4500;
hbos6ded1902016-11-01 01:50:46 -07001105 EXPECT_CALL(*voice_media_channel, GetStats(_))
1106 .WillOnce(DoAll(SetArgPointee<0>(voice_media_info), Return(true)));
1107
1108 SessionStats session_stats;
1109 session_stats.proxy_to_transport["VoiceContentName"] = "TransportName";
1110 session_stats.transport_stats["TransportName"].transport_name =
1111 "TransportName";
1112
1113 // Make sure the associated |RTCTransportStats| is created.
1114 cricket::TransportChannelStats channel_stats;
1115 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
hbos6ded1902016-11-01 01:50:46 -07001116 session_stats.transport_stats["TransportName"].channel_stats.push_back(
1117 channel_stats);
1118
1119 EXPECT_CALL(test_->session(), GetTransportStats(_))
1120 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true)));
1121 EXPECT_CALL(test_->session(), voice_channel())
1122 .WillRepeatedly(Return(&voice_channel));
1123
1124 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1125
1126 RTCOutboundRTPStreamStats expected_audio(
1127 "RTCOutboundRTPAudioStream_1", report->timestamp_us());
1128 expected_audio.ssrc = "1";
1129 expected_audio.is_remote = false;
1130 expected_audio.media_type = "audio";
1131 expected_audio.transport_id = "RTCTransport_TransportName_" +
1132 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1133 expected_audio.packets_sent = 2;
1134 expected_audio.bytes_sent = 3;
1135 expected_audio.round_trip_time = 4.5;
1136
1137 ASSERT(report->Get(expected_audio.id()));
1138 const RTCOutboundRTPStreamStats& audio = report->Get(
1139 expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>();
1140 EXPECT_EQ(audio, expected_audio);
1141
1142 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
1143}
1144
1145TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
1146 MockVideoMediaChannel* video_media_channel = new MockVideoMediaChannel();
1147 cricket::VideoChannel video_channel(
1148 test_->worker_thread(), test_->network_thread(), video_media_channel,
1149 nullptr, "VideoContentName", false);
1150
1151 cricket::VideoMediaInfo video_media_info;
1152 video_media_info.senders.push_back(cricket::VideoSenderInfo());
1153 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
1154 video_media_info.senders[0].local_stats[0].ssrc = 1;
1155 video_media_info.senders[0].firs_rcvd = 2;
1156 video_media_info.senders[0].plis_rcvd = 3;
1157 video_media_info.senders[0].nacks_rcvd = 4;
1158 video_media_info.senders[0].packets_sent = 5;
1159 video_media_info.senders[0].bytes_sent = 6;
hboseeafe942016-11-01 03:00:17 -07001160 video_media_info.senders[0].rtt_ms = 7500;
hbos6ded1902016-11-01 01:50:46 -07001161 EXPECT_CALL(*video_media_channel, GetStats(_))
1162 .WillOnce(DoAll(SetArgPointee<0>(video_media_info), Return(true)));
1163
1164 SessionStats session_stats;
1165 session_stats.proxy_to_transport["VideoContentName"] = "TransportName";
1166 session_stats.transport_stats["TransportName"].transport_name =
1167 "TransportName";
1168
1169 // Make sure the associated |RTCTransportStats| is created.
1170 cricket::TransportChannelStats channel_stats;
1171 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
hbos6ded1902016-11-01 01:50:46 -07001172 session_stats.transport_stats["TransportName"].channel_stats.push_back(
1173 channel_stats);
1174
1175 EXPECT_CALL(test_->session(), GetTransportStats(_))
1176 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true)));
1177 EXPECT_CALL(test_->session(), video_channel())
1178 .WillRepeatedly(Return(&video_channel));
1179
1180 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1181
1182 RTCOutboundRTPStreamStats expected_video(
1183 "RTCOutboundRTPVideoStream_1", report->timestamp_us());
1184 expected_video.ssrc = "1";
1185 expected_video.is_remote = false;
1186 expected_video.media_type = "video";
1187 expected_video.transport_id = "RTCTransport_TransportName_" +
1188 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1189 expected_video.fir_count = 2;
1190 expected_video.pli_count = 3;
1191 expected_video.nack_count = 4;
1192 expected_video.packets_sent = 5;
1193 expected_video.bytes_sent = 6;
1194 expected_video.round_trip_time = 7.5;
1195
1196 ASSERT(report->Get(expected_video.id()));
1197 const RTCOutboundRTPStreamStats& video = report->Get(
1198 expected_video.id())->cast_to<RTCOutboundRTPStreamStats>();
1199 EXPECT_EQ(video, expected_video);
1200
1201 EXPECT_TRUE(report->Get(*expected_video.transport_id));
1202}
1203
hbos2fa7c672016-10-24 04:00:05 -07001204TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
1205 std::unique_ptr<cricket::Candidate> rtp_local_candidate = CreateFakeCandidate(
1206 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
1207 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
1208 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1209 cricket::LOCAL_PORT_TYPE, 42);
1210 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
1211 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1212 cricket::LOCAL_PORT_TYPE, 42);
1213 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
1214 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1215 cricket::LOCAL_PORT_TYPE, 42);
1216
1217 SessionStats session_stats;
1218 session_stats.transport_stats["transport"].transport_name = "transport";
1219
1220 cricket::ConnectionInfo rtp_connection_info;
1221 rtp_connection_info.best_connection = false;
1222 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
1223 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
1224 rtp_connection_info.sent_total_bytes = 42;
1225 rtp_connection_info.recv_total_bytes = 1337;
1226 cricket::TransportChannelStats rtp_transport_channel_stats;
1227 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1228 rtp_transport_channel_stats.connection_infos.push_back(rtp_connection_info);
1229 session_stats.transport_stats["transport"].channel_stats.push_back(
1230 rtp_transport_channel_stats);
1231
1232
1233 // Mock the session to return the desired candidates.
1234 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
1235 [this, &session_stats](SessionStats* stats) {
1236 *stats = session_stats;
1237 return true;
1238 }));
1239
1240 // Get stats without RTCP, an active connection or certificates.
1241 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1242 ExpectReportContainsTransportStats(
1243 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1244
1245 cricket::ConnectionInfo rtcp_connection_info;
1246 rtcp_connection_info.best_connection = false;
1247 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
1248 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
1249 rtcp_connection_info.sent_total_bytes = 1337;
1250 rtcp_connection_info.recv_total_bytes = 42;
1251 cricket::TransportChannelStats rtcp_transport_channel_stats;
1252 rtcp_transport_channel_stats.component =
1253 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
1254 rtcp_transport_channel_stats.connection_infos.push_back(rtcp_connection_info);
1255 session_stats.transport_stats["transport"].channel_stats.push_back(
1256 rtcp_transport_channel_stats);
1257
1258 collector_->ClearCachedStatsReport();
1259 // Get stats with RTCP and without an active connection or certificates.
1260 report = GetStatsReport();
1261 ExpectReportContainsTransportStats(
1262 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1263
1264 // Get stats with an active connection.
1265 rtcp_connection_info.best_connection = true;
1266
1267 collector_->ClearCachedStatsReport();
1268 report = GetStatsReport();
1269 ExpectReportContainsTransportStats(
1270 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1271
1272 // Get stats with certificates.
1273 std::unique_ptr<CertificateInfo> local_certinfo =
1274 CreateFakeCertificateAndInfoFromDers(
1275 std::vector<std::string>({ "(local) local", "(local) chain" }));
1276 std::unique_ptr<CertificateInfo> remote_certinfo =
1277 CreateFakeCertificateAndInfoFromDers(
1278 std::vector<std::string>({ "(remote) local", "(remote) chain" }));
1279 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
1280 Invoke([this, &local_certinfo](const std::string& transport_name,
1281 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
1282 if (transport_name == "transport") {
1283 *certificate = local_certinfo->certificate;
1284 return true;
1285 }
1286 return false;
1287 }));
1288 EXPECT_CALL(test_->session(),
1289 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
1290 [this, &remote_certinfo](const std::string& transport_name) {
1291 if (transport_name == "transport")
1292 return remote_certinfo->certificate->ssl_certificate().GetReference();
1293 return static_cast<rtc::SSLCertificate*>(nullptr);
1294 }));
1295
1296 collector_->ClearCachedStatsReport();
1297 report = GetStatsReport();
1298 ExpectReportContainsTransportStats(
1299 report, session_stats.transport_stats["transport"],
1300 local_certinfo.get(), remote_certinfo.get());
1301}
1302
hbosc82f2e12016-09-05 01:36:50 -07001303class RTCStatsCollectorTestWithFakeCollector : public testing::Test {
1304 public:
1305 RTCStatsCollectorTestWithFakeCollector()
1306 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()),
1307 collector_(FakeRTCStatsCollector::Create(
1308 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) {
1309 }
1310
1311 protected:
1312 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_;
1313 rtc::scoped_refptr<FakeRTCStatsCollector> collector_;
1314};
1315
1316TEST_F(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
1317 collector_->VerifyThreadUsageAndResultsMerging();
1318}
1319
1320} // namespace
1321
hbosd565b732016-08-30 14:04:35 -07001322} // namespace webrtc