blob: a498dc84db8974322a34ebf53c074ae982243333 [file] [log] [blame]
hbosdb346a72016-11-29 01:57:01 -08001/*
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 06:47:31 +020014#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 01:57:01 -080029
30namespace webrtc {
31
32namespace {
33
34const int64_t kGetStatsTimeoutMs = 10000;
35
ehmaldonado80c829f2017-07-18 07:35:19 -070036const unsigned char* GetCategoryEnabledHandler(const char* name) {
ehmaldonado8ab0fd82017-09-04 14:35:04 -070037 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 07:35:19 -070041}
42
ehmaldonado8ab0fd82017-09-04 14:35:04 -070043class 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 07:35:19 -070085
hbosdb346a72016-11-29 01:57:01 -080086class RTCStatsIntegrationTest : public testing::Test {
87 public:
88 RTCStatsIntegrationTest()
tommie7251592017-07-14 14:44:46 -070089 : network_thread_(new rtc::Thread(&virtual_socket_server_)),
90 worker_thread_(rtc::Thread::Create()) {
ehmaldonado8ab0fd82017-09-04 14:35:04 -070091 RTCStatsReportTraceListener::SetUp();
ehmaldonado80c829f2017-07-18 07:35:19 -070092
tommie7251592017-07-14 14:44:46 -070093 RTC_CHECK(network_thread_->Start());
94 RTC_CHECK(worker_thread_->Start());
hbosdb346a72016-11-29 01:57:01 -080095
96 caller_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommie7251592017-07-14 14:44:46 -070097 "caller", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 01:57:01 -080098 callee_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommie7251592017-07-14 14:44:46 -070099 "callee", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 01:57:01 -0800100 }
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 03:47:57 -0700108 EXPECT_TRUE(caller_->CreatePc(nullptr, config,
109 CreateBuiltinAudioEncoderFactory(),
110 CreateBuiltinAudioDecoderFactory()));
111 EXPECT_TRUE(callee_->CreatePc(nullptr, config,
112 CreateBuiltinAudioEncoderFactory(),
113 CreateBuiltinAudioDecoderFactory()));
hbosdb346a72016-11-29 01:57:01 -0800114 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-16 18:00:06 -0700151 // |network_thread_| uses |virtual_socket_server_| so they must be
152 // constructed/destructed in the correct order.
hbosdb346a72016-11-29 01:57:01 -0800153 rtc::VirtualSocketServer virtual_socket_server_;
tommie7251592017-07-14 14:44:46 -0700154 std::unique_ptr<rtc::Thread> network_thread_;
155 std::unique_ptr<rtc::Thread> worker_thread_;
hbosdb346a72016-11-29 01:57:01 -0800156 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 06:52:19 -0800179 stats_->type() << "." << member.name() << "[" << stats_->id() <<
180 "] was undefined.";
hbosdb346a72016-11-29 01:57:01 -0800181 MarkMemberTested(member, member.is_defined());
182 }
183
184 void TestMemberIsUndefined(const RTCStatsMemberInterface& member) {
185 EXPECT_FALSE(member.is_defined()) <<
hbos23351192017-01-02 06:52:19 -0800186 stats_->type() << "." << member.name() << "[" << stats_->id() <<
187 "] was defined (" << member.ValueToString() << ").";
hbosdb346a72016-11-29 01:57:01 -0800188 MarkMemberTested(member, !member.is_defined());
189 }
190
hbos23351192017-01-02 06:52:19 -0800191 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 01:57:01 -0800223 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 06:41:21 -0800317 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 01:57:01 -0800322 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 06:41:21 -0800335 stats.cast_to<RTCIceCandidatePairStats>(),
336 stats.id() == selected_candidate_pair_id);
hbosdb346a72016-11-29 01:57:01 -0800337 } 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 07:29:12 -0700374 report_->ToJson();
hbosdb346a72016-11-29 01:57:01 -0800375 }
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 06:56:04 -0800392 verifier.TestMemberIsDefined(codec.mime_type);
hbos23351192017-01-02 06:52:19 -0800393 verifier.TestMemberIsPositive<uint32_t>(codec.clock_rate);
hbosdb346a72016-11-29 01:57:01 -0800394 verifier.TestMemberIsUndefined(codec.channels);
hbos13f54b22017-02-28 06:56:04 -0800395 verifier.TestMemberIsUndefined(codec.sdp_fmtp_line);
hbosdb346a72016-11-29 01:57:01 -0800396 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 06:52:19 -0800407 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 01:57:01 -0800411 return verifier.ExpectAllMembersSuccessfullyTested();
412 }
413
414 bool VerifyRTCIceCandidatePairStats(
hbos338f78a2017-02-07 06:41:21 -0800415 const RTCIceCandidatePairStats& candidate_pair, bool is_selected_pair) {
hbosdb346a72016-11-29 01:57:01 -0800416 RTCStatsVerifier verifier(report_, &candidate_pair);
hbos0583b282016-11-30 01:50:14 -0800417 verifier.TestMemberIsIDReference(
418 candidate_pair.transport_id, RTCTransportStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800419 verifier.TestMemberIsIDReference(
420 candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType);
421 verifier.TestMemberIsIDReference(
422 candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType);
hbos06495bc2017-01-02 08:08:18 -0800423 verifier.TestMemberIsDefined(candidate_pair.state);
424 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.priority);
hbos92eaec62017-02-27 01:38:08 -0800425 verifier.TestMemberIsDefined(candidate_pair.nominated);
hbosdb346a72016-11-29 01:57:01 -0800426 verifier.TestMemberIsDefined(candidate_pair.writable);
427 verifier.TestMemberIsUndefined(candidate_pair.readable);
hbos23351192017-01-02 06:52:19 -0800428 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_sent);
429 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_received);
hbosbf8d3e52017-02-28 06:34:47 -0800430 verifier.TestMemberIsNonNegative<double>(
431 candidate_pair.total_round_trip_time);
hbos23351192017-01-02 06:52:19 -0800432 verifier.TestMemberIsNonNegative<double>(
433 candidate_pair.current_round_trip_time);
hbos338f78a2017-02-07 06:41:21 -0800434 if (is_selected_pair) {
435 verifier.TestMemberIsNonNegative<double>(
436 candidate_pair.available_outgoing_bitrate);
deadbeef86c40a12017-06-28 09:37:23 -0700437 // A pair should be nominated in order to be selected.
438 EXPECT_TRUE(*candidate_pair.nominated);
hbos338f78a2017-02-07 06:41:21 -0800439 } else {
440 verifier.TestMemberIsUndefined(candidate_pair.available_outgoing_bitrate);
441 }
hbosdb346a72016-11-29 01:57:01 -0800442 verifier.TestMemberIsUndefined(candidate_pair.available_incoming_bitrate);
hbos23351192017-01-02 06:52:19 -0800443 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 01:57:01 -0800449 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_received);
450 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_sent);
451 verifier.TestMemberIsUndefined(candidate_pair.consent_requests_received);
hbos23351192017-01-02 06:52:19 -0800452 verifier.TestMemberIsNonNegative<uint64_t>(
453 candidate_pair.consent_requests_sent);
hbosdb346a72016-11-29 01:57:01 -0800454 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 09:59:31 -0800462 verifier.TestMemberIsIDReference(
463 candidate.transport_id, RTCTransportStats::kType);
hbosc3a2b7f2017-01-02 04:46:15 -0800464 verifier.TestMemberIsDefined(candidate.is_remote);
hbosdb346a72016-11-29 01:57:01 -0800465 verifier.TestMemberIsDefined(candidate.ip);
hbos23351192017-01-02 06:52:19 -0800466 verifier.TestMemberIsNonNegative<int32_t>(candidate.port);
hbosdb346a72016-11-29 01:57:01 -0800467 verifier.TestMemberIsDefined(candidate.protocol);
468 verifier.TestMemberIsDefined(candidate.candidate_type);
hbos23351192017-01-02 06:52:19 -0800469 verifier.TestMemberIsNonNegative<int32_t>(candidate.priority);
hbosdb346a72016-11-29 01:57:01 -0800470 verifier.TestMemberIsUndefined(candidate.url);
hbosd17a5a72017-01-02 08:09:59 -0800471 verifier.TestMemberIsDefined(candidate.deleted);
hbosdb346a72016-11-29 01:57:01 -0800472 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 02:53:23 -0800501 verifier.TestMemberIsDefined(media_stream_track.kind);
hbosdb346a72016-11-29 01:57:01 -0800502 // Video or audio media stream track?
hbos160e4a72017-01-17 02:53:23 -0800503 if (*media_stream_track.kind == RTCMediaStreamTrackKind::kVideo) {
hbosdb346a72016-11-29 01:57:01 -0800504 // Video-only members
hbos9e302742017-01-20 02:47:10 -0800505 verifier.TestMemberIsNonNegative<uint32_t>(
506 media_stream_track.frame_width);
507 verifier.TestMemberIsNonNegative<uint32_t>(
508 media_stream_track.frame_height);
hbosdb346a72016-11-29 01:57:01 -0800509 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second);
hbos42f6d2f2017-01-20 03:56:50 -0800510 if (*media_stream_track.remote_source) {
hbosfefe0762017-01-20 06:14:25 -0800511 verifier.TestMemberIsUndefined(media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 03:56:50 -0800512 verifier.TestMemberIsNonNegative<uint32_t>(
513 media_stream_track.frames_received);
hbosf64941f2017-01-20 07:39:09 -0800514 verifier.TestMemberIsNonNegative<uint32_t>(
515 media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 07:21:55 -0800516 verifier.TestMemberIsNonNegative<uint32_t>(
517 media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 03:56:50 -0800518 } else {
hbosfefe0762017-01-20 06:14:25 -0800519 verifier.TestMemberIsNonNegative<uint32_t>(
520 media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 03:56:50 -0800521 verifier.TestMemberIsUndefined(media_stream_track.frames_received);
hbosf64941f2017-01-20 07:39:09 -0800522 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 07:21:55 -0800523 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 03:56:50 -0800524 }
hbosdb346a72016-11-29 01:57:01 -0800525 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 12:17:49 -0700533 verifier.TestMemberIsUndefined(media_stream_track.total_audio_energy);
534 verifier.TestMemberIsUndefined(media_stream_track.total_samples_duration);
hbosdb346a72016-11-29 01:57:01 -0800535 } else {
hbos42f6d2f2017-01-20 03:56:50 -0800536 RTC_DCHECK_EQ(*media_stream_track.kind,
537 RTCMediaStreamTrackKind::kAudio);
hbosdb346a72016-11-29 01:57:01 -0800538 // 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 02:47:10 -0800550 verifier.TestMemberIsNonNegative<double>(media_stream_track.audio_level);
zsteine76bd3a2017-07-14 12:17:49 -0700551 verifier.TestMemberIsNonNegative<double>(
552 media_stream_track.total_audio_energy);
553 verifier.TestMemberIsNonNegative<double>(
554 media_stream_track.total_samples_duration);
hbos2d4d6532017-01-20 04:16:41 -0800555 // 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 01:57:01 -0800562 }
Steve Anton2dbc69f2017-08-24 17:15:13 -0700563 // 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 01:57:01 -0800575 return verifier.ExpectAllMembersSuccessfullyTested();
576 }
577
578 bool VerifyRTCPeerConnectionStats(
579 const RTCPeerConnectionStats& peer_connection) {
580 RTCStatsVerifier verifier(report_, &peer_connection);
hbos23351192017-01-02 06:52:19 -0800581 verifier.TestMemberIsNonNegative<uint32_t>(
582 peer_connection.data_channels_opened);
583 verifier.TestMemberIsNonNegative<uint32_t>(
584 peer_connection.data_channels_closed);
hbosdb346a72016-11-29 01:57:01 -0800585 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 06:16:44 -0800594 verifier->TestMemberIsIDReference(
hbosb0ae9202017-01-27 06:35:16 -0800595 stream.track_id, RTCMediaStreamTrackStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800596 verifier->TestMemberIsIDReference(
597 stream.transport_id, RTCTransportStats::kType);
hbos7bf53692016-12-15 03:33:35 -0800598 verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800599 if (stream.media_type.is_defined() && *stream.media_type == "video") {
hbos23351192017-01-02 06:52:19 -0800600 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 01:57:01 -0800603 } 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 06:43:58 -0800615 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 05:34:48 -0800619 verifier.TestMemberIsUndefined(inbound_stream.qp_sum);
sakal5fec1282017-02-20 06:43:58 -0800620 }
hbos23351192017-01-02 06:52:19 -0800621 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 01:57:01 -0800624 if (inbound_stream.media_type.is_defined() &&
625 *inbound_stream.media_type == "video") {
626 verifier.TestMemberIsUndefined(inbound_stream.jitter);
627 } else {
hbos23351192017-01-02 06:52:19 -0800628 verifier.TestMemberIsNonNegative<double>(inbound_stream.jitter);
hbosdb346a72016-11-29 01:57:01 -0800629 }
hbos23351192017-01-02 06:52:19 -0800630 verifier.TestMemberIsNonNegative<double>(inbound_stream.fraction_lost);
hbosa7a9be12017-03-01 01:02:45 -0800631 verifier.TestMemberIsUndefined(inbound_stream.round_trip_time);
hbosdb346a72016-11-29 01:57:01 -0800632 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 08:35:13 -0800642 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 01:57:01 -0800648 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 08:35:13 -0800655 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 06:52:19 -0800661 verifier.TestMemberIsNonNegative<uint32_t>(outbound_stream.packets_sent);
662 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.bytes_sent);
hbosdb346a72016-11-29 01:57:01 -0800663 verifier.TestMemberIsUndefined(outbound_stream.target_bitrate);
hbos6769c492017-01-02 08:35:13 -0800664 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 01:57:01 -0800670 return verifier.ExpectAllMembersSuccessfullyTested();
671 }
672
673 bool VerifyRTCTransportStats(
674 const RTCTransportStats& transport) {
675 RTCStatsVerifier verifier(report_, &transport);
hbos23351192017-01-02 06:52:19 -0800676 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_sent);
677 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_received);
hbosdb346a72016-11-29 01:57:01 -0800678 verifier.TestMemberIsOptionalIDReference(
679 transport.rtcp_transport_stats_id, RTCTransportStats::kType);
hbos7064d592017-01-16 07:38:02 -0800680 verifier.TestMemberIsDefined(transport.dtls_state);
hbos7bf53692016-12-15 03:33:35 -0800681 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 01:57:01 -0800687 return verifier.ExpectAllMembersSuccessfullyTested();
688 }
689
690 private:
691 rtc::scoped_refptr<const RTCStatsReport> report_;
692};
693
deadbeef40610e22016-12-22 10:53:38 -0800694#ifdef HAVE_SCTP
hbosdb346a72016-11-29 01:57:01 -0800695TEST_F(RTCStatsIntegrationTest, GetStatsFromCaller) {
696 StartCall();
697
698 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCaller();
699 RTCStatsReportVerifier(report.get()).VerifyReport();
ehmaldonado8ab0fd82017-09-04 14:35:04 -0700700 EXPECT_EQ(report->ToJson(), RTCStatsReportTraceListener::last_trace());
hbosdb346a72016-11-29 01:57:01 -0800701}
702
703TEST_F(RTCStatsIntegrationTest, GetStatsFromCallee) {
704 StartCall();
705
706 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCallee();
707 RTCStatsReportVerifier(report.get()).VerifyReport();
ehmaldonado8ab0fd82017-09-04 14:35:04 -0700708 EXPECT_EQ(report->ToJson(), RTCStatsReportTraceListener::last_trace());
hbosdb346a72016-11-29 01:57:01 -0800709}
710
hbosb78306a2016-12-19 05:06:57 -0800711TEST_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 14:35:04 -0700722 EXPECT_EQ(stats_obtainer->report()->ToJson(),
723 RTCStatsReportTraceListener::last_trace());
hbosb78306a2016-12-19 05:06:57 -0800724}
deadbeef40610e22016-12-22 10:53:38 -0800725#endif // HAVE_SCTP
hbosb78306a2016-12-19 05:06:57 -0800726
hbosdb346a72016-11-29 01:57:01 -0800727} // namespace
728
729} // namespace webrtc