blob: a498dc84db8974322a34ebf53c074ae982243333 [file] [log] [blame]
hbosdb346a72016-11-29 09:57:011/*
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
11#include <set>
12#include <vector>
13
Mirko Bonadei92ea95e2017-09-15 04:47:3114#include "api/audio_codecs/builtin_audio_decoder_factory.h"
15#include "api/audio_codecs/builtin_audio_encoder_factory.h"
16#include "api/datachannelinterface.h"
17#include "api/peerconnectioninterface.h"
18#include "api/stats/rtcstats_objects.h"
19#include "api/stats/rtcstatsreport.h"
20#include "pc/test/peerconnectiontestwrapper.h"
21#include "pc/test/rtcstatsobtainer.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/event_tracer.h"
24#include "rtc_base/gunit.h"
25#include "rtc_base/refcountedobject.h"
26#include "rtc_base/scoped_ref_ptr.h"
27#include "rtc_base/trace_event.h"
28#include "rtc_base/virtualsocketserver.h"
hbosdb346a72016-11-29 09:57:0129
30namespace webrtc {
31
32namespace {
33
34const int64_t kGetStatsTimeoutMs = 10000;
35
ehmaldonado80c829f2017-07-18 14:35:1936const unsigned char* GetCategoryEnabledHandler(const char* name) {
ehmaldonado8ab0fd82017-09-04 21:35:0437 if (strcmp("webrtc_stats", name) != 0) {
38 return reinterpret_cast<const unsigned char*>("");
39 }
40 return reinterpret_cast<const unsigned char*>(name);
ehmaldonado80c829f2017-07-18 14:35:1941}
42
ehmaldonado8ab0fd82017-09-04 21:35:0443class RTCStatsReportTraceListener {
44 public:
45 static void SetUp() {
46 if (!traced_report_)
47 traced_report_ = new RTCStatsReportTraceListener();
48 traced_report_->last_trace_ = "";
49 SetupEventTracer(&GetCategoryEnabledHandler,
50 &RTCStatsReportTraceListener::AddTraceEventHandler);
51 }
52
53 static const std::string& last_trace() {
54 RTC_DCHECK(traced_report_);
55 return traced_report_->last_trace_;
56 }
57
58 private:
59 static void AddTraceEventHandler(char phase,
60 const unsigned char* category_enabled,
61 const char* name,
62 unsigned long long id,
63 int num_args,
64 const char** arg_names,
65 const unsigned char* arg_types,
66 const unsigned long long* arg_values,
67 unsigned char flags) {
68 RTC_DCHECK(traced_report_);
69 EXPECT_STREQ("webrtc_stats",
70 reinterpret_cast<const char*>(category_enabled));
71 EXPECT_STREQ("webrtc_stats", name);
72 EXPECT_EQ(1, num_args);
73 EXPECT_STREQ("report", arg_names[0]);
74 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, arg_types[0]);
75
76 traced_report_->last_trace_ = reinterpret_cast<const char*>(arg_values[0]);
77 }
78
79 static RTCStatsReportTraceListener* traced_report_;
80 std::string last_trace_;
81};
82
83RTCStatsReportTraceListener* RTCStatsReportTraceListener::traced_report_ =
84 nullptr;
ehmaldonado80c829f2017-07-18 14:35:1985
hbosdb346a72016-11-29 09:57:0186class RTCStatsIntegrationTest : public testing::Test {
87 public:
88 RTCStatsIntegrationTest()
tommie7251592017-07-14 21:44:4689 : network_thread_(new rtc::Thread(&virtual_socket_server_)),
90 worker_thread_(rtc::Thread::Create()) {
ehmaldonado8ab0fd82017-09-04 21:35:0491 RTCStatsReportTraceListener::SetUp();
ehmaldonado80c829f2017-07-18 14:35:1992
tommie7251592017-07-14 21:44:4693 RTC_CHECK(network_thread_->Start());
94 RTC_CHECK(worker_thread_->Start());
hbosdb346a72016-11-29 09:57:0195
96 caller_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommie7251592017-07-14 21:44:4697 "caller", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 09:57:0198 callee_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommie7251592017-07-14 21:44:4699 "callee", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 09:57:01100 }
101
102 void StartCall() {
103 // Create PeerConnections and "connect" sigslots
104 PeerConnectionInterface::RTCConfiguration config;
105 PeerConnectionInterface::IceServer ice_server;
106 ice_server.uri = "stun:1.1.1.1:3478";
107 config.servers.push_back(ice_server);
kwiberg9e5b11e2017-04-19 10:47:57108 EXPECT_TRUE(caller_->CreatePc(nullptr, config,
109 CreateBuiltinAudioEncoderFactory(),
110 CreateBuiltinAudioDecoderFactory()));
111 EXPECT_TRUE(callee_->CreatePc(nullptr, config,
112 CreateBuiltinAudioEncoderFactory(),
113 CreateBuiltinAudioDecoderFactory()));
hbosdb346a72016-11-29 09:57:01114 PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get());
115
116 // Get user media for audio and video
117 caller_->GetAndAddUserMedia(true, FakeConstraints(),
118 true, FakeConstraints());
119 callee_->GetAndAddUserMedia(true, FakeConstraints(),
120 true, FakeConstraints());
121
122 // Create data channels
123 DataChannelInit init;
124 caller_->CreateDataChannel("data", init);
125 callee_->CreateDataChannel("data", init);
126
127 // Negotiate and wait for call to establish
128 caller_->CreateOffer(nullptr);
129 caller_->WaitForCallEstablished();
130 callee_->WaitForCallEstablished();
131 }
132
133 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCaller() {
134 return GetStats(caller_->pc());
135 }
136
137 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCallee() {
138 return GetStats(callee_->pc());
139 }
140
141 protected:
142 static rtc::scoped_refptr<const RTCStatsReport> GetStats(
143 PeerConnectionInterface* pc) {
144 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer =
145 RTCStatsObtainer::Create();
146 pc->GetStats(stats_obtainer);
147 EXPECT_TRUE_WAIT(stats_obtainer->report(), kGetStatsTimeoutMs);
148 return stats_obtainer->report();
149 }
150
deadbeef98e186c2017-05-17 01:00:06151 // |network_thread_| uses |virtual_socket_server_| so they must be
152 // constructed/destructed in the correct order.
hbosdb346a72016-11-29 09:57:01153 rtc::VirtualSocketServer virtual_socket_server_;
tommie7251592017-07-14 21:44:46154 std::unique_ptr<rtc::Thread> network_thread_;
155 std::unique_ptr<rtc::Thread> worker_thread_;
hbosdb346a72016-11-29 09:57:01156 rtc::scoped_refptr<PeerConnectionTestWrapper> caller_;
157 rtc::scoped_refptr<PeerConnectionTestWrapper> callee_;
158};
159
160class RTCStatsVerifier {
161 public:
162 RTCStatsVerifier(const RTCStatsReport* report, const RTCStats* stats)
163 : report_(report), stats_(stats), all_tests_successful_(true) {
164 RTC_CHECK(report_);
165 RTC_CHECK(stats_);
166 for (const RTCStatsMemberInterface* member : stats_->Members()) {
167 untested_members_.insert(member);
168 }
169 }
170
171 void MarkMemberTested(
172 const RTCStatsMemberInterface& member, bool test_successful) {
173 untested_members_.erase(&member);
174 all_tests_successful_ &= test_successful;
175 }
176
177 void TestMemberIsDefined(const RTCStatsMemberInterface& member) {
178 EXPECT_TRUE(member.is_defined()) <<
hbos23351192017-01-02 14:52:19179 stats_->type() << "." << member.name() << "[" << stats_->id() <<
180 "] was undefined.";
hbosdb346a72016-11-29 09:57:01181 MarkMemberTested(member, member.is_defined());
182 }
183
184 void TestMemberIsUndefined(const RTCStatsMemberInterface& member) {
185 EXPECT_FALSE(member.is_defined()) <<
hbos23351192017-01-02 14:52:19186 stats_->type() << "." << member.name() << "[" << stats_->id() <<
187 "] was defined (" << member.ValueToString() << ").";
hbosdb346a72016-11-29 09:57:01188 MarkMemberTested(member, !member.is_defined());
189 }
190
hbos23351192017-01-02 14:52:19191 template<typename T>
192 void TestMemberIsPositive(const RTCStatsMemberInterface& member) {
193 EXPECT_TRUE(member.is_defined()) <<
194 stats_->type() << "." << member.name() << "[" << stats_->id() <<
195 "] was undefined.";
196 if (!member.is_defined()) {
197 MarkMemberTested(member, false);
198 return;
199 }
200 bool is_positive = *member.cast_to<RTCStatsMember<T>>() > T(0);
201 EXPECT_TRUE(is_positive) <<
202 stats_->type() << "." << member.name() << "[" << stats_->id() <<
203 "] was not positive (" << member.ValueToString() << ").";
204 MarkMemberTested(member, is_positive);
205 }
206
207 template<typename T>
208 void TestMemberIsNonNegative(const RTCStatsMemberInterface& member) {
209 EXPECT_TRUE(member.is_defined()) <<
210 stats_->type() << "." << member.name() << "[" << stats_->id() <<
211 "] was undefined.";
212 if (!member.is_defined()) {
213 MarkMemberTested(member, false);
214 return;
215 }
216 bool is_non_negative = *member.cast_to<RTCStatsMember<T>>() >= T(0);
217 EXPECT_TRUE(is_non_negative) <<
218 stats_->type() << "." << member.name() << "[" << stats_->id() <<
219 "] was not non-negative (" << member.ValueToString() << ").";
220 MarkMemberTested(member, is_non_negative);
221 }
222
hbosdb346a72016-11-29 09:57:01223 void TestMemberIsIDReference(
224 const RTCStatsMemberInterface& member,
225 const char* expected_type) {
226 TestMemberIsIDReference(member, expected_type, false);
227 }
228
229 void TestMemberIsOptionalIDReference(
230 const RTCStatsMemberInterface& member,
231 const char* expected_type) {
232 TestMemberIsIDReference(member, expected_type, true);
233 }
234
235 bool ExpectAllMembersSuccessfullyTested() {
236 if (untested_members_.empty())
237 return all_tests_successful_;
238 for (const RTCStatsMemberInterface* member : untested_members_) {
239 EXPECT_TRUE(false) <<
240 stats_->type() << "." << member->name() << "[" << stats_->id() <<
241 "] was not tested.";
242 }
243 return false;
244 }
245
246 private:
247 void TestMemberIsIDReference(
248 const RTCStatsMemberInterface& member,
249 const char* expected_type,
250 bool optional) {
251 if (optional && !member.is_defined()) {
252 MarkMemberTested(member, true);
253 return;
254 }
255 bool valid_reference = false;
256 if (member.is_defined()) {
257 if (member.type() == RTCStatsMemberInterface::kString) {
258 // A single ID.
259 const RTCStatsMember<std::string>& id =
260 member.cast_to<RTCStatsMember<std::string>>();
261 const RTCStats* referenced_stats = report_->Get(*id);
262 valid_reference =
263 referenced_stats && referenced_stats->type() == expected_type;
264 } else if (member.type() == RTCStatsMemberInterface::kSequenceString) {
265 // A vector of IDs.
266 valid_reference = true;
267 const RTCStatsMember<std::vector<std::string>>& ids =
268 member.cast_to<RTCStatsMember<std::vector<std::string>>>();
269 for (const std::string id : *ids) {
270 const RTCStats* referenced_stats = report_->Get(id);
271 if (!referenced_stats || referenced_stats->type() != expected_type) {
272 valid_reference = false;
273 break;
274 }
275 }
276 }
277 }
278 EXPECT_TRUE(valid_reference) <<
279 stats_->type() << "." << member.name() << " is not a reference to an " <<
280 "existing dictionary of type " << expected_type << " (" <<
281 member.ValueToString() << ").";
282 MarkMemberTested(member, valid_reference);
283 }
284
285 rtc::scoped_refptr<const RTCStatsReport> report_;
286 const RTCStats* stats_;
287 std::set<const RTCStatsMemberInterface*> untested_members_;
288 bool all_tests_successful_;
289};
290
291class RTCStatsReportVerifier {
292 public:
293 static std::set<const char*> StatsTypes() {
294 std::set<const char*> stats_types;
295 stats_types.insert(RTCCertificateStats::kType);
296 stats_types.insert(RTCCodecStats::kType);
297 stats_types.insert(RTCDataChannelStats::kType);
298 stats_types.insert(RTCIceCandidatePairStats::kType);
299 stats_types.insert(RTCLocalIceCandidateStats::kType);
300 stats_types.insert(RTCRemoteIceCandidateStats::kType);
301 stats_types.insert(RTCMediaStreamStats::kType);
302 stats_types.insert(RTCMediaStreamTrackStats::kType);
303 stats_types.insert(RTCPeerConnectionStats::kType);
304 stats_types.insert(RTCInboundRTPStreamStats::kType);
305 stats_types.insert(RTCOutboundRTPStreamStats::kType);
306 stats_types.insert(RTCTransportStats::kType);
307 return stats_types;
308 }
309
310 explicit RTCStatsReportVerifier(const RTCStatsReport* report)
311 : report_(report) {
312 }
313
314 void VerifyReport() {
315 std::set<const char*> missing_stats = StatsTypes();
316 bool verify_successful = true;
hbos338f78a2017-02-07 14:41:21317 std::vector<const RTCTransportStats*> transport_stats =
318 report_->GetStatsOfType<RTCTransportStats>();
319 EXPECT_EQ(transport_stats.size(), 1);
320 std::string selected_candidate_pair_id =
321 *transport_stats[0]->selected_candidate_pair_id;
hbosdb346a72016-11-29 09:57:01322 for (const RTCStats& stats : *report_) {
323 missing_stats.erase(stats.type());
324 if (stats.type() == RTCCertificateStats::kType) {
325 verify_successful &= VerifyRTCCertificateStats(
326 stats.cast_to<RTCCertificateStats>());
327 } else if (stats.type() == RTCCodecStats::kType) {
328 verify_successful &= VerifyRTCCodecStats(
329 stats.cast_to<RTCCodecStats>());
330 } else if (stats.type() == RTCDataChannelStats::kType) {
331 verify_successful &= VerifyRTCDataChannelStats(
332 stats.cast_to<RTCDataChannelStats>());
333 } else if (stats.type() == RTCIceCandidatePairStats::kType) {
334 verify_successful &= VerifyRTCIceCandidatePairStats(
hbos338f78a2017-02-07 14:41:21335 stats.cast_to<RTCIceCandidatePairStats>(),
336 stats.id() == selected_candidate_pair_id);
hbosdb346a72016-11-29 09:57:01337 } else if (stats.type() == RTCLocalIceCandidateStats::kType) {
338 verify_successful &= VerifyRTCLocalIceCandidateStats(
339 stats.cast_to<RTCLocalIceCandidateStats>());
340 } else if (stats.type() == RTCRemoteIceCandidateStats::kType) {
341 verify_successful &= VerifyRTCRemoteIceCandidateStats(
342 stats.cast_to<RTCRemoteIceCandidateStats>());
343 } else if (stats.type() == RTCMediaStreamStats::kType) {
344 verify_successful &= VerifyRTCMediaStreamStats(
345 stats.cast_to<RTCMediaStreamStats>());
346 } else if (stats.type() == RTCMediaStreamTrackStats::kType) {
347 verify_successful &= VerifyRTCMediaStreamTrackStats(
348 stats.cast_to<RTCMediaStreamTrackStats>());
349 } else if (stats.type() == RTCPeerConnectionStats::kType) {
350 verify_successful &= VerifyRTCPeerConnectionStats(
351 stats.cast_to<RTCPeerConnectionStats>());
352 } else if (stats.type() == RTCInboundRTPStreamStats::kType) {
353 verify_successful &= VerifyRTCInboundRTPStreamStats(
354 stats.cast_to<RTCInboundRTPStreamStats>());
355 } else if (stats.type() == RTCOutboundRTPStreamStats::kType) {
356 verify_successful &= VerifyRTCOutboundRTPStreamStats(
357 stats.cast_to<RTCOutboundRTPStreamStats>());
358 } else if (stats.type() == RTCTransportStats::kType) {
359 verify_successful &= VerifyRTCTransportStats(
360 stats.cast_to<RTCTransportStats>());
361 } else {
362 EXPECT_TRUE(false) << "Unrecognized stats type: " << stats.type();
363 verify_successful = false;
364 }
365 }
366 if (!missing_stats.empty()) {
367 verify_successful = false;
368 for (const char* missing : missing_stats) {
369 EXPECT_TRUE(false) << "Missing expected stats type: " << missing;
370 }
371 }
372 EXPECT_TRUE(verify_successful) <<
373 "One or more problems with the stats. This is the report:\n" <<
ehmaldonado35a872c2017-07-28 14:29:12374 report_->ToJson();
hbosdb346a72016-11-29 09:57:01375 }
376
377 bool VerifyRTCCertificateStats(
378 const RTCCertificateStats& certificate) {
379 RTCStatsVerifier verifier(report_, &certificate);
380 verifier.TestMemberIsDefined(certificate.fingerprint);
381 verifier.TestMemberIsDefined(certificate.fingerprint_algorithm);
382 verifier.TestMemberIsDefined(certificate.base64_certificate);
383 verifier.TestMemberIsOptionalIDReference(
384 certificate.issuer_certificate_id, RTCCertificateStats::kType);
385 return verifier.ExpectAllMembersSuccessfullyTested();
386 }
387
388 bool VerifyRTCCodecStats(
389 const RTCCodecStats& codec) {
390 RTCStatsVerifier verifier(report_, &codec);
391 verifier.TestMemberIsDefined(codec.payload_type);
hbos13f54b22017-02-28 14:56:04392 verifier.TestMemberIsDefined(codec.mime_type);
hbos23351192017-01-02 14:52:19393 verifier.TestMemberIsPositive<uint32_t>(codec.clock_rate);
hbosdb346a72016-11-29 09:57:01394 verifier.TestMemberIsUndefined(codec.channels);
hbos13f54b22017-02-28 14:56:04395 verifier.TestMemberIsUndefined(codec.sdp_fmtp_line);
hbosdb346a72016-11-29 09:57:01396 verifier.TestMemberIsUndefined(codec.implementation);
397 return verifier.ExpectAllMembersSuccessfullyTested();
398 }
399
400 bool VerifyRTCDataChannelStats(
401 const RTCDataChannelStats& data_channel) {
402 RTCStatsVerifier verifier(report_, &data_channel);
403 verifier.TestMemberIsDefined(data_channel.label);
404 verifier.TestMemberIsDefined(data_channel.protocol);
405 verifier.TestMemberIsDefined(data_channel.datachannelid);
406 verifier.TestMemberIsDefined(data_channel.state);
hbos23351192017-01-02 14:52:19407 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_sent);
408 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_sent);
409 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_received);
410 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_received);
hbosdb346a72016-11-29 09:57:01411 return verifier.ExpectAllMembersSuccessfullyTested();
412 }
413
414 bool VerifyRTCIceCandidatePairStats(
hbos338f78a2017-02-07 14:41:21415 const RTCIceCandidatePairStats& candidate_pair, bool is_selected_pair) {
hbosdb346a72016-11-29 09:57:01416 RTCStatsVerifier verifier(report_, &candidate_pair);
hbos0583b282016-11-30 09:50:14417 verifier.TestMemberIsIDReference(
418 candidate_pair.transport_id, RTCTransportStats::kType);
hbosdb346a72016-11-29 09:57:01419 verifier.TestMemberIsIDReference(
420 candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType);
421 verifier.TestMemberIsIDReference(
422 candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType);
hbos06495bc2017-01-02 16:08:18423 verifier.TestMemberIsDefined(candidate_pair.state);
424 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.priority);
hbos92eaec62017-02-27 09:38:08425 verifier.TestMemberIsDefined(candidate_pair.nominated);
hbosdb346a72016-11-29 09:57:01426 verifier.TestMemberIsDefined(candidate_pair.writable);
427 verifier.TestMemberIsUndefined(candidate_pair.readable);
hbos23351192017-01-02 14:52:19428 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_sent);
429 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_received);
hbosbf8d3e52017-02-28 14:34:47430 verifier.TestMemberIsNonNegative<double>(
431 candidate_pair.total_round_trip_time);
hbos23351192017-01-02 14:52:19432 verifier.TestMemberIsNonNegative<double>(
433 candidate_pair.current_round_trip_time);
hbos338f78a2017-02-07 14:41:21434 if (is_selected_pair) {
435 verifier.TestMemberIsNonNegative<double>(
436 candidate_pair.available_outgoing_bitrate);
deadbeef86c40a12017-06-28 16:37:23437 // A pair should be nominated in order to be selected.
438 EXPECT_TRUE(*candidate_pair.nominated);
hbos338f78a2017-02-07 14:41:21439 } else {
440 verifier.TestMemberIsUndefined(candidate_pair.available_outgoing_bitrate);
441 }
hbosdb346a72016-11-29 09:57:01442 verifier.TestMemberIsUndefined(candidate_pair.available_incoming_bitrate);
hbos23351192017-01-02 14:52:19443 verifier.TestMemberIsNonNegative<uint64_t>(
444 candidate_pair.requests_received);
445 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.requests_sent);
446 verifier.TestMemberIsNonNegative<uint64_t>(
447 candidate_pair.responses_received);
448 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.responses_sent);
hbosdb346a72016-11-29 09:57:01449 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_received);
450 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_sent);
451 verifier.TestMemberIsUndefined(candidate_pair.consent_requests_received);
hbos23351192017-01-02 14:52:19452 verifier.TestMemberIsNonNegative<uint64_t>(
453 candidate_pair.consent_requests_sent);
hbosdb346a72016-11-29 09:57:01454 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_received);
455 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_sent);
456 return verifier.ExpectAllMembersSuccessfullyTested();
457 }
458
459 bool VerifyRTCIceCandidateStats(
460 const RTCIceCandidateStats& candidate) {
461 RTCStatsVerifier verifier(report_, &candidate);
hbosb4e426e2017-01-02 17:59:31462 verifier.TestMemberIsIDReference(
463 candidate.transport_id, RTCTransportStats::kType);
hbosc3a2b7f2017-01-02 12:46:15464 verifier.TestMemberIsDefined(candidate.is_remote);
hbosdb346a72016-11-29 09:57:01465 verifier.TestMemberIsDefined(candidate.ip);
hbos23351192017-01-02 14:52:19466 verifier.TestMemberIsNonNegative<int32_t>(candidate.port);
hbosdb346a72016-11-29 09:57:01467 verifier.TestMemberIsDefined(candidate.protocol);
468 verifier.TestMemberIsDefined(candidate.candidate_type);
hbos23351192017-01-02 14:52:19469 verifier.TestMemberIsNonNegative<int32_t>(candidate.priority);
hbosdb346a72016-11-29 09:57:01470 verifier.TestMemberIsUndefined(candidate.url);
hbosd17a5a72017-01-02 16:09:59471 verifier.TestMemberIsDefined(candidate.deleted);
hbosdb346a72016-11-29 09:57:01472 return verifier.ExpectAllMembersSuccessfullyTested();
473 }
474
475 bool VerifyRTCLocalIceCandidateStats(
476 const RTCLocalIceCandidateStats& local_candidate) {
477 return VerifyRTCIceCandidateStats(local_candidate);
478 }
479
480 bool VerifyRTCRemoteIceCandidateStats(
481 const RTCRemoteIceCandidateStats& remote_candidate) {
482 return VerifyRTCIceCandidateStats(remote_candidate);
483 }
484
485 bool VerifyRTCMediaStreamStats(
486 const RTCMediaStreamStats& media_stream) {
487 RTCStatsVerifier verifier(report_, &media_stream);
488 verifier.TestMemberIsDefined(media_stream.stream_identifier);
489 verifier.TestMemberIsIDReference(
490 media_stream.track_ids, RTCMediaStreamTrackStats::kType);
491 return verifier.ExpectAllMembersSuccessfullyTested();
492 }
493
494 bool VerifyRTCMediaStreamTrackStats(
495 const RTCMediaStreamTrackStats& media_stream_track) {
496 RTCStatsVerifier verifier(report_, &media_stream_track);
497 verifier.TestMemberIsDefined(media_stream_track.track_identifier);
498 verifier.TestMemberIsDefined(media_stream_track.remote_source);
499 verifier.TestMemberIsDefined(media_stream_track.ended);
500 verifier.TestMemberIsDefined(media_stream_track.detached);
hbos160e4a72017-01-17 10:53:23501 verifier.TestMemberIsDefined(media_stream_track.kind);
hbosdb346a72016-11-29 09:57:01502 // Video or audio media stream track?
hbos160e4a72017-01-17 10:53:23503 if (*media_stream_track.kind == RTCMediaStreamTrackKind::kVideo) {
hbosdb346a72016-11-29 09:57:01504 // Video-only members
hbos9e302742017-01-20 10:47:10505 verifier.TestMemberIsNonNegative<uint32_t>(
506 media_stream_track.frame_width);
507 verifier.TestMemberIsNonNegative<uint32_t>(
508 media_stream_track.frame_height);
hbosdb346a72016-11-29 09:57:01509 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second);
hbos42f6d2f2017-01-20 11:56:50510 if (*media_stream_track.remote_source) {
hbosfefe0762017-01-20 14:14:25511 verifier.TestMemberIsUndefined(media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 11:56:50512 verifier.TestMemberIsNonNegative<uint32_t>(
513 media_stream_track.frames_received);
hbosf64941f2017-01-20 15:39:09514 verifier.TestMemberIsNonNegative<uint32_t>(
515 media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 15:21:55516 verifier.TestMemberIsNonNegative<uint32_t>(
517 media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 11:56:50518 } else {
hbosfefe0762017-01-20 14:14:25519 verifier.TestMemberIsNonNegative<uint32_t>(
520 media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 11:56:50521 verifier.TestMemberIsUndefined(media_stream_track.frames_received);
hbosf64941f2017-01-20 15:39:09522 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 15:21:55523 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 11:56:50524 }
hbosdb346a72016-11-29 09:57:01525 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted);
526 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost);
527 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost);
528 // Audio-only members should be undefined
529 verifier.TestMemberIsUndefined(media_stream_track.audio_level);
530 verifier.TestMemberIsUndefined(media_stream_track.echo_return_loss);
531 verifier.TestMemberIsUndefined(
532 media_stream_track.echo_return_loss_enhancement);
zsteine76bd3a2017-07-14 19:17:49533 verifier.TestMemberIsUndefined(media_stream_track.total_audio_energy);
534 verifier.TestMemberIsUndefined(media_stream_track.total_samples_duration);
hbosdb346a72016-11-29 09:57:01535 } else {
hbos42f6d2f2017-01-20 11:56:50536 RTC_DCHECK_EQ(*media_stream_track.kind,
537 RTCMediaStreamTrackKind::kAudio);
hbosdb346a72016-11-29 09:57:01538 // Video-only members should be undefined
539 verifier.TestMemberIsUndefined(media_stream_track.frame_width);
540 verifier.TestMemberIsUndefined(media_stream_track.frame_height);
541 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second);
542 verifier.TestMemberIsUndefined(media_stream_track.frames_sent);
543 verifier.TestMemberIsUndefined(media_stream_track.frames_received);
544 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded);
545 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped);
546 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted);
547 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost);
548 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost);
549 // Audio-only members
hbos9e302742017-01-20 10:47:10550 verifier.TestMemberIsNonNegative<double>(media_stream_track.audio_level);
zsteine76bd3a2017-07-14 19:17:49551 verifier.TestMemberIsNonNegative<double>(
552 media_stream_track.total_audio_energy);
553 verifier.TestMemberIsNonNegative<double>(
554 media_stream_track.total_samples_duration);
hbos2d4d6532017-01-20 12:16:41555 // TODO(hbos): |echo_return_loss| and |echo_return_loss_enhancement| are
556 // flaky on msan bot (sometimes defined, sometimes undefined). Should the
557 // test run until available or is there a way to have it always be
558 // defined? crbug.com/627816
559 verifier.MarkMemberTested(media_stream_track.echo_return_loss, true);
560 verifier.MarkMemberTested(
561 media_stream_track.echo_return_loss_enhancement, true);
hbosdb346a72016-11-29 09:57:01562 }
Steve Anton2dbc69f2017-08-25 00:15:13563 // totalSamplesReceived and concealedSamples are only present on inbound
564 // audio tracks.
565 if (*media_stream_track.kind == RTCMediaStreamTrackKind::kAudio &&
566 *media_stream_track.remote_source) {
567 verifier.TestMemberIsNonNegative<uint64_t>(
568 media_stream_track.total_samples_received);
569 verifier.TestMemberIsNonNegative<uint64_t>(
570 media_stream_track.concealed_samples);
571 } else {
572 verifier.TestMemberIsUndefined(media_stream_track.total_samples_received);
573 verifier.TestMemberIsUndefined(media_stream_track.concealed_samples);
574 }
hbosdb346a72016-11-29 09:57:01575 return verifier.ExpectAllMembersSuccessfullyTested();
576 }
577
578 bool VerifyRTCPeerConnectionStats(
579 const RTCPeerConnectionStats& peer_connection) {
580 RTCStatsVerifier verifier(report_, &peer_connection);
hbos23351192017-01-02 14:52:19581 verifier.TestMemberIsNonNegative<uint32_t>(
582 peer_connection.data_channels_opened);
583 verifier.TestMemberIsNonNegative<uint32_t>(
584 peer_connection.data_channels_closed);
hbosdb346a72016-11-29 09:57:01585 return verifier.ExpectAllMembersSuccessfullyTested();
586 }
587
588 void VerifyRTCRTPStreamStats(
589 const RTCRTPStreamStats& stream, RTCStatsVerifier* verifier) {
590 verifier->TestMemberIsDefined(stream.ssrc);
591 verifier->TestMemberIsUndefined(stream.associate_stats_id);
592 verifier->TestMemberIsDefined(stream.is_remote);
593 verifier->TestMemberIsDefined(stream.media_type);
hbos84abeb12017-01-16 14:16:44594 verifier->TestMemberIsIDReference(
hbosb0ae9202017-01-27 14:35:16595 stream.track_id, RTCMediaStreamTrackStats::kType);
hbosdb346a72016-11-29 09:57:01596 verifier->TestMemberIsIDReference(
597 stream.transport_id, RTCTransportStats::kType);
hbos7bf53692016-12-15 11:33:35598 verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
hbosdb346a72016-11-29 09:57:01599 if (stream.media_type.is_defined() && *stream.media_type == "video") {
hbos23351192017-01-02 14:52:19600 verifier->TestMemberIsNonNegative<uint32_t>(stream.fir_count);
601 verifier->TestMemberIsNonNegative<uint32_t>(stream.pli_count);
602 verifier->TestMemberIsNonNegative<uint32_t>(stream.nack_count);
hbosdb346a72016-11-29 09:57:01603 } else {
604 verifier->TestMemberIsUndefined(stream.fir_count);
605 verifier->TestMemberIsUndefined(stream.pli_count);
606 verifier->TestMemberIsUndefined(stream.nack_count);
607 }
608 verifier->TestMemberIsUndefined(stream.sli_count);
609 }
610
611 bool VerifyRTCInboundRTPStreamStats(
612 const RTCInboundRTPStreamStats& inbound_stream) {
613 RTCStatsVerifier verifier(report_, &inbound_stream);
614 VerifyRTCRTPStreamStats(inbound_stream, &verifier);
sakal5fec1282017-02-20 14:43:58615 if (inbound_stream.media_type.is_defined() &&
616 *inbound_stream.media_type == "video") {
617 verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum);
618 } else {
hbosa51d4f32017-02-16 13:34:48619 verifier.TestMemberIsUndefined(inbound_stream.qp_sum);
sakal5fec1282017-02-20 14:43:58620 }
hbos23351192017-01-02 14:52:19621 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received);
622 verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.bytes_received);
623 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_lost);
hbosdb346a72016-11-29 09:57:01624 if (inbound_stream.media_type.is_defined() &&
625 *inbound_stream.media_type == "video") {
626 verifier.TestMemberIsUndefined(inbound_stream.jitter);
627 } else {
hbos23351192017-01-02 14:52:19628 verifier.TestMemberIsNonNegative<double>(inbound_stream.jitter);
hbosdb346a72016-11-29 09:57:01629 }
hbos23351192017-01-02 14:52:19630 verifier.TestMemberIsNonNegative<double>(inbound_stream.fraction_lost);
hbosa7a9be12017-03-01 09:02:45631 verifier.TestMemberIsUndefined(inbound_stream.round_trip_time);
hbosdb346a72016-11-29 09:57:01632 verifier.TestMemberIsUndefined(inbound_stream.packets_discarded);
633 verifier.TestMemberIsUndefined(inbound_stream.packets_repaired);
634 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_lost);
635 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_discarded);
636 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_count);
637 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_count);
638 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_rate);
639 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_rate);
640 verifier.TestMemberIsUndefined(inbound_stream.gap_loss_rate);
641 verifier.TestMemberIsUndefined(inbound_stream.gap_discard_rate);
hbos6769c492017-01-02 16:35:13642 if (inbound_stream.media_type.is_defined() &&
643 *inbound_stream.media_type == "video") {
644 verifier.TestMemberIsDefined(inbound_stream.frames_decoded);
645 } else {
646 verifier.TestMemberIsUndefined(inbound_stream.frames_decoded);
647 }
hbosdb346a72016-11-29 09:57:01648 return verifier.ExpectAllMembersSuccessfullyTested();
649 }
650
651 bool VerifyRTCOutboundRTPStreamStats(
652 const RTCOutboundRTPStreamStats& outbound_stream) {
653 RTCStatsVerifier verifier(report_, &outbound_stream);
654 VerifyRTCRTPStreamStats(outbound_stream, &verifier);
hbos6769c492017-01-02 16:35:13655 if (outbound_stream.media_type.is_defined() &&
656 *outbound_stream.media_type == "video") {
657 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.qp_sum);
658 } else {
659 verifier.TestMemberIsUndefined(outbound_stream.qp_sum);
660 }
hbos23351192017-01-02 14:52:19661 verifier.TestMemberIsNonNegative<uint32_t>(outbound_stream.packets_sent);
662 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.bytes_sent);
hbosdb346a72016-11-29 09:57:01663 verifier.TestMemberIsUndefined(outbound_stream.target_bitrate);
hbos6769c492017-01-02 16:35:13664 if (outbound_stream.media_type.is_defined() &&
665 *outbound_stream.media_type == "video") {
666 verifier.TestMemberIsDefined(outbound_stream.frames_encoded);
667 } else {
668 verifier.TestMemberIsUndefined(outbound_stream.frames_encoded);
669 }
hbosdb346a72016-11-29 09:57:01670 return verifier.ExpectAllMembersSuccessfullyTested();
671 }
672
673 bool VerifyRTCTransportStats(
674 const RTCTransportStats& transport) {
675 RTCStatsVerifier verifier(report_, &transport);
hbos23351192017-01-02 14:52:19676 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_sent);
677 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_received);
hbosdb346a72016-11-29 09:57:01678 verifier.TestMemberIsOptionalIDReference(
679 transport.rtcp_transport_stats_id, RTCTransportStats::kType);
hbos7064d592017-01-16 15:38:02680 verifier.TestMemberIsDefined(transport.dtls_state);
hbos7bf53692016-12-15 11:33:35681 verifier.TestMemberIsIDReference(
682 transport.selected_candidate_pair_id, RTCIceCandidatePairStats::kType);
683 verifier.TestMemberIsIDReference(
684 transport.local_certificate_id, RTCCertificateStats::kType);
685 verifier.TestMemberIsIDReference(
686 transport.remote_certificate_id, RTCCertificateStats::kType);
hbosdb346a72016-11-29 09:57:01687 return verifier.ExpectAllMembersSuccessfullyTested();
688 }
689
690 private:
691 rtc::scoped_refptr<const RTCStatsReport> report_;
692};
693
deadbeef40610e22016-12-22 18:53:38694#ifdef HAVE_SCTP
hbosdb346a72016-11-29 09:57:01695TEST_F(RTCStatsIntegrationTest, GetStatsFromCaller) {
696 StartCall();
697
698 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCaller();
699 RTCStatsReportVerifier(report.get()).VerifyReport();
ehmaldonado8ab0fd82017-09-04 21:35:04700 EXPECT_EQ(report->ToJson(), RTCStatsReportTraceListener::last_trace());
hbosdb346a72016-11-29 09:57:01701}
702
703TEST_F(RTCStatsIntegrationTest, GetStatsFromCallee) {
704 StartCall();
705
706 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCallee();
707 RTCStatsReportVerifier(report.get()).VerifyReport();
ehmaldonado8ab0fd82017-09-04 21:35:04708 EXPECT_EQ(report->ToJson(), RTCStatsReportTraceListener::last_trace());
hbosdb346a72016-11-29 09:57:01709}
710
hbosb78306a2016-12-19 13:06:57711TEST_F(RTCStatsIntegrationTest, GetsStatsWhileDestroyingPeerConnections) {
712 StartCall();
713
714 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer =
715 RTCStatsObtainer::Create();
716 caller_->pc()->GetStats(stats_obtainer);
717 // This will destroy the peer connection.
718 caller_ = nullptr;
719 // Any pending stats requests should have completed in the act of destroying
720 // the peer connection.
721 EXPECT_TRUE(stats_obtainer->report());
ehmaldonado8ab0fd82017-09-04 21:35:04722 EXPECT_EQ(stats_obtainer->report()->ToJson(),
723 RTCStatsReportTraceListener::last_trace());
hbosb78306a2016-12-19 13:06:57724}
deadbeef40610e22016-12-22 18:53:38725#endif // HAVE_SCTP
hbosb78306a2016-12-19 13:06:57726
hbosdb346a72016-11-29 09:57:01727} // namespace
728
729} // namespace webrtc