blob: 3dffb8d7139257d3af0774ab8196b065c9b0ad52 [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
kwiberg9e5b11e2017-04-19 03:47:57 -070014#include "webrtc/api/audio_codecs/builtin_audio_decoder_factory.h"
ossu6488ea42017-05-17 04:39:36 -070015#include "webrtc/api/audio_codecs/builtin_audio_encoder_factory.h"
hbosdb346a72016-11-29 01:57:01 -080016#include "webrtc/api/datachannelinterface.h"
17#include "webrtc/api/peerconnectioninterface.h"
18#include "webrtc/api/stats/rtcstats_objects.h"
19#include "webrtc/api/stats/rtcstatsreport.h"
ossu7bb87ee2017-01-23 04:56:25 -080020#include "webrtc/pc/test/peerconnectiontestwrapper.h"
21#include "webrtc/pc/test/rtcstatsobtainer.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020022#include "webrtc/rtc_base/checks.h"
23#include "webrtc/rtc_base/gunit.h"
24#include "webrtc/rtc_base/refcountedobject.h"
25#include "webrtc/rtc_base/scoped_ref_ptr.h"
26#include "webrtc/rtc_base/virtualsocketserver.h"
hbosdb346a72016-11-29 01:57:01 -080027
28namespace webrtc {
29
30namespace {
31
32const int64_t kGetStatsTimeoutMs = 10000;
33
34class RTCStatsIntegrationTest : public testing::Test {
35 public:
36 RTCStatsIntegrationTest()
tommia8a35152017-07-13 05:47:25 -070037 : network_thread_(new rtc::Thread(&virtual_socket_server_)),
38 worker_thread_(rtc::Thread::Create()) {
39 RTC_CHECK(network_thread_->Start());
40 RTC_CHECK(worker_thread_->Start());
hbosdb346a72016-11-29 01:57:01 -080041
42 caller_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommia8a35152017-07-13 05:47:25 -070043 "caller", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 01:57:01 -080044 callee_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>(
tommia8a35152017-07-13 05:47:25 -070045 "callee", network_thread_.get(), worker_thread_.get());
hbosdb346a72016-11-29 01:57:01 -080046 }
47
48 void StartCall() {
49 // Create PeerConnections and "connect" sigslots
50 PeerConnectionInterface::RTCConfiguration config;
51 PeerConnectionInterface::IceServer ice_server;
52 ice_server.uri = "stun:1.1.1.1:3478";
53 config.servers.push_back(ice_server);
kwiberg9e5b11e2017-04-19 03:47:57 -070054 EXPECT_TRUE(caller_->CreatePc(nullptr, config,
55 CreateBuiltinAudioEncoderFactory(),
56 CreateBuiltinAudioDecoderFactory()));
57 EXPECT_TRUE(callee_->CreatePc(nullptr, config,
58 CreateBuiltinAudioEncoderFactory(),
59 CreateBuiltinAudioDecoderFactory()));
hbosdb346a72016-11-29 01:57:01 -080060 PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get());
61
62 // Get user media for audio and video
63 caller_->GetAndAddUserMedia(true, FakeConstraints(),
64 true, FakeConstraints());
65 callee_->GetAndAddUserMedia(true, FakeConstraints(),
66 true, FakeConstraints());
67
68 // Create data channels
69 DataChannelInit init;
70 caller_->CreateDataChannel("data", init);
71 callee_->CreateDataChannel("data", init);
72
73 // Negotiate and wait for call to establish
74 caller_->CreateOffer(nullptr);
75 caller_->WaitForCallEstablished();
76 callee_->WaitForCallEstablished();
77 }
78
79 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCaller() {
80 return GetStats(caller_->pc());
81 }
82
83 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCallee() {
84 return GetStats(callee_->pc());
85 }
86
87 protected:
88 static rtc::scoped_refptr<const RTCStatsReport> GetStats(
89 PeerConnectionInterface* pc) {
90 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer =
91 RTCStatsObtainer::Create();
92 pc->GetStats(stats_obtainer);
93 EXPECT_TRUE_WAIT(stats_obtainer->report(), kGetStatsTimeoutMs);
94 return stats_obtainer->report();
95 }
96
deadbeef98e186c2017-05-16 18:00:06 -070097 // |network_thread_| uses |virtual_socket_server_| so they must be
98 // constructed/destructed in the correct order.
hbosdb346a72016-11-29 01:57:01 -080099 rtc::VirtualSocketServer virtual_socket_server_;
tommia8a35152017-07-13 05:47:25 -0700100 std::unique_ptr<rtc::Thread> network_thread_;
101 std::unique_ptr<rtc::Thread> worker_thread_;
hbosdb346a72016-11-29 01:57:01 -0800102 rtc::scoped_refptr<PeerConnectionTestWrapper> caller_;
103 rtc::scoped_refptr<PeerConnectionTestWrapper> callee_;
104};
105
106class RTCStatsVerifier {
107 public:
108 RTCStatsVerifier(const RTCStatsReport* report, const RTCStats* stats)
109 : report_(report), stats_(stats), all_tests_successful_(true) {
110 RTC_CHECK(report_);
111 RTC_CHECK(stats_);
112 for (const RTCStatsMemberInterface* member : stats_->Members()) {
113 untested_members_.insert(member);
114 }
115 }
116
117 void MarkMemberTested(
118 const RTCStatsMemberInterface& member, bool test_successful) {
119 untested_members_.erase(&member);
120 all_tests_successful_ &= test_successful;
121 }
122
123 void TestMemberIsDefined(const RTCStatsMemberInterface& member) {
124 EXPECT_TRUE(member.is_defined()) <<
hbos23351192017-01-02 06:52:19 -0800125 stats_->type() << "." << member.name() << "[" << stats_->id() <<
126 "] was undefined.";
hbosdb346a72016-11-29 01:57:01 -0800127 MarkMemberTested(member, member.is_defined());
128 }
129
130 void TestMemberIsUndefined(const RTCStatsMemberInterface& member) {
131 EXPECT_FALSE(member.is_defined()) <<
hbos23351192017-01-02 06:52:19 -0800132 stats_->type() << "." << member.name() << "[" << stats_->id() <<
133 "] was defined (" << member.ValueToString() << ").";
hbosdb346a72016-11-29 01:57:01 -0800134 MarkMemberTested(member, !member.is_defined());
135 }
136
hbos23351192017-01-02 06:52:19 -0800137 template<typename T>
138 void TestMemberIsPositive(const RTCStatsMemberInterface& member) {
139 EXPECT_TRUE(member.is_defined()) <<
140 stats_->type() << "." << member.name() << "[" << stats_->id() <<
141 "] was undefined.";
142 if (!member.is_defined()) {
143 MarkMemberTested(member, false);
144 return;
145 }
146 bool is_positive = *member.cast_to<RTCStatsMember<T>>() > T(0);
147 EXPECT_TRUE(is_positive) <<
148 stats_->type() << "." << member.name() << "[" << stats_->id() <<
149 "] was not positive (" << member.ValueToString() << ").";
150 MarkMemberTested(member, is_positive);
151 }
152
153 template<typename T>
154 void TestMemberIsNonNegative(const RTCStatsMemberInterface& member) {
155 EXPECT_TRUE(member.is_defined()) <<
156 stats_->type() << "." << member.name() << "[" << stats_->id() <<
157 "] was undefined.";
158 if (!member.is_defined()) {
159 MarkMemberTested(member, false);
160 return;
161 }
162 bool is_non_negative = *member.cast_to<RTCStatsMember<T>>() >= T(0);
163 EXPECT_TRUE(is_non_negative) <<
164 stats_->type() << "." << member.name() << "[" << stats_->id() <<
165 "] was not non-negative (" << member.ValueToString() << ").";
166 MarkMemberTested(member, is_non_negative);
167 }
168
hbosdb346a72016-11-29 01:57:01 -0800169 void TestMemberIsIDReference(
170 const RTCStatsMemberInterface& member,
171 const char* expected_type) {
172 TestMemberIsIDReference(member, expected_type, false);
173 }
174
175 void TestMemberIsOptionalIDReference(
176 const RTCStatsMemberInterface& member,
177 const char* expected_type) {
178 TestMemberIsIDReference(member, expected_type, true);
179 }
180
181 bool ExpectAllMembersSuccessfullyTested() {
182 if (untested_members_.empty())
183 return all_tests_successful_;
184 for (const RTCStatsMemberInterface* member : untested_members_) {
185 EXPECT_TRUE(false) <<
186 stats_->type() << "." << member->name() << "[" << stats_->id() <<
187 "] was not tested.";
188 }
189 return false;
190 }
191
192 private:
193 void TestMemberIsIDReference(
194 const RTCStatsMemberInterface& member,
195 const char* expected_type,
196 bool optional) {
197 if (optional && !member.is_defined()) {
198 MarkMemberTested(member, true);
199 return;
200 }
201 bool valid_reference = false;
202 if (member.is_defined()) {
203 if (member.type() == RTCStatsMemberInterface::kString) {
204 // A single ID.
205 const RTCStatsMember<std::string>& id =
206 member.cast_to<RTCStatsMember<std::string>>();
207 const RTCStats* referenced_stats = report_->Get(*id);
208 valid_reference =
209 referenced_stats && referenced_stats->type() == expected_type;
210 } else if (member.type() == RTCStatsMemberInterface::kSequenceString) {
211 // A vector of IDs.
212 valid_reference = true;
213 const RTCStatsMember<std::vector<std::string>>& ids =
214 member.cast_to<RTCStatsMember<std::vector<std::string>>>();
215 for (const std::string id : *ids) {
216 const RTCStats* referenced_stats = report_->Get(id);
217 if (!referenced_stats || referenced_stats->type() != expected_type) {
218 valid_reference = false;
219 break;
220 }
221 }
222 }
223 }
224 EXPECT_TRUE(valid_reference) <<
225 stats_->type() << "." << member.name() << " is not a reference to an " <<
226 "existing dictionary of type " << expected_type << " (" <<
227 member.ValueToString() << ").";
228 MarkMemberTested(member, valid_reference);
229 }
230
231 rtc::scoped_refptr<const RTCStatsReport> report_;
232 const RTCStats* stats_;
233 std::set<const RTCStatsMemberInterface*> untested_members_;
234 bool all_tests_successful_;
235};
236
237class RTCStatsReportVerifier {
238 public:
239 static std::set<const char*> StatsTypes() {
240 std::set<const char*> stats_types;
241 stats_types.insert(RTCCertificateStats::kType);
242 stats_types.insert(RTCCodecStats::kType);
243 stats_types.insert(RTCDataChannelStats::kType);
244 stats_types.insert(RTCIceCandidatePairStats::kType);
245 stats_types.insert(RTCLocalIceCandidateStats::kType);
246 stats_types.insert(RTCRemoteIceCandidateStats::kType);
247 stats_types.insert(RTCMediaStreamStats::kType);
248 stats_types.insert(RTCMediaStreamTrackStats::kType);
249 stats_types.insert(RTCPeerConnectionStats::kType);
250 stats_types.insert(RTCInboundRTPStreamStats::kType);
251 stats_types.insert(RTCOutboundRTPStreamStats::kType);
252 stats_types.insert(RTCTransportStats::kType);
253 return stats_types;
254 }
255
256 explicit RTCStatsReportVerifier(const RTCStatsReport* report)
257 : report_(report) {
258 }
259
260 void VerifyReport() {
261 std::set<const char*> missing_stats = StatsTypes();
262 bool verify_successful = true;
hbos338f78a2017-02-07 06:41:21 -0800263 std::vector<const RTCTransportStats*> transport_stats =
264 report_->GetStatsOfType<RTCTransportStats>();
265 EXPECT_EQ(transport_stats.size(), 1);
266 std::string selected_candidate_pair_id =
267 *transport_stats[0]->selected_candidate_pair_id;
hbosdb346a72016-11-29 01:57:01 -0800268 for (const RTCStats& stats : *report_) {
269 missing_stats.erase(stats.type());
270 if (stats.type() == RTCCertificateStats::kType) {
271 verify_successful &= VerifyRTCCertificateStats(
272 stats.cast_to<RTCCertificateStats>());
273 } else if (stats.type() == RTCCodecStats::kType) {
274 verify_successful &= VerifyRTCCodecStats(
275 stats.cast_to<RTCCodecStats>());
276 } else if (stats.type() == RTCDataChannelStats::kType) {
277 verify_successful &= VerifyRTCDataChannelStats(
278 stats.cast_to<RTCDataChannelStats>());
279 } else if (stats.type() == RTCIceCandidatePairStats::kType) {
280 verify_successful &= VerifyRTCIceCandidatePairStats(
hbos338f78a2017-02-07 06:41:21 -0800281 stats.cast_to<RTCIceCandidatePairStats>(),
282 stats.id() == selected_candidate_pair_id);
hbosdb346a72016-11-29 01:57:01 -0800283 } else if (stats.type() == RTCLocalIceCandidateStats::kType) {
284 verify_successful &= VerifyRTCLocalIceCandidateStats(
285 stats.cast_to<RTCLocalIceCandidateStats>());
286 } else if (stats.type() == RTCRemoteIceCandidateStats::kType) {
287 verify_successful &= VerifyRTCRemoteIceCandidateStats(
288 stats.cast_to<RTCRemoteIceCandidateStats>());
289 } else if (stats.type() == RTCMediaStreamStats::kType) {
290 verify_successful &= VerifyRTCMediaStreamStats(
291 stats.cast_to<RTCMediaStreamStats>());
292 } else if (stats.type() == RTCMediaStreamTrackStats::kType) {
293 verify_successful &= VerifyRTCMediaStreamTrackStats(
294 stats.cast_to<RTCMediaStreamTrackStats>());
295 } else if (stats.type() == RTCPeerConnectionStats::kType) {
296 verify_successful &= VerifyRTCPeerConnectionStats(
297 stats.cast_to<RTCPeerConnectionStats>());
298 } else if (stats.type() == RTCInboundRTPStreamStats::kType) {
299 verify_successful &= VerifyRTCInboundRTPStreamStats(
300 stats.cast_to<RTCInboundRTPStreamStats>());
301 } else if (stats.type() == RTCOutboundRTPStreamStats::kType) {
302 verify_successful &= VerifyRTCOutboundRTPStreamStats(
303 stats.cast_to<RTCOutboundRTPStreamStats>());
304 } else if (stats.type() == RTCTransportStats::kType) {
305 verify_successful &= VerifyRTCTransportStats(
306 stats.cast_to<RTCTransportStats>());
307 } else {
308 EXPECT_TRUE(false) << "Unrecognized stats type: " << stats.type();
309 verify_successful = false;
310 }
311 }
312 if (!missing_stats.empty()) {
313 verify_successful = false;
314 for (const char* missing : missing_stats) {
315 EXPECT_TRUE(false) << "Missing expected stats type: " << missing;
316 }
317 }
318 EXPECT_TRUE(verify_successful) <<
319 "One or more problems with the stats. This is the report:\n" <<
320 report_->ToString();
321 }
322
323 bool VerifyRTCCertificateStats(
324 const RTCCertificateStats& certificate) {
325 RTCStatsVerifier verifier(report_, &certificate);
326 verifier.TestMemberIsDefined(certificate.fingerprint);
327 verifier.TestMemberIsDefined(certificate.fingerprint_algorithm);
328 verifier.TestMemberIsDefined(certificate.base64_certificate);
329 verifier.TestMemberIsOptionalIDReference(
330 certificate.issuer_certificate_id, RTCCertificateStats::kType);
331 return verifier.ExpectAllMembersSuccessfullyTested();
332 }
333
334 bool VerifyRTCCodecStats(
335 const RTCCodecStats& codec) {
336 RTCStatsVerifier verifier(report_, &codec);
337 verifier.TestMemberIsDefined(codec.payload_type);
hbos13f54b22017-02-28 06:56:04 -0800338 verifier.TestMemberIsDefined(codec.mime_type);
hbos23351192017-01-02 06:52:19 -0800339 verifier.TestMemberIsPositive<uint32_t>(codec.clock_rate);
hbosdb346a72016-11-29 01:57:01 -0800340 verifier.TestMemberIsUndefined(codec.channels);
hbos13f54b22017-02-28 06:56:04 -0800341 verifier.TestMemberIsUndefined(codec.sdp_fmtp_line);
hbosdb346a72016-11-29 01:57:01 -0800342 verifier.TestMemberIsUndefined(codec.implementation);
343 return verifier.ExpectAllMembersSuccessfullyTested();
344 }
345
346 bool VerifyRTCDataChannelStats(
347 const RTCDataChannelStats& data_channel) {
348 RTCStatsVerifier verifier(report_, &data_channel);
349 verifier.TestMemberIsDefined(data_channel.label);
350 verifier.TestMemberIsDefined(data_channel.protocol);
351 verifier.TestMemberIsDefined(data_channel.datachannelid);
352 verifier.TestMemberIsDefined(data_channel.state);
hbos23351192017-01-02 06:52:19 -0800353 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_sent);
354 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_sent);
355 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_received);
356 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_received);
hbosdb346a72016-11-29 01:57:01 -0800357 return verifier.ExpectAllMembersSuccessfullyTested();
358 }
359
360 bool VerifyRTCIceCandidatePairStats(
hbos338f78a2017-02-07 06:41:21 -0800361 const RTCIceCandidatePairStats& candidate_pair, bool is_selected_pair) {
hbosdb346a72016-11-29 01:57:01 -0800362 RTCStatsVerifier verifier(report_, &candidate_pair);
hbos0583b282016-11-30 01:50:14 -0800363 verifier.TestMemberIsIDReference(
364 candidate_pair.transport_id, RTCTransportStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800365 verifier.TestMemberIsIDReference(
366 candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType);
367 verifier.TestMemberIsIDReference(
368 candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType);
hbos06495bc2017-01-02 08:08:18 -0800369 verifier.TestMemberIsDefined(candidate_pair.state);
370 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.priority);
hbos92eaec62017-02-27 01:38:08 -0800371 verifier.TestMemberIsDefined(candidate_pair.nominated);
hbosdb346a72016-11-29 01:57:01 -0800372 verifier.TestMemberIsDefined(candidate_pair.writable);
373 verifier.TestMemberIsUndefined(candidate_pair.readable);
hbos23351192017-01-02 06:52:19 -0800374 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_sent);
375 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_received);
hbosbf8d3e52017-02-28 06:34:47 -0800376 verifier.TestMemberIsNonNegative<double>(
377 candidate_pair.total_round_trip_time);
hbos23351192017-01-02 06:52:19 -0800378 verifier.TestMemberIsNonNegative<double>(
379 candidate_pair.current_round_trip_time);
hbos338f78a2017-02-07 06:41:21 -0800380 if (is_selected_pair) {
381 verifier.TestMemberIsNonNegative<double>(
382 candidate_pair.available_outgoing_bitrate);
deadbeef86c40a12017-06-28 09:37:23 -0700383 // A pair should be nominated in order to be selected.
384 EXPECT_TRUE(*candidate_pair.nominated);
hbos338f78a2017-02-07 06:41:21 -0800385 } else {
386 verifier.TestMemberIsUndefined(candidate_pair.available_outgoing_bitrate);
387 }
hbosdb346a72016-11-29 01:57:01 -0800388 verifier.TestMemberIsUndefined(candidate_pair.available_incoming_bitrate);
hbos23351192017-01-02 06:52:19 -0800389 verifier.TestMemberIsNonNegative<uint64_t>(
390 candidate_pair.requests_received);
391 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.requests_sent);
392 verifier.TestMemberIsNonNegative<uint64_t>(
393 candidate_pair.responses_received);
394 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.responses_sent);
hbosdb346a72016-11-29 01:57:01 -0800395 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_received);
396 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_sent);
397 verifier.TestMemberIsUndefined(candidate_pair.consent_requests_received);
hbos23351192017-01-02 06:52:19 -0800398 verifier.TestMemberIsNonNegative<uint64_t>(
399 candidate_pair.consent_requests_sent);
hbosdb346a72016-11-29 01:57:01 -0800400 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_received);
401 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_sent);
402 return verifier.ExpectAllMembersSuccessfullyTested();
403 }
404
405 bool VerifyRTCIceCandidateStats(
406 const RTCIceCandidateStats& candidate) {
407 RTCStatsVerifier verifier(report_, &candidate);
hbosb4e426e2017-01-02 09:59:31 -0800408 verifier.TestMemberIsIDReference(
409 candidate.transport_id, RTCTransportStats::kType);
hbosc3a2b7f2017-01-02 04:46:15 -0800410 verifier.TestMemberIsDefined(candidate.is_remote);
hbosdb346a72016-11-29 01:57:01 -0800411 verifier.TestMemberIsDefined(candidate.ip);
hbos23351192017-01-02 06:52:19 -0800412 verifier.TestMemberIsNonNegative<int32_t>(candidate.port);
hbosdb346a72016-11-29 01:57:01 -0800413 verifier.TestMemberIsDefined(candidate.protocol);
414 verifier.TestMemberIsDefined(candidate.candidate_type);
hbos23351192017-01-02 06:52:19 -0800415 verifier.TestMemberIsNonNegative<int32_t>(candidate.priority);
hbosdb346a72016-11-29 01:57:01 -0800416 verifier.TestMemberIsUndefined(candidate.url);
hbosd17a5a72017-01-02 08:09:59 -0800417 verifier.TestMemberIsDefined(candidate.deleted);
hbosdb346a72016-11-29 01:57:01 -0800418 return verifier.ExpectAllMembersSuccessfullyTested();
419 }
420
421 bool VerifyRTCLocalIceCandidateStats(
422 const RTCLocalIceCandidateStats& local_candidate) {
423 return VerifyRTCIceCandidateStats(local_candidate);
424 }
425
426 bool VerifyRTCRemoteIceCandidateStats(
427 const RTCRemoteIceCandidateStats& remote_candidate) {
428 return VerifyRTCIceCandidateStats(remote_candidate);
429 }
430
431 bool VerifyRTCMediaStreamStats(
432 const RTCMediaStreamStats& media_stream) {
433 RTCStatsVerifier verifier(report_, &media_stream);
434 verifier.TestMemberIsDefined(media_stream.stream_identifier);
435 verifier.TestMemberIsIDReference(
436 media_stream.track_ids, RTCMediaStreamTrackStats::kType);
437 return verifier.ExpectAllMembersSuccessfullyTested();
438 }
439
440 bool VerifyRTCMediaStreamTrackStats(
441 const RTCMediaStreamTrackStats& media_stream_track) {
442 RTCStatsVerifier verifier(report_, &media_stream_track);
443 verifier.TestMemberIsDefined(media_stream_track.track_identifier);
444 verifier.TestMemberIsDefined(media_stream_track.remote_source);
445 verifier.TestMemberIsDefined(media_stream_track.ended);
446 verifier.TestMemberIsDefined(media_stream_track.detached);
hbos160e4a72017-01-17 02:53:23 -0800447 verifier.TestMemberIsDefined(media_stream_track.kind);
hbosdb346a72016-11-29 01:57:01 -0800448 // Video or audio media stream track?
hbos160e4a72017-01-17 02:53:23 -0800449 if (*media_stream_track.kind == RTCMediaStreamTrackKind::kVideo) {
hbosdb346a72016-11-29 01:57:01 -0800450 // Video-only members
hbos9e302742017-01-20 02:47:10 -0800451 verifier.TestMemberIsNonNegative<uint32_t>(
452 media_stream_track.frame_width);
453 verifier.TestMemberIsNonNegative<uint32_t>(
454 media_stream_track.frame_height);
hbosdb346a72016-11-29 01:57:01 -0800455 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second);
hbos42f6d2f2017-01-20 03:56:50 -0800456 if (*media_stream_track.remote_source) {
hbosfefe0762017-01-20 06:14:25 -0800457 verifier.TestMemberIsUndefined(media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 03:56:50 -0800458 verifier.TestMemberIsNonNegative<uint32_t>(
459 media_stream_track.frames_received);
hbosf64941f2017-01-20 07:39:09 -0800460 verifier.TestMemberIsNonNegative<uint32_t>(
461 media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 07:21:55 -0800462 verifier.TestMemberIsNonNegative<uint32_t>(
463 media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 03:56:50 -0800464 } else {
hbosfefe0762017-01-20 06:14:25 -0800465 verifier.TestMemberIsNonNegative<uint32_t>(
466 media_stream_track.frames_sent);
hbos42f6d2f2017-01-20 03:56:50 -0800467 verifier.TestMemberIsUndefined(media_stream_track.frames_received);
hbosf64941f2017-01-20 07:39:09 -0800468 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded);
hbos50cfe1f2017-01-23 07:21:55 -0800469 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped);
hbos42f6d2f2017-01-20 03:56:50 -0800470 }
hbosdb346a72016-11-29 01:57:01 -0800471 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted);
472 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost);
473 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost);
474 // Audio-only members should be undefined
475 verifier.TestMemberIsUndefined(media_stream_track.audio_level);
476 verifier.TestMemberIsUndefined(media_stream_track.echo_return_loss);
477 verifier.TestMemberIsUndefined(
478 media_stream_track.echo_return_loss_enhancement);
479 } else {
hbos42f6d2f2017-01-20 03:56:50 -0800480 RTC_DCHECK_EQ(*media_stream_track.kind,
481 RTCMediaStreamTrackKind::kAudio);
hbosdb346a72016-11-29 01:57:01 -0800482 // Video-only members should be undefined
483 verifier.TestMemberIsUndefined(media_stream_track.frame_width);
484 verifier.TestMemberIsUndefined(media_stream_track.frame_height);
485 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second);
486 verifier.TestMemberIsUndefined(media_stream_track.frames_sent);
487 verifier.TestMemberIsUndefined(media_stream_track.frames_received);
488 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded);
489 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped);
490 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted);
491 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost);
492 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost);
493 // Audio-only members
hbos9e302742017-01-20 02:47:10 -0800494 verifier.TestMemberIsNonNegative<double>(media_stream_track.audio_level);
hbos2d4d6532017-01-20 04:16:41 -0800495 // TODO(hbos): |echo_return_loss| and |echo_return_loss_enhancement| are
496 // flaky on msan bot (sometimes defined, sometimes undefined). Should the
497 // test run until available or is there a way to have it always be
498 // defined? crbug.com/627816
499 verifier.MarkMemberTested(media_stream_track.echo_return_loss, true);
500 verifier.MarkMemberTested(
501 media_stream_track.echo_return_loss_enhancement, true);
hbosdb346a72016-11-29 01:57:01 -0800502 }
503 return verifier.ExpectAllMembersSuccessfullyTested();
504 }
505
506 bool VerifyRTCPeerConnectionStats(
507 const RTCPeerConnectionStats& peer_connection) {
508 RTCStatsVerifier verifier(report_, &peer_connection);
hbos23351192017-01-02 06:52:19 -0800509 verifier.TestMemberIsNonNegative<uint32_t>(
510 peer_connection.data_channels_opened);
511 verifier.TestMemberIsNonNegative<uint32_t>(
512 peer_connection.data_channels_closed);
hbosdb346a72016-11-29 01:57:01 -0800513 return verifier.ExpectAllMembersSuccessfullyTested();
514 }
515
516 void VerifyRTCRTPStreamStats(
517 const RTCRTPStreamStats& stream, RTCStatsVerifier* verifier) {
518 verifier->TestMemberIsDefined(stream.ssrc);
519 verifier->TestMemberIsUndefined(stream.associate_stats_id);
520 verifier->TestMemberIsDefined(stream.is_remote);
521 verifier->TestMemberIsDefined(stream.media_type);
hbos84abeb12017-01-16 06:16:44 -0800522 verifier->TestMemberIsIDReference(
hbosb0ae9202017-01-27 06:35:16 -0800523 stream.track_id, RTCMediaStreamTrackStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800524 verifier->TestMemberIsIDReference(
525 stream.transport_id, RTCTransportStats::kType);
hbos7bf53692016-12-15 03:33:35 -0800526 verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800527 if (stream.media_type.is_defined() && *stream.media_type == "video") {
hbos23351192017-01-02 06:52:19 -0800528 verifier->TestMemberIsNonNegative<uint32_t>(stream.fir_count);
529 verifier->TestMemberIsNonNegative<uint32_t>(stream.pli_count);
530 verifier->TestMemberIsNonNegative<uint32_t>(stream.nack_count);
hbosdb346a72016-11-29 01:57:01 -0800531 } else {
532 verifier->TestMemberIsUndefined(stream.fir_count);
533 verifier->TestMemberIsUndefined(stream.pli_count);
534 verifier->TestMemberIsUndefined(stream.nack_count);
535 }
536 verifier->TestMemberIsUndefined(stream.sli_count);
537 }
538
539 bool VerifyRTCInboundRTPStreamStats(
540 const RTCInboundRTPStreamStats& inbound_stream) {
541 RTCStatsVerifier verifier(report_, &inbound_stream);
542 VerifyRTCRTPStreamStats(inbound_stream, &verifier);
sakal5fec1282017-02-20 06:43:58 -0800543 if (inbound_stream.media_type.is_defined() &&
544 *inbound_stream.media_type == "video") {
545 verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum);
546 } else {
hbosa51d4f32017-02-16 05:34:48 -0800547 verifier.TestMemberIsUndefined(inbound_stream.qp_sum);
sakal5fec1282017-02-20 06:43:58 -0800548 }
hbos23351192017-01-02 06:52:19 -0800549 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received);
550 verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.bytes_received);
551 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_lost);
hbosdb346a72016-11-29 01:57:01 -0800552 if (inbound_stream.media_type.is_defined() &&
553 *inbound_stream.media_type == "video") {
554 verifier.TestMemberIsUndefined(inbound_stream.jitter);
555 } else {
hbos23351192017-01-02 06:52:19 -0800556 verifier.TestMemberIsNonNegative<double>(inbound_stream.jitter);
hbosdb346a72016-11-29 01:57:01 -0800557 }
hbos23351192017-01-02 06:52:19 -0800558 verifier.TestMemberIsNonNegative<double>(inbound_stream.fraction_lost);
hbosa7a9be12017-03-01 01:02:45 -0800559 verifier.TestMemberIsUndefined(inbound_stream.round_trip_time);
hbosdb346a72016-11-29 01:57:01 -0800560 verifier.TestMemberIsUndefined(inbound_stream.packets_discarded);
561 verifier.TestMemberIsUndefined(inbound_stream.packets_repaired);
562 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_lost);
563 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_discarded);
564 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_count);
565 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_count);
566 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_rate);
567 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_rate);
568 verifier.TestMemberIsUndefined(inbound_stream.gap_loss_rate);
569 verifier.TestMemberIsUndefined(inbound_stream.gap_discard_rate);
hbos6769c492017-01-02 08:35:13 -0800570 if (inbound_stream.media_type.is_defined() &&
571 *inbound_stream.media_type == "video") {
572 verifier.TestMemberIsDefined(inbound_stream.frames_decoded);
573 } else {
574 verifier.TestMemberIsUndefined(inbound_stream.frames_decoded);
575 }
hbosdb346a72016-11-29 01:57:01 -0800576 return verifier.ExpectAllMembersSuccessfullyTested();
577 }
578
579 bool VerifyRTCOutboundRTPStreamStats(
580 const RTCOutboundRTPStreamStats& outbound_stream) {
581 RTCStatsVerifier verifier(report_, &outbound_stream);
582 VerifyRTCRTPStreamStats(outbound_stream, &verifier);
hbos6769c492017-01-02 08:35:13 -0800583 if (outbound_stream.media_type.is_defined() &&
584 *outbound_stream.media_type == "video") {
585 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.qp_sum);
586 } else {
587 verifier.TestMemberIsUndefined(outbound_stream.qp_sum);
588 }
hbos23351192017-01-02 06:52:19 -0800589 verifier.TestMemberIsNonNegative<uint32_t>(outbound_stream.packets_sent);
590 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.bytes_sent);
hbosdb346a72016-11-29 01:57:01 -0800591 verifier.TestMemberIsUndefined(outbound_stream.target_bitrate);
hbos6769c492017-01-02 08:35:13 -0800592 if (outbound_stream.media_type.is_defined() &&
593 *outbound_stream.media_type == "video") {
594 verifier.TestMemberIsDefined(outbound_stream.frames_encoded);
595 } else {
596 verifier.TestMemberIsUndefined(outbound_stream.frames_encoded);
597 }
hbosdb346a72016-11-29 01:57:01 -0800598 return verifier.ExpectAllMembersSuccessfullyTested();
599 }
600
601 bool VerifyRTCTransportStats(
602 const RTCTransportStats& transport) {
603 RTCStatsVerifier verifier(report_, &transport);
hbos23351192017-01-02 06:52:19 -0800604 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_sent);
605 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_received);
hbosdb346a72016-11-29 01:57:01 -0800606 verifier.TestMemberIsOptionalIDReference(
607 transport.rtcp_transport_stats_id, RTCTransportStats::kType);
hbos7064d592017-01-16 07:38:02 -0800608 verifier.TestMemberIsDefined(transport.dtls_state);
hbos7bf53692016-12-15 03:33:35 -0800609 verifier.TestMemberIsIDReference(
610 transport.selected_candidate_pair_id, RTCIceCandidatePairStats::kType);
611 verifier.TestMemberIsIDReference(
612 transport.local_certificate_id, RTCCertificateStats::kType);
613 verifier.TestMemberIsIDReference(
614 transport.remote_certificate_id, RTCCertificateStats::kType);
hbosdb346a72016-11-29 01:57:01 -0800615 return verifier.ExpectAllMembersSuccessfullyTested();
616 }
617
618 private:
619 rtc::scoped_refptr<const RTCStatsReport> report_;
620};
621
deadbeef40610e22016-12-22 10:53:38 -0800622#ifdef HAVE_SCTP
hbosdb346a72016-11-29 01:57:01 -0800623TEST_F(RTCStatsIntegrationTest, GetStatsFromCaller) {
624 StartCall();
625
626 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCaller();
627 RTCStatsReportVerifier(report.get()).VerifyReport();
628}
629
630TEST_F(RTCStatsIntegrationTest, GetStatsFromCallee) {
631 StartCall();
632
633 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCallee();
634 RTCStatsReportVerifier(report.get()).VerifyReport();
635}
636
hbosb78306a2016-12-19 05:06:57 -0800637TEST_F(RTCStatsIntegrationTest, GetsStatsWhileDestroyingPeerConnections) {
638 StartCall();
639
640 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer =
641 RTCStatsObtainer::Create();
642 caller_->pc()->GetStats(stats_obtainer);
643 // This will destroy the peer connection.
644 caller_ = nullptr;
645 // Any pending stats requests should have completed in the act of destroying
646 // the peer connection.
647 EXPECT_TRUE(stats_obtainer->report());
648}
deadbeef40610e22016-12-22 10:53:38 -0800649#endif // HAVE_SCTP
hbosb78306a2016-12-19 05:06:57 -0800650
hbosdb346a72016-11-29 01:57:01 -0800651} // namespace
652
653} // namespace webrtc