blob: 312f0d2d985ed453a5ae64fc3b46271b15146460 [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
hbos6ded1902016-11-01 01:50:46 -070073void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) {
74 *os << stats.ToString();
75}
76
hbosda389e32016-10-25 10:55:08 -070077void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
78 *os << stats.ToString();
79}
80
hbosc82f2e12016-09-05 01:36:50 -070081namespace {
82
83const int64_t kGetStatsReportTimeoutMs = 1000;
84
hbos6ab97ce2016-10-03 14:16:56 -070085struct CertificateInfo {
86 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
87 std::vector<std::string> ders;
88 std::vector<std::string> pems;
89 std::vector<std::string> fingerprints;
90};
91
92std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
93 const std::vector<std::string>& ders) {
94 RTC_CHECK(!ders.empty());
95 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
96 info->ders = ders;
97 for (const std::string& der : ders) {
98 info->pems.push_back(rtc::SSLIdentity::DerToPem(
99 "CERTIFICATE",
100 reinterpret_cast<const unsigned char*>(der.c_str()),
101 der.length()));
102 }
103 info->certificate =
104 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
105 new rtc::FakeSSLIdentity(rtc::FakeSSLCertificate(info->pems))));
106 // Strip header/footer and newline characters of PEM strings.
107 for (size_t i = 0; i < info->pems.size(); ++i) {
108 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27,
109 "", 0, &info->pems[i]);
110 rtc::replace_substrs("-----END CERTIFICATE-----", 25,
111 "", 0, &info->pems[i]);
112 rtc::replace_substrs("\n", 1,
113 "", 0, &info->pems[i]);
114 }
115 // Fingerprint of leaf certificate.
116 std::unique_ptr<rtc::SSLFingerprint> fp(
117 rtc::SSLFingerprint::Create("sha-1",
118 &info->certificate->ssl_certificate()));
119 EXPECT_TRUE(fp);
120 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
121 // Fingerprints of the rest of the chain.
122 std::unique_ptr<rtc::SSLCertChain> chain =
123 info->certificate->ssl_certificate().GetChain();
124 if (chain) {
125 for (size_t i = 0; i < chain->GetSize(); i++) {
126 fp.reset(rtc::SSLFingerprint::Create("sha-1", &chain->Get(i)));
127 EXPECT_TRUE(fp);
128 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
129 }
130 }
131 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
132 return info;
133}
134
hbosab9f6e42016-10-07 02:18:47 -0700135std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
136 const std::string& hostname,
137 int port,
138 const std::string& protocol,
139 const std::string& candidate_type,
140 uint32_t priority) {
141 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
142 candidate->set_address(rtc::SocketAddress(hostname, port));
143 candidate->set_protocol(protocol);
144 candidate->set_type(candidate_type);
145 candidate->set_priority(priority);
146 return candidate;
147}
148
hbosc82f2e12016-09-05 01:36:50 -0700149class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver {
hbosd565b732016-08-30 14:04:35 -0700150 public:
hbosc82f2e12016-09-05 01:36:50 -0700151 RTCStatsCollectorTestHelper()
hbosd565b732016-08-30 14:04:35 -0700152 : worker_thread_(rtc::Thread::Current()),
153 network_thread_(rtc::Thread::Current()),
hbos6ded1902016-11-01 01:50:46 -0700154 media_engine_(new cricket::FakeMediaEngine()),
skvlad11a9cbf2016-10-07 11:53:05 -0700155 channel_manager_(
hbos6ded1902016-11-01 01:50:46 -0700156 new cricket::ChannelManager(media_engine_,
skvlad11a9cbf2016-10-07 11:53:05 -0700157 worker_thread_,
158 network_thread_)),
hbosd565b732016-08-30 14:04:35 -0700159 media_controller_(
160 MediaControllerInterface::Create(cricket::MediaConfig(),
161 worker_thread_,
skvlad11a9cbf2016-10-07 11:53:05 -0700162 channel_manager_.get(),
163 &event_log_)),
hbosd565b732016-08-30 14:04:35 -0700164 session_(media_controller_.get()),
165 pc_() {
hbos6ab97ce2016-10-03 14:16:56 -0700166 // Default return values for mocks.
hbosd565b732016-08-30 14:04:35 -0700167 EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_));
168 EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly(
169 ReturnRef(data_channels_));
hbos6ded1902016-11-01 01:50:46 -0700170 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
171 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
hbos6ab97ce2016-10-03 14:16:56 -0700172 EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false));
hbosab9f6e42016-10-07 02:18:47 -0700173 EXPECT_CALL(session_, GetLocalCertificate(_, _)).WillRepeatedly(
174 Return(false));
175 EXPECT_CALL(session_, GetRemoteSSLCertificate_ReturnsRawPointer(_))
176 .WillRepeatedly(Return(nullptr));
hbosd565b732016-08-30 14:04:35 -0700177 }
178
hbosfdafab82016-09-14 06:02:13 -0700179 rtc::ScopedFakeClock& fake_clock() { return fake_clock_; }
hbos6ded1902016-11-01 01:50:46 -0700180 rtc::Thread* worker_thread() { return worker_thread_; }
181 rtc::Thread* network_thread() { return network_thread_; }
182 cricket::FakeMediaEngine* media_engine() { return media_engine_; }
hbosd565b732016-08-30 14:04:35 -0700183 MockWebRtcSession& session() { return session_; }
184 MockPeerConnection& pc() { return pc_; }
185 std::vector<rtc::scoped_refptr<DataChannel>>& data_channels() {
186 return data_channels_;
187 }
188
189 // SetSessionDescriptionObserver overrides.
190 void OnSuccess() override {}
191 void OnFailure(const std::string& error) override {
192 RTC_NOTREACHED() << error;
193 }
194
195 private:
hbosfdafab82016-09-14 06:02:13 -0700196 rtc::ScopedFakeClock fake_clock_;
skvlad11a9cbf2016-10-07 11:53:05 -0700197 webrtc::RtcEventLogNullImpl event_log_;
hbosd565b732016-08-30 14:04:35 -0700198 rtc::Thread* const worker_thread_;
199 rtc::Thread* const network_thread_;
hbos6ded1902016-11-01 01:50:46 -0700200 cricket::FakeMediaEngine* media_engine_;
hbosd565b732016-08-30 14:04:35 -0700201 std::unique_ptr<cricket::ChannelManager> channel_manager_;
202 std::unique_ptr<webrtc::MediaControllerInterface> media_controller_;
203 MockWebRtcSession session_;
204 MockPeerConnection pc_;
205
206 std::vector<rtc::scoped_refptr<DataChannel>> data_channels_;
207};
208
hbosc82f2e12016-09-05 01:36:50 -0700209class RTCTestStats : public RTCStats {
hbosd565b732016-08-30 14:04:35 -0700210 public:
hbosfc5e0502016-10-06 02:06:10 -0700211 WEBRTC_RTCSTATS_DECL();
212
hbosc82f2e12016-09-05 01:36:50 -0700213 RTCTestStats(const std::string& id, int64_t timestamp_us)
214 : RTCStats(id, timestamp_us),
215 dummy_stat("dummyStat") {}
216
hbosc82f2e12016-09-05 01:36:50 -0700217 RTCStatsMember<int32_t> dummy_stat;
218};
219
hbosfc5e0502016-10-06 02:06:10 -0700220WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats",
221 &dummy_stat);
hbosc82f2e12016-09-05 01:36:50 -0700222
223// Overrides the stats collection to verify thread usage and that the resulting
224// partial reports are merged.
225class FakeRTCStatsCollector : public RTCStatsCollector,
226 public RTCStatsCollectorCallback {
227 public:
228 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
229 PeerConnection* pc,
230 int64_t cache_lifetime_us) {
231 return rtc::scoped_refptr<FakeRTCStatsCollector>(
232 new rtc::RefCountedObject<FakeRTCStatsCollector>(
233 pc, cache_lifetime_us));
234 }
235
236 // RTCStatsCollectorCallback implementation.
237 void OnStatsDelivered(
238 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
239 EXPECT_TRUE(signaling_thread_->IsCurrent());
240 rtc::CritScope cs(&lock_);
241 delivered_report_ = report;
242 }
243
244 void VerifyThreadUsageAndResultsMerging() {
245 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
246 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
247 }
248
249 bool HasVerifiedResults() {
250 EXPECT_TRUE(signaling_thread_->IsCurrent());
251 rtc::CritScope cs(&lock_);
252 if (!delivered_report_)
253 return false;
254 EXPECT_EQ(produced_on_signaling_thread_, 1);
255 EXPECT_EQ(produced_on_worker_thread_, 1);
256 EXPECT_EQ(produced_on_network_thread_, 1);
257
258 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
259 EXPECT_TRUE(delivered_report_->Get("WorkerThreadStats"));
260 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
261
262 produced_on_signaling_thread_ = 0;
263 produced_on_worker_thread_ = 0;
264 produced_on_network_thread_ = 0;
265 delivered_report_ = nullptr;
266 return true;
hbosd565b732016-08-30 14:04:35 -0700267 }
268
269 protected:
hbosc82f2e12016-09-05 01:36:50 -0700270 FakeRTCStatsCollector(
271 PeerConnection* pc,
272 int64_t cache_lifetime)
273 : RTCStatsCollector(pc, cache_lifetime),
274 signaling_thread_(pc->session()->signaling_thread()),
275 worker_thread_(pc->session()->worker_thread()),
276 network_thread_(pc->session()->network_thread()) {
277 }
278
279 void ProducePartialResultsOnSignalingThread(int64_t timestamp_us) override {
280 EXPECT_TRUE(signaling_thread_->IsCurrent());
281 {
282 rtc::CritScope cs(&lock_);
283 EXPECT_FALSE(delivered_report_);
284 ++produced_on_signaling_thread_;
285 }
286
287 rtc::scoped_refptr<RTCStatsReport> signaling_report =
hbos6ded1902016-11-01 01:50:46 -0700288 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700289 signaling_report->AddStats(std::unique_ptr<const RTCStats>(
290 new RTCTestStats("SignalingThreadStats", timestamp_us)));
291 AddPartialResults(signaling_report);
292 }
293 void ProducePartialResultsOnWorkerThread(int64_t timestamp_us) override {
294 EXPECT_TRUE(worker_thread_->IsCurrent());
295 {
296 rtc::CritScope cs(&lock_);
297 EXPECT_FALSE(delivered_report_);
298 ++produced_on_worker_thread_;
299 }
300
hbos6ded1902016-11-01 01:50:46 -0700301 rtc::scoped_refptr<RTCStatsReport> worker_report =
302 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700303 worker_report->AddStats(std::unique_ptr<const RTCStats>(
304 new RTCTestStats("WorkerThreadStats", timestamp_us)));
305 AddPartialResults(worker_report);
306 }
307 void ProducePartialResultsOnNetworkThread(int64_t timestamp_us) override {
308 EXPECT_TRUE(network_thread_->IsCurrent());
309 {
310 rtc::CritScope cs(&lock_);
311 EXPECT_FALSE(delivered_report_);
312 ++produced_on_network_thread_;
313 }
314
315 rtc::scoped_refptr<RTCStatsReport> network_report =
hbos6ded1902016-11-01 01:50:46 -0700316 RTCStatsReport::Create(0);
hbosc82f2e12016-09-05 01:36:50 -0700317 network_report->AddStats(std::unique_ptr<const RTCStats>(
318 new RTCTestStats("NetworkThreadStats", timestamp_us)));
319 AddPartialResults(network_report);
320 }
321
322 private:
323 rtc::Thread* const signaling_thread_;
324 rtc::Thread* const worker_thread_;
325 rtc::Thread* const network_thread_;
326
327 rtc::CriticalSection lock_;
328 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
329 int produced_on_signaling_thread_ = 0;
330 int produced_on_worker_thread_ = 0;
331 int produced_on_network_thread_ = 0;
hbosd565b732016-08-30 14:04:35 -0700332};
333
hbosc82f2e12016-09-05 01:36:50 -0700334class StatsCallback : public RTCStatsCollectorCallback {
335 public:
336 static rtc::scoped_refptr<StatsCallback> Create(
337 rtc::scoped_refptr<const RTCStatsReport>* report_ptr = nullptr) {
338 return rtc::scoped_refptr<StatsCallback>(
339 new rtc::RefCountedObject<StatsCallback>(report_ptr));
340 }
341
342 void OnStatsDelivered(
343 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
344 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
345 report_ = report;
346 if (report_ptr_)
347 *report_ptr_ = report_;
348 }
349
350 rtc::scoped_refptr<const RTCStatsReport> report() const {
351 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
352 return report_;
353 }
354
355 protected:
356 explicit StatsCallback(rtc::scoped_refptr<const RTCStatsReport>* report_ptr)
357 : report_ptr_(report_ptr) {}
358
359 private:
360 rtc::ThreadChecker thread_checker_;
361 rtc::scoped_refptr<const RTCStatsReport> report_;
362 rtc::scoped_refptr<const RTCStatsReport>* report_ptr_;
363};
364
365class RTCStatsCollectorTest : public testing::Test {
366 public:
367 RTCStatsCollectorTest()
368 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()),
369 collector_(RTCStatsCollector::Create(
370 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) {
371 }
372
373 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
374 rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create();
375 collector_->GetStatsReport(callback);
376 EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs);
hboscc555c52016-10-18 12:48:31 -0700377 int64_t after = rtc::TimeUTCMicros();
378 for (const RTCStats& stats : *callback->report()) {
379 EXPECT_LE(stats.timestamp_us(), after);
380 }
hbosc82f2e12016-09-05 01:36:50 -0700381 return callback->report();
382 }
383
hbosc47a0c32016-10-11 14:54:49 -0700384 const RTCIceCandidateStats* ExpectReportContainsCandidate(
hbosab9f6e42016-10-07 02:18:47 -0700385 const rtc::scoped_refptr<const RTCStatsReport>& report,
386 const cricket::Candidate& candidate,
387 bool is_local) {
hbosc47a0c32016-10-11 14:54:49 -0700388 const RTCStats* stats = report->Get("RTCIceCandidate_" + candidate.id());
hbosab9f6e42016-10-07 02:18:47 -0700389 EXPECT_TRUE(stats);
390 const RTCIceCandidateStats* candidate_stats;
391 if (is_local)
392 candidate_stats = &stats->cast_to<RTCLocalIceCandidateStats>();
393 else
394 candidate_stats = &stats->cast_to<RTCRemoteIceCandidateStats>();
395 EXPECT_EQ(*candidate_stats->ip, candidate.address().ipaddr().ToString());
396 EXPECT_EQ(*candidate_stats->port,
397 static_cast<int32_t>(candidate.address().port()));
398 EXPECT_EQ(*candidate_stats->protocol, candidate.protocol());
399 EXPECT_EQ(*candidate_stats->candidate_type,
hboscc555c52016-10-18 12:48:31 -0700400 CandidateTypeToRTCIceCandidateTypeForTesting(candidate.type()));
hbosab9f6e42016-10-07 02:18:47 -0700401 EXPECT_EQ(*candidate_stats->priority,
402 static_cast<int32_t>(candidate.priority()));
403 // TODO(hbos): Define candidate_stats->url. crbug.com/632723
404 EXPECT_FALSE(candidate_stats->url.is_defined());
hbosc47a0c32016-10-11 14:54:49 -0700405 return candidate_stats;
406 }
407
408 void ExpectReportContainsCandidatePair(
409 const rtc::scoped_refptr<const RTCStatsReport>& report,
410 const cricket::TransportStats& transport_stats) {
411 for (const auto& channel_stats : transport_stats.channel_stats) {
412 for (const cricket::ConnectionInfo& info :
413 channel_stats.connection_infos) {
414 const std::string& id = "RTCIceCandidatePair_" +
415 info.local_candidate.id() + "_" + info.remote_candidate.id();
416 const RTCStats* stats = report->Get(id);
hbos2fa7c672016-10-24 04:00:05 -0700417 ASSERT_TRUE(stats);
hbosc47a0c32016-10-11 14:54:49 -0700418 const RTCIceCandidatePairStats& candidate_pair_stats =
419 stats->cast_to<RTCIceCandidatePairStats>();
420
421 // TODO(hbos): Define all the undefined |candidate_pair_stats| stats.
422 // The EXPECT_FALSE are for the undefined stats, see also todos listed
hbos5d79a7c2016-10-24 09:27:10 -0700423 // in rtcstats_objects.h. crbug.com/633550
hbosc47a0c32016-10-11 14:54:49 -0700424 EXPECT_FALSE(candidate_pair_stats.transport_id.is_defined());
425 const RTCIceCandidateStats* local_candidate =
426 ExpectReportContainsCandidate(report, info.local_candidate, true);
427 EXPECT_EQ(*candidate_pair_stats.local_candidate_id,
428 local_candidate->id());
429 const RTCIceCandidateStats* remote_candidate =
430 ExpectReportContainsCandidate(report, info.remote_candidate, false);
431 EXPECT_EQ(*candidate_pair_stats.remote_candidate_id,
432 remote_candidate->id());
433
434 EXPECT_FALSE(candidate_pair_stats.state.is_defined());
435 EXPECT_FALSE(candidate_pair_stats.priority.is_defined());
436 EXPECT_FALSE(candidate_pair_stats.nominated.is_defined());
437 EXPECT_EQ(*candidate_pair_stats.writable, info.writable);
438 EXPECT_FALSE(candidate_pair_stats.readable.is_defined());
439 EXPECT_EQ(*candidate_pair_stats.bytes_sent,
440 static_cast<uint64_t>(info.sent_total_bytes));
441 EXPECT_EQ(*candidate_pair_stats.bytes_received,
442 static_cast<uint64_t>(info.recv_total_bytes));
443 EXPECT_FALSE(candidate_pair_stats.total_rtt.is_defined());
444 EXPECT_EQ(*candidate_pair_stats.current_rtt,
445 static_cast<double>(info.rtt) / 1000.0);
446 EXPECT_FALSE(
447 candidate_pair_stats.available_outgoing_bitrate.is_defined());
448 EXPECT_FALSE(
449 candidate_pair_stats.available_incoming_bitrate.is_defined());
450 EXPECT_FALSE(candidate_pair_stats.requests_received.is_defined());
451 EXPECT_EQ(*candidate_pair_stats.requests_sent,
452 static_cast<uint64_t>(info.sent_ping_requests_total));
453 EXPECT_EQ(*candidate_pair_stats.responses_received,
454 static_cast<uint64_t>(info.recv_ping_responses));
455 EXPECT_EQ(*candidate_pair_stats.responses_sent,
456 static_cast<uint64_t>(info.sent_ping_responses));
457 EXPECT_FALSE(
458 candidate_pair_stats.retransmissions_received.is_defined());
459 EXPECT_FALSE(candidate_pair_stats.retransmissions_sent.is_defined());
460 EXPECT_FALSE(
461 candidate_pair_stats.consent_requests_received.is_defined());
462 EXPECT_FALSE(candidate_pair_stats.consent_requests_sent.is_defined());
463 EXPECT_FALSE(
464 candidate_pair_stats.consent_responses_received.is_defined());
465 EXPECT_FALSE(candidate_pair_stats.consent_responses_sent.is_defined());
466 }
467 }
hbosab9f6e42016-10-07 02:18:47 -0700468 }
469
hbos6ab97ce2016-10-03 14:16:56 -0700470 void ExpectReportContainsCertificateInfo(
471 const rtc::scoped_refptr<const RTCStatsReport>& report,
472 const CertificateInfo& cert_info) {
473 for (size_t i = 0; i < cert_info.fingerprints.size(); ++i) {
474 const RTCStats* stats = report->Get(
475 "RTCCertificate_" + cert_info.fingerprints[i]);
hbos2fa7c672016-10-24 04:00:05 -0700476 ASSERT_TRUE(stats);
hbos6ab97ce2016-10-03 14:16:56 -0700477 const RTCCertificateStats& cert_stats =
478 stats->cast_to<const RTCCertificateStats>();
479 EXPECT_EQ(*cert_stats.fingerprint, cert_info.fingerprints[i]);
480 EXPECT_EQ(*cert_stats.fingerprint_algorithm, "sha-1");
481 EXPECT_EQ(*cert_stats.base64_certificate, cert_info.pems[i]);
482 if (i + 1 < cert_info.fingerprints.size()) {
483 EXPECT_EQ(*cert_stats.issuer_certificate_id,
484 "RTCCertificate_" + cert_info.fingerprints[i + 1]);
485 } else {
486 EXPECT_FALSE(cert_stats.issuer_certificate_id.is_defined());
487 }
488 }
489 }
490
hbos2fa7c672016-10-24 04:00:05 -0700491 void ExpectReportContainsTransportStats(
492 const rtc::scoped_refptr<const RTCStatsReport>& report,
493 const cricket::TransportStats& transport,
494 const CertificateInfo* local_certinfo,
495 const CertificateInfo* remote_certinfo) {
496 std::string rtcp_transport_stats_id;
497 for (const auto& channel_stats : transport.channel_stats) {
498 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
499 rtcp_transport_stats_id = "RTCTransport_" + transport.transport_name +
500 "_" + rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTCP);
501 }
502 }
503 for (const auto& channel_stats : transport.channel_stats) {
504 const cricket::ConnectionInfo* best_connection_info = nullptr;
505 const RTCStats* stats = report->Get(
506 "RTCTransport_" + transport.transport_name + "_" +
507 rtc::ToString<>(channel_stats.component));
508 ASSERT_TRUE(stats);
509 const RTCTransportStats& transport_stats =
510 stats->cast_to<const RTCTransportStats>();
511 uint64_t bytes_sent = 0;
512 uint64_t bytes_received = 0;
513 for (const cricket::ConnectionInfo& info :
514 channel_stats.connection_infos) {
515 bytes_sent += info.sent_total_bytes;
516 bytes_received += info.recv_total_bytes;
517 if (info.best_connection)
518 best_connection_info = &info;
519 }
520 EXPECT_EQ(*transport_stats.bytes_sent, bytes_sent);
521 EXPECT_EQ(*transport_stats.bytes_received, bytes_received);
522 if (best_connection_info) {
523 EXPECT_EQ(*transport_stats.active_connection, true);
524 // TODO(hbos): Instead of testing how the ID looks, test that the
525 // corresponding pair's IP addresses are equal to the IP addresses of
526 // the |best_connection_info| data. crbug.com/653873
527 EXPECT_EQ(*transport_stats.selected_candidate_pair_id,
528 "RTCIceCandidatePair_" +
529 best_connection_info->local_candidate.id() + "_" +
530 best_connection_info->remote_candidate.id());
531 EXPECT_TRUE(report->Get(*transport_stats.selected_candidate_pair_id));
532 } else {
533 EXPECT_EQ(*transport_stats.active_connection, false);
534 EXPECT_FALSE(transport_stats.selected_candidate_pair_id.is_defined());
535 }
536 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
537 !rtcp_transport_stats_id.empty()) {
538 EXPECT_EQ(*transport_stats.rtcp_transport_stats_id,
539 rtcp_transport_stats_id);
540 } else {
541 EXPECT_FALSE(transport_stats.rtcp_transport_stats_id.is_defined());
542 }
543 if (local_certinfo && remote_certinfo) {
544 EXPECT_EQ(*transport_stats.local_certificate_id,
545 "RTCCertificate_" + local_certinfo->fingerprints[0]);
546 EXPECT_EQ(*transport_stats.remote_certificate_id,
547 "RTCCertificate_" + remote_certinfo->fingerprints[0]);
548 EXPECT_TRUE(report->Get(*transport_stats.local_certificate_id));
549 EXPECT_TRUE(report->Get(*transport_stats.remote_certificate_id));
550 } else {
551 EXPECT_FALSE(transport_stats.local_certificate_id.is_defined());
552 EXPECT_FALSE(transport_stats.remote_certificate_id.is_defined());
553 }
554 }
555 }
556
hboscc555c52016-10-18 12:48:31 -0700557 void ExpectReportContainsDataChannel(
558 const rtc::scoped_refptr<const RTCStatsReport>& report,
559 const DataChannel& data_channel) {
560 const RTCStats* stats = report->Get("RTCDataChannel_" +
561 rtc::ToString<>(data_channel.id()));
562 EXPECT_TRUE(stats);
563 const RTCDataChannelStats& data_channel_stats =
564 stats->cast_to<const RTCDataChannelStats>();
565 EXPECT_EQ(*data_channel_stats.label, data_channel.label());
566 EXPECT_EQ(*data_channel_stats.protocol, data_channel.protocol());
567 EXPECT_EQ(*data_channel_stats.datachannelid, data_channel.id());
568 EXPECT_EQ(*data_channel_stats.state,
569 DataStateToRTCDataChannelStateForTesting(data_channel.state()));
570 EXPECT_EQ(*data_channel_stats.messages_sent, data_channel.messages_sent());
571 EXPECT_EQ(*data_channel_stats.bytes_sent, data_channel.bytes_sent());
572 EXPECT_EQ(*data_channel_stats.messages_received,
573 data_channel.messages_received());
574 EXPECT_EQ(*data_channel_stats.bytes_received,
575 data_channel.bytes_received());
576 }
577
hbosc82f2e12016-09-05 01:36:50 -0700578 protected:
579 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_;
580 rtc::scoped_refptr<RTCStatsCollector> collector_;
581};
582
583TEST_F(RTCStatsCollectorTest, SingleCallback) {
584 rtc::scoped_refptr<const RTCStatsReport> result;
585 collector_->GetStatsReport(StatsCallback::Create(&result));
586 EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs);
587}
588
589TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
590 rtc::scoped_refptr<const RTCStatsReport> a;
591 rtc::scoped_refptr<const RTCStatsReport> b;
592 rtc::scoped_refptr<const RTCStatsReport> c;
593 collector_->GetStatsReport(StatsCallback::Create(&a));
594 collector_->GetStatsReport(StatsCallback::Create(&b));
595 collector_->GetStatsReport(StatsCallback::Create(&c));
596 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs);
597 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs);
598 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs);
599 EXPECT_EQ(a.get(), b.get());
600 EXPECT_EQ(b.get(), c.get());
601}
602
603TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
hbosd565b732016-08-30 14:04:35 -0700604 // Caching should ensure |a| and |b| are the same report.
hbosc82f2e12016-09-05 01:36:50 -0700605 rtc::scoped_refptr<const RTCStatsReport> a = GetStatsReport();
606 rtc::scoped_refptr<const RTCStatsReport> b = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700607 EXPECT_EQ(a.get(), b.get());
608 // Invalidate cache by clearing it.
hbosc82f2e12016-09-05 01:36:50 -0700609 collector_->ClearCachedStatsReport();
610 rtc::scoped_refptr<const RTCStatsReport> c = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700611 EXPECT_NE(b.get(), c.get());
612 // Invalidate cache by advancing time.
hbosfdafab82016-09-14 06:02:13 -0700613 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51));
hbosc82f2e12016-09-05 01:36:50 -0700614 rtc::scoped_refptr<const RTCStatsReport> d = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700615 EXPECT_TRUE(d);
616 EXPECT_NE(c.get(), d.get());
617}
618
hbosc82f2e12016-09-05 01:36:50 -0700619TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
hbosc82f2e12016-09-05 01:36:50 -0700620 rtc::scoped_refptr<const RTCStatsReport> a;
621 rtc::scoped_refptr<const RTCStatsReport> b;
622 rtc::scoped_refptr<const RTCStatsReport> c;
623 collector_->GetStatsReport(StatsCallback::Create(&a));
624 collector_->GetStatsReport(StatsCallback::Create(&b));
625 // Cache is invalidated after 50 ms.
hbosfdafab82016-09-14 06:02:13 -0700626 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51));
hbosc82f2e12016-09-05 01:36:50 -0700627 collector_->GetStatsReport(StatsCallback::Create(&c));
628 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs);
629 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs);
630 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs);
631 EXPECT_EQ(a.get(), b.get());
632 // The act of doing |AdvanceTime| processes all messages. If this was not the
633 // case we might not require |c| to be fresher than |b|.
634 EXPECT_NE(c.get(), b.get());
635}
636
hbos6ab97ce2016-10-03 14:16:56 -0700637TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
638 std::unique_ptr<CertificateInfo> local_certinfo =
639 CreateFakeCertificateAndInfoFromDers(
640 std::vector<std::string>({ "(local) single certificate" }));
641 std::unique_ptr<CertificateInfo> remote_certinfo =
642 CreateFakeCertificateAndInfoFromDers(
643 std::vector<std::string>({ "(remote) single certificate" }));
644
645 // Mock the session to return the local and remote certificates.
646 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
647 [this](SessionStats* stats) {
648 stats->transport_stats["transport"].transport_name = "transport";
649 return true;
650 }));
651 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
652 Invoke([this, &local_certinfo](const std::string& transport_name,
653 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
654 if (transport_name == "transport") {
655 *certificate = local_certinfo->certificate;
656 return true;
657 }
658 return false;
659 }));
660 EXPECT_CALL(test_->session(),
661 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
662 [this, &remote_certinfo](const std::string& transport_name) {
663 if (transport_name == "transport")
664 return remote_certinfo->certificate->ssl_certificate().GetReference();
665 return static_cast<rtc::SSLCertificate*>(nullptr);
666 }));
667
668 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
669 ExpectReportContainsCertificateInfo(report, *local_certinfo.get());
670 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
671}
672
673TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
674 std::unique_ptr<CertificateInfo> audio_local_certinfo =
675 CreateFakeCertificateAndInfoFromDers(
676 std::vector<std::string>({ "(local) audio" }));
677 audio_local_certinfo = CreateFakeCertificateAndInfoFromDers(
678 audio_local_certinfo->ders);
679 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
680 CreateFakeCertificateAndInfoFromDers(
681 std::vector<std::string>({ "(remote) audio" }));
682 audio_remote_certinfo = CreateFakeCertificateAndInfoFromDers(
683 audio_remote_certinfo->ders);
684
685 std::unique_ptr<CertificateInfo> video_local_certinfo =
686 CreateFakeCertificateAndInfoFromDers(
687 std::vector<std::string>({ "(local) video" }));
688 video_local_certinfo = CreateFakeCertificateAndInfoFromDers(
689 video_local_certinfo->ders);
690 std::unique_ptr<CertificateInfo> video_remote_certinfo =
691 CreateFakeCertificateAndInfoFromDers(
692 std::vector<std::string>({ "(remote) video" }));
693 video_remote_certinfo = CreateFakeCertificateAndInfoFromDers(
694 video_remote_certinfo->ders);
695
696 // Mock the session to return the local and remote certificates.
697 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
698 [this](SessionStats* stats) {
699 stats->transport_stats["audio"].transport_name = "audio";
700 stats->transport_stats["video"].transport_name = "video";
701 return true;
702 }));
703 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
704 Invoke([this, &audio_local_certinfo, &video_local_certinfo](
705 const std::string& transport_name,
706 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
707 if (transport_name == "audio") {
708 *certificate = audio_local_certinfo->certificate;
709 return true;
710 }
711 if (transport_name == "video") {
712 *certificate = video_local_certinfo->certificate;
713 return true;
714 }
715 return false;
716 }));
717 EXPECT_CALL(test_->session(),
718 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
719 [this, &audio_remote_certinfo, &video_remote_certinfo](
720 const std::string& transport_name) {
721 if (transport_name == "audio") {
722 return audio_remote_certinfo->certificate->ssl_certificate()
723 .GetReference();
724 }
725 if (transport_name == "video") {
726 return video_remote_certinfo->certificate->ssl_certificate()
727 .GetReference();
728 }
729 return static_cast<rtc::SSLCertificate*>(nullptr);
730 }));
731
732 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
733 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo.get());
734 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo.get());
735 ExpectReportContainsCertificateInfo(report, *video_local_certinfo.get());
736 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo.get());
737}
738
739TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
740 std::vector<std::string> local_ders;
741 local_ders.push_back("(local) this");
742 local_ders.push_back("(local) is");
743 local_ders.push_back("(local) a");
744 local_ders.push_back("(local) chain");
745 std::unique_ptr<CertificateInfo> local_certinfo =
746 CreateFakeCertificateAndInfoFromDers(local_ders);
747 std::vector<std::string> remote_ders;
748 remote_ders.push_back("(remote) this");
749 remote_ders.push_back("(remote) is");
750 remote_ders.push_back("(remote) another");
751 remote_ders.push_back("(remote) chain");
752 std::unique_ptr<CertificateInfo> remote_certinfo =
753 CreateFakeCertificateAndInfoFromDers(remote_ders);
754
755 // Mock the session to return the local and remote certificates.
756 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
757 [this](SessionStats* stats) {
758 stats->transport_stats["transport"].transport_name = "transport";
759 return true;
760 }));
761 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
762 Invoke([this, &local_certinfo](const std::string& transport_name,
763 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
764 if (transport_name == "transport") {
765 *certificate = local_certinfo->certificate;
766 return true;
767 }
768 return false;
769 }));
770 EXPECT_CALL(test_->session(),
771 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
772 [this, &remote_certinfo](const std::string& transport_name) {
773 if (transport_name == "transport")
774 return remote_certinfo->certificate->ssl_certificate().GetReference();
775 return static_cast<rtc::SSLCertificate*>(nullptr);
776 }));
777
778 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
779 ExpectReportContainsCertificateInfo(report, *local_certinfo.get());
780 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
781}
782
hboscc555c52016-10-18 12:48:31 -0700783TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
784 test_->data_channels().push_back(
785 new MockDataChannel(0, DataChannelInterface::kConnecting));
786 test_->data_channels().push_back(
787 new MockDataChannel(1, DataChannelInterface::kOpen));
788 test_->data_channels().push_back(
789 new MockDataChannel(2, DataChannelInterface::kClosing));
790 test_->data_channels().push_back(
791 new MockDataChannel(3, DataChannelInterface::kClosed));
792
793 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
794 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
795 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
796 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
797 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
798
799 test_->data_channels().clear();
800 test_->data_channels().push_back(
801 new MockDataChannel(0, DataChannelInterface::kConnecting,
802 1, 2, 3, 4));
803 test_->data_channels().push_back(
804 new MockDataChannel(1, DataChannelInterface::kOpen,
805 5, 6, 7, 8));
806 test_->data_channels().push_back(
807 new MockDataChannel(2, DataChannelInterface::kClosing,
808 9, 10, 11, 12));
809 test_->data_channels().push_back(
810 new MockDataChannel(3, DataChannelInterface::kClosed,
811 13, 14, 15, 16));
812
813 collector_->ClearCachedStatsReport();
814 report = GetStatsReport();
815 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
816 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
817 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
818 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
819}
820
hbosab9f6e42016-10-07 02:18:47 -0700821TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
822 // Candidates in the first transport stats.
823 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
824 "1.2.3.4", 5,
825 "a_local_host's protocol",
826 cricket::LOCAL_PORT_TYPE,
827 0);
828 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
829 "6.7.8.9", 10,
830 "remote_srflx's protocol",
831 cricket::STUN_PORT_TYPE,
832 1);
833 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
834 "11.12.13.14", 15,
835 "a_local_prflx's protocol",
836 cricket::PRFLX_PORT_TYPE,
837 2);
838 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
839 "16.17.18.19", 20,
840 "a_remote_relay's protocol",
841 cricket::RELAY_PORT_TYPE,
842 3);
843 // Candidates in the second transport stats.
844 std::unique_ptr<cricket::Candidate> b_local = CreateFakeCandidate(
845 "42.42.42.42", 42,
846 "b_local's protocol",
847 cricket::LOCAL_PORT_TYPE,
848 42);
849 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
850 "42.42.42.42", 42,
851 "b_remote's protocol",
852 cricket::LOCAL_PORT_TYPE,
853 42);
854
855 SessionStats session_stats;
856
857 cricket::TransportChannelStats a_transport_channel_stats;
858 a_transport_channel_stats.connection_infos.push_back(
859 cricket::ConnectionInfo());
860 a_transport_channel_stats.connection_infos[0].local_candidate =
861 *a_local_host.get();
862 a_transport_channel_stats.connection_infos[0].remote_candidate =
863 *a_remote_srflx.get();
864 a_transport_channel_stats.connection_infos.push_back(
865 cricket::ConnectionInfo());
866 a_transport_channel_stats.connection_infos[1].local_candidate =
867 *a_local_prflx.get();
868 a_transport_channel_stats.connection_infos[1].remote_candidate =
869 *a_remote_relay.get();
870 session_stats.transport_stats["a"].channel_stats.push_back(
871 a_transport_channel_stats);
872
873 cricket::TransportChannelStats b_transport_channel_stats;
874 b_transport_channel_stats.connection_infos.push_back(
875 cricket::ConnectionInfo());
876 b_transport_channel_stats.connection_infos[0].local_candidate =
877 *b_local.get();
878 b_transport_channel_stats.connection_infos[0].remote_candidate =
879 *b_remote.get();
880 session_stats.transport_stats["b"].channel_stats.push_back(
881 b_transport_channel_stats);
882
883 // Mock the session to return the desired candidates.
884 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
885 [this, &session_stats](SessionStats* stats) {
886 *stats = session_stats;
887 return true;
888 }));
889
890 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
891 ExpectReportContainsCandidate(report, *a_local_host.get(), true);
892 ExpectReportContainsCandidate(report, *a_remote_srflx.get(), false);
893 ExpectReportContainsCandidate(report, *a_local_prflx.get(), true);
894 ExpectReportContainsCandidate(report, *a_remote_relay.get(), false);
895 ExpectReportContainsCandidate(report, *b_local.get(), true);
896 ExpectReportContainsCandidate(report, *b_remote.get(), false);
897}
898
hbosc47a0c32016-10-11 14:54:49 -0700899TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
900 std::unique_ptr<cricket::Candidate> local_candidate = CreateFakeCandidate(
901 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
902 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
903 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
904
905 SessionStats session_stats;
906
907 cricket::ConnectionInfo connection_info;
908 connection_info.local_candidate = *local_candidate.get();
909 connection_info.remote_candidate = *remote_candidate.get();
910 connection_info.writable = true;
911 connection_info.sent_total_bytes = 42;
912 connection_info.recv_total_bytes = 1234;
913 connection_info.rtt = 1337;
914 connection_info.sent_ping_requests_total = 1010;
915 connection_info.recv_ping_responses = 4321;
916 connection_info.sent_ping_responses = 1000;
917
918 cricket::TransportChannelStats transport_channel_stats;
919 transport_channel_stats.connection_infos.push_back(connection_info);
920 session_stats.transport_stats["transport"].transport_name = "transport";
921 session_stats.transport_stats["transport"].channel_stats.push_back(
922 transport_channel_stats);
923
924 // Mock the session to return the desired candidates.
925 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
926 [this, &session_stats](SessionStats* stats) {
927 *stats = session_stats;
928 return true;
929 }));
930
931 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
932 ExpectReportContainsCandidatePair(
933 report, session_stats.transport_stats["transport"]);
934}
935
hbosd565b732016-08-30 14:04:35 -0700936TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosc82f2e12016-09-05 01:36:50 -0700937 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700938 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(),
939 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats.";
940 const RTCStats* stats = report->Get("RTCPeerConnection");
941 EXPECT_TRUE(stats);
hbosd565b732016-08-30 14:04:35 -0700942 {
943 // Expected stats with no data channels
944 const RTCPeerConnectionStats& pcstats =
945 stats->cast_to<RTCPeerConnectionStats>();
946 EXPECT_EQ(*pcstats.data_channels_opened, static_cast<uint32_t>(0));
947 EXPECT_EQ(*pcstats.data_channels_closed, static_cast<uint32_t>(0));
948 }
949
950 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700951 new MockDataChannel(0, DataChannelInterface::kConnecting));
hbosd565b732016-08-30 14:04:35 -0700952 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700953 new MockDataChannel(1, DataChannelInterface::kOpen));
hbosd565b732016-08-30 14:04:35 -0700954 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700955 new MockDataChannel(2, DataChannelInterface::kClosing));
hbosd565b732016-08-30 14:04:35 -0700956 test_->data_channels().push_back(
hboscc555c52016-10-18 12:48:31 -0700957 new MockDataChannel(3, DataChannelInterface::kClosed));
hbosd565b732016-08-30 14:04:35 -0700958
hbosc82f2e12016-09-05 01:36:50 -0700959 collector_->ClearCachedStatsReport();
960 report = GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700961 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(),
962 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats.";
963 stats = report->Get("RTCPeerConnection");
hbos2fa7c672016-10-24 04:00:05 -0700964 ASSERT_TRUE(stats);
hbosd565b732016-08-30 14:04:35 -0700965 {
966 // Expected stats with the above four data channels
967 // TODO(hbos): When the |RTCPeerConnectionStats| is the number of data
968 // channels that have been opened and closed, not the numbers currently
969 // open/closed, we would expect opened >= closed and (opened - closed) to be
970 // the number currently open. crbug.com/636818.
971 const RTCPeerConnectionStats& pcstats =
972 stats->cast_to<RTCPeerConnectionStats>();
973 EXPECT_EQ(*pcstats.data_channels_opened, static_cast<uint32_t>(1));
974 EXPECT_EQ(*pcstats.data_channels_closed, static_cast<uint32_t>(3));
975 }
976}
977
hbos6ded1902016-11-01 01:50:46 -0700978TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
979 MockVoiceMediaChannel* voice_media_channel = new MockVoiceMediaChannel();
980 cricket::VoiceChannel voice_channel(
981 test_->worker_thread(), test_->network_thread(), test_->media_engine(),
982 voice_media_channel, nullptr, "VoiceContentName", false);
983
984 cricket::VoiceMediaInfo voice_media_info;
985 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
986 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
987 voice_media_info.senders[0].local_stats[0].ssrc = 1;
988 voice_media_info.senders[0].packets_sent = 2;
989 voice_media_info.senders[0].bytes_sent = 3;
990 voice_media_info.senders[0].rtt_ms = 4500.0;
991 EXPECT_CALL(*voice_media_channel, GetStats(_))
992 .WillOnce(DoAll(SetArgPointee<0>(voice_media_info), Return(true)));
993
994 SessionStats session_stats;
995 session_stats.proxy_to_transport["VoiceContentName"] = "TransportName";
996 session_stats.transport_stats["TransportName"].transport_name =
997 "TransportName";
998
999 // Make sure the associated |RTCTransportStats| is created.
1000 cricket::TransportChannelStats channel_stats;
1001 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1002 cricket::ConnectionInfo connection_info;
1003 connection_info.local_candidate = *CreateFakeCandidate(
1004 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42).get();
1005 connection_info.remote_candidate = *CreateFakeCandidate(
1006 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42).get();
1007 channel_stats.connection_infos.push_back(connection_info);
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 RTCOutboundRTPStreamStats expected_audio(
1019 "RTCOutboundRTPAudioStream_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_sent = 2;
1026 expected_audio.bytes_sent = 3;
1027 expected_audio.round_trip_time = 4.5;
1028
1029 ASSERT(report->Get(expected_audio.id()));
1030 const RTCOutboundRTPStreamStats& audio = report->Get(
1031 expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>();
1032 EXPECT_EQ(audio, expected_audio);
1033
1034 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
1035}
1036
1037TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
1038 MockVideoMediaChannel* video_media_channel = new MockVideoMediaChannel();
1039 cricket::VideoChannel video_channel(
1040 test_->worker_thread(), test_->network_thread(), video_media_channel,
1041 nullptr, "VideoContentName", false);
1042
1043 cricket::VideoMediaInfo video_media_info;
1044 video_media_info.senders.push_back(cricket::VideoSenderInfo());
1045 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
1046 video_media_info.senders[0].local_stats[0].ssrc = 1;
1047 video_media_info.senders[0].firs_rcvd = 2;
1048 video_media_info.senders[0].plis_rcvd = 3;
1049 video_media_info.senders[0].nacks_rcvd = 4;
1050 video_media_info.senders[0].packets_sent = 5;
1051 video_media_info.senders[0].bytes_sent = 6;
1052 video_media_info.senders[0].rtt_ms = 7500.0;
1053 EXPECT_CALL(*video_media_channel, GetStats(_))
1054 .WillOnce(DoAll(SetArgPointee<0>(video_media_info), Return(true)));
1055
1056 SessionStats session_stats;
1057 session_stats.proxy_to_transport["VideoContentName"] = "TransportName";
1058 session_stats.transport_stats["TransportName"].transport_name =
1059 "TransportName";
1060
1061 // Make sure the associated |RTCTransportStats| is created.
1062 cricket::TransportChannelStats channel_stats;
1063 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1064 cricket::ConnectionInfo connection_info;
1065 connection_info.local_candidate = *CreateFakeCandidate(
1066 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42).get();
1067 connection_info.remote_candidate = *CreateFakeCandidate(
1068 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42).get();
1069 channel_stats.connection_infos.push_back(connection_info);
1070 session_stats.transport_stats["TransportName"].channel_stats.push_back(
1071 channel_stats);
1072
1073 EXPECT_CALL(test_->session(), GetTransportStats(_))
1074 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true)));
1075 EXPECT_CALL(test_->session(), video_channel())
1076 .WillRepeatedly(Return(&video_channel));
1077
1078 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1079
1080 RTCOutboundRTPStreamStats expected_video(
1081 "RTCOutboundRTPVideoStream_1", report->timestamp_us());
1082 expected_video.ssrc = "1";
1083 expected_video.is_remote = false;
1084 expected_video.media_type = "video";
1085 expected_video.transport_id = "RTCTransport_TransportName_" +
1086 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1087 expected_video.fir_count = 2;
1088 expected_video.pli_count = 3;
1089 expected_video.nack_count = 4;
1090 expected_video.packets_sent = 5;
1091 expected_video.bytes_sent = 6;
1092 expected_video.round_trip_time = 7.5;
1093
1094 ASSERT(report->Get(expected_video.id()));
1095 const RTCOutboundRTPStreamStats& video = report->Get(
1096 expected_video.id())->cast_to<RTCOutboundRTPStreamStats>();
1097 EXPECT_EQ(video, expected_video);
1098
1099 EXPECT_TRUE(report->Get(*expected_video.transport_id));
1100}
1101
hbos2fa7c672016-10-24 04:00:05 -07001102TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
1103 std::unique_ptr<cricket::Candidate> rtp_local_candidate = CreateFakeCandidate(
1104 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
1105 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
1106 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1107 cricket::LOCAL_PORT_TYPE, 42);
1108 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
1109 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1110 cricket::LOCAL_PORT_TYPE, 42);
1111 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
1112 CreateFakeCandidate("42.42.42.42", 42, "protocol",
1113 cricket::LOCAL_PORT_TYPE, 42);
1114
1115 SessionStats session_stats;
1116 session_stats.transport_stats["transport"].transport_name = "transport";
1117
1118 cricket::ConnectionInfo rtp_connection_info;
1119 rtp_connection_info.best_connection = false;
1120 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
1121 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
1122 rtp_connection_info.sent_total_bytes = 42;
1123 rtp_connection_info.recv_total_bytes = 1337;
1124 cricket::TransportChannelStats rtp_transport_channel_stats;
1125 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1126 rtp_transport_channel_stats.connection_infos.push_back(rtp_connection_info);
1127 session_stats.transport_stats["transport"].channel_stats.push_back(
1128 rtp_transport_channel_stats);
1129
1130
1131 // Mock the session to return the desired candidates.
1132 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
1133 [this, &session_stats](SessionStats* stats) {
1134 *stats = session_stats;
1135 return true;
1136 }));
1137
1138 // Get stats without RTCP, an active connection or certificates.
1139 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
1140 ExpectReportContainsTransportStats(
1141 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1142
1143 cricket::ConnectionInfo rtcp_connection_info;
1144 rtcp_connection_info.best_connection = false;
1145 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
1146 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
1147 rtcp_connection_info.sent_total_bytes = 1337;
1148 rtcp_connection_info.recv_total_bytes = 42;
1149 cricket::TransportChannelStats rtcp_transport_channel_stats;
1150 rtcp_transport_channel_stats.component =
1151 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
1152 rtcp_transport_channel_stats.connection_infos.push_back(rtcp_connection_info);
1153 session_stats.transport_stats["transport"].channel_stats.push_back(
1154 rtcp_transport_channel_stats);
1155
1156 collector_->ClearCachedStatsReport();
1157 // Get stats with RTCP and without an active connection or certificates.
1158 report = GetStatsReport();
1159 ExpectReportContainsTransportStats(
1160 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1161
1162 // Get stats with an active connection.
1163 rtcp_connection_info.best_connection = true;
1164
1165 collector_->ClearCachedStatsReport();
1166 report = GetStatsReport();
1167 ExpectReportContainsTransportStats(
1168 report, session_stats.transport_stats["transport"], nullptr, nullptr);
1169
1170 // Get stats with certificates.
1171 std::unique_ptr<CertificateInfo> local_certinfo =
1172 CreateFakeCertificateAndInfoFromDers(
1173 std::vector<std::string>({ "(local) local", "(local) chain" }));
1174 std::unique_ptr<CertificateInfo> remote_certinfo =
1175 CreateFakeCertificateAndInfoFromDers(
1176 std::vector<std::string>({ "(remote) local", "(remote) chain" }));
1177 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly(
1178 Invoke([this, &local_certinfo](const std::string& transport_name,
1179 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
1180 if (transport_name == "transport") {
1181 *certificate = local_certinfo->certificate;
1182 return true;
1183 }
1184 return false;
1185 }));
1186 EXPECT_CALL(test_->session(),
1187 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke(
1188 [this, &remote_certinfo](const std::string& transport_name) {
1189 if (transport_name == "transport")
1190 return remote_certinfo->certificate->ssl_certificate().GetReference();
1191 return static_cast<rtc::SSLCertificate*>(nullptr);
1192 }));
1193
1194 collector_->ClearCachedStatsReport();
1195 report = GetStatsReport();
1196 ExpectReportContainsTransportStats(
1197 report, session_stats.transport_stats["transport"],
1198 local_certinfo.get(), remote_certinfo.get());
1199}
1200
hbosc82f2e12016-09-05 01:36:50 -07001201class RTCStatsCollectorTestWithFakeCollector : public testing::Test {
1202 public:
1203 RTCStatsCollectorTestWithFakeCollector()
1204 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()),
1205 collector_(FakeRTCStatsCollector::Create(
1206 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) {
1207 }
1208
1209 protected:
1210 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_;
1211 rtc::scoped_refptr<FakeRTCStatsCollector> collector_;
1212};
1213
1214TEST_F(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
1215 collector_->VerifyThreadUsageAndResultsMerging();
1216}
1217
1218} // namespace
1219
hbosd565b732016-08-30 14:04:35 -07001220} // namespace webrtc