OLD | NEW |
| (Empty) |
1 /* | |
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 "webrtc/api/rtcstatscollector.h" | |
12 | |
13 #include <memory> | |
14 #include <ostream> | |
15 #include <string> | |
16 #include <vector> | |
17 | |
18 #include "webrtc/api/mediastream.h" | |
19 #include "webrtc/api/mediastreamtrack.h" | |
20 #include "webrtc/api/jsepsessiondescription.h" | |
21 #include "webrtc/api/stats/rtcstats_objects.h" | |
22 #include "webrtc/api/stats/rtcstatsreport.h" | |
23 #include "webrtc/api/test/mock_datachannel.h" | |
24 #include "webrtc/api/test/mock_peerconnection.h" | |
25 #include "webrtc/api/test/mock_webrtcsession.h" | |
26 #include "webrtc/base/checks.h" | |
27 #include "webrtc/base/fakeclock.h" | |
28 #include "webrtc/base/fakesslidentity.h" | |
29 #include "webrtc/base/gunit.h" | |
30 #include "webrtc/base/logging.h" | |
31 #include "webrtc/base/socketaddress.h" | |
32 #include "webrtc/base/thread_checker.h" | |
33 #include "webrtc/base/timedelta.h" | |
34 #include "webrtc/base/timeutils.h" | |
35 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" | |
36 #include "webrtc/media/base/fakemediaengine.h" | |
37 #include "webrtc/media/base/test/mock_mediachannel.h" | |
38 #include "webrtc/p2p/base/p2pconstants.h" | |
39 #include "webrtc/p2p/base/port.h" | |
40 | |
41 using testing::_; | |
42 using testing::Invoke; | |
43 using testing::Return; | |
44 using testing::ReturnNull; | |
45 using testing::ReturnRef; | |
46 using testing::SetArgPointee; | |
47 | |
48 namespace webrtc { | |
49 | |
50 // These are used by gtest code, such as if |EXPECT_EQ| fails. | |
51 void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) { | |
52 *os << stats.ToString(); | |
53 } | |
54 | |
55 void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) { | |
56 *os << stats.ToString(); | |
57 } | |
58 | |
59 void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) { | |
60 *os << stats.ToString(); | |
61 } | |
62 | |
63 void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) { | |
64 *os << stats.ToString(); | |
65 } | |
66 | |
67 void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) { | |
68 *os << stats.ToString(); | |
69 } | |
70 | |
71 void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) { | |
72 *os << stats.ToString(); | |
73 } | |
74 | |
75 void PrintTo(const RTCMediaStreamStats& stats, ::std::ostream* os) { | |
76 *os << stats.ToString(); | |
77 } | |
78 | |
79 void PrintTo(const RTCMediaStreamTrackStats& stats, ::std::ostream* os) { | |
80 *os << stats.ToString(); | |
81 } | |
82 | |
83 void PrintTo(const RTCInboundRTPStreamStats& stats, ::std::ostream* os) { | |
84 *os << stats.ToString(); | |
85 } | |
86 | |
87 void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) { | |
88 *os << stats.ToString(); | |
89 } | |
90 | |
91 void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) { | |
92 *os << stats.ToString(); | |
93 } | |
94 | |
95 namespace { | |
96 | |
97 const int64_t kGetStatsReportTimeoutMs = 1000; | |
98 | |
99 struct CertificateInfo { | |
100 rtc::scoped_refptr<rtc::RTCCertificate> certificate; | |
101 std::vector<std::string> ders; | |
102 std::vector<std::string> pems; | |
103 std::vector<std::string> fingerprints; | |
104 }; | |
105 | |
106 std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers( | |
107 const std::vector<std::string>& ders) { | |
108 RTC_CHECK(!ders.empty()); | |
109 std::unique_ptr<CertificateInfo> info(new CertificateInfo()); | |
110 info->ders = ders; | |
111 for (const std::string& der : ders) { | |
112 info->pems.push_back(rtc::SSLIdentity::DerToPem( | |
113 "CERTIFICATE", | |
114 reinterpret_cast<const unsigned char*>(der.c_str()), | |
115 der.length())); | |
116 } | |
117 info->certificate = | |
118 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>( | |
119 new rtc::FakeSSLIdentity(rtc::FakeSSLCertificate(info->pems)))); | |
120 // Strip header/footer and newline characters of PEM strings. | |
121 for (size_t i = 0; i < info->pems.size(); ++i) { | |
122 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, | |
123 "", 0, &info->pems[i]); | |
124 rtc::replace_substrs("-----END CERTIFICATE-----", 25, | |
125 "", 0, &info->pems[i]); | |
126 rtc::replace_substrs("\n", 1, | |
127 "", 0, &info->pems[i]); | |
128 } | |
129 // Fingerprint of leaf certificate. | |
130 std::unique_ptr<rtc::SSLFingerprint> fp( | |
131 rtc::SSLFingerprint::Create("sha-1", | |
132 &info->certificate->ssl_certificate())); | |
133 EXPECT_TRUE(fp); | |
134 info->fingerprints.push_back(fp->GetRfc4572Fingerprint()); | |
135 // Fingerprints of the rest of the chain. | |
136 std::unique_ptr<rtc::SSLCertChain> chain = | |
137 info->certificate->ssl_certificate().GetChain(); | |
138 if (chain) { | |
139 for (size_t i = 0; i < chain->GetSize(); i++) { | |
140 fp.reset(rtc::SSLFingerprint::Create("sha-1", &chain->Get(i))); | |
141 EXPECT_TRUE(fp); | |
142 info->fingerprints.push_back(fp->GetRfc4572Fingerprint()); | |
143 } | |
144 } | |
145 EXPECT_EQ(info->ders.size(), info->fingerprints.size()); | |
146 return info; | |
147 } | |
148 | |
149 std::unique_ptr<cricket::Candidate> CreateFakeCandidate( | |
150 const std::string& hostname, | |
151 int port, | |
152 const std::string& protocol, | |
153 const std::string& candidate_type, | |
154 uint32_t priority) { | |
155 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate()); | |
156 candidate->set_address(rtc::SocketAddress(hostname, port)); | |
157 candidate->set_protocol(protocol); | |
158 candidate->set_type(candidate_type); | |
159 candidate->set_priority(priority); | |
160 return candidate; | |
161 } | |
162 | |
163 class FakeAudioProcessorForStats | |
164 : public rtc::RefCountedObject<AudioProcessorInterface> { | |
165 public: | |
166 FakeAudioProcessorForStats( | |
167 AudioProcessorInterface::AudioProcessorStats stats) | |
168 : stats_(stats) { | |
169 } | |
170 | |
171 void GetStats(AudioProcessorInterface::AudioProcessorStats* stats) override { | |
172 *stats = stats_; | |
173 } | |
174 | |
175 private: | |
176 AudioProcessorInterface::AudioProcessorStats stats_; | |
177 }; | |
178 | |
179 class FakeAudioTrackForStats | |
180 : public MediaStreamTrack<AudioTrackInterface> { | |
181 public: | |
182 static rtc::scoped_refptr<FakeAudioTrackForStats> Create( | |
183 const std::string& id, | |
184 MediaStreamTrackInterface::TrackState state, | |
185 int signal_level, | |
186 rtc::scoped_refptr<FakeAudioProcessorForStats> processor) { | |
187 rtc::scoped_refptr<FakeAudioTrackForStats> audio_track_stats( | |
188 new rtc::RefCountedObject<FakeAudioTrackForStats>( | |
189 id, signal_level, processor)); | |
190 audio_track_stats->set_state(state); | |
191 return audio_track_stats; | |
192 } | |
193 | |
194 FakeAudioTrackForStats( | |
195 const std::string& id, | |
196 int signal_level, | |
197 rtc::scoped_refptr<FakeAudioProcessorForStats> processor) | |
198 : MediaStreamTrack<AudioTrackInterface>(id), | |
199 signal_level_(signal_level), | |
200 processor_(processor) { | |
201 } | |
202 | |
203 std::string kind() const override { | |
204 return MediaStreamTrackInterface::kAudioKind; | |
205 } | |
206 webrtc::AudioSourceInterface* GetSource() const override { return nullptr; } | |
207 void AddSink(webrtc::AudioTrackSinkInterface* sink) override {} | |
208 void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override {} | |
209 bool GetSignalLevel(int* level) override { | |
210 *level = signal_level_; | |
211 return true; | |
212 } | |
213 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override { | |
214 return processor_; | |
215 } | |
216 | |
217 private: | |
218 int signal_level_; | |
219 rtc::scoped_refptr<FakeAudioProcessorForStats> processor_; | |
220 }; | |
221 | |
222 class FakeVideoTrackSourceForStats | |
223 : public rtc::RefCountedObject<VideoTrackSourceInterface> { | |
224 public: | |
225 FakeVideoTrackSourceForStats(VideoTrackSourceInterface::Stats stats) | |
226 : stats_(stats) { | |
227 } | |
228 | |
229 MediaSourceInterface::SourceState state() const override { | |
230 return MediaSourceInterface::kLive; | |
231 } | |
232 bool remote() const override { return false; } | |
233 void RegisterObserver(ObserverInterface* observer) override {} | |
234 void UnregisterObserver(ObserverInterface* observer) override {} | |
235 void AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink, | |
236 const rtc::VideoSinkWants& wants) override {} | |
237 void RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) override { | |
238 } | |
239 bool is_screencast() const override { return false; } | |
240 rtc::Optional<bool> needs_denoising() const override { | |
241 return rtc::Optional<bool>(); | |
242 } | |
243 bool GetStats(VideoTrackSourceInterface::Stats* stats) override { | |
244 *stats = stats_; | |
245 return true; | |
246 } | |
247 | |
248 private: | |
249 VideoTrackSourceInterface::Stats stats_; | |
250 }; | |
251 | |
252 class FakeVideoTrackForStats | |
253 : public MediaStreamTrack<VideoTrackInterface> { | |
254 public: | |
255 static rtc::scoped_refptr<FakeVideoTrackForStats> Create( | |
256 const std::string& id, | |
257 MediaStreamTrackInterface::TrackState state, | |
258 rtc::scoped_refptr<VideoTrackSourceInterface> source) { | |
259 rtc::scoped_refptr<FakeVideoTrackForStats> video_track( | |
260 new rtc::RefCountedObject<FakeVideoTrackForStats>(id, source)); | |
261 video_track->set_state(state); | |
262 return video_track; | |
263 } | |
264 | |
265 FakeVideoTrackForStats( | |
266 const std::string& id, | |
267 rtc::scoped_refptr<VideoTrackSourceInterface> source) | |
268 : MediaStreamTrack<VideoTrackInterface>(id), | |
269 source_(source) { | |
270 } | |
271 | |
272 std::string kind() const override { | |
273 return MediaStreamTrackInterface::kVideoKind; | |
274 } | |
275 VideoTrackSourceInterface* GetSource() const override { | |
276 return source_; | |
277 } | |
278 | |
279 private: | |
280 rtc::scoped_refptr<VideoTrackSourceInterface> source_; | |
281 }; | |
282 | |
283 class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver { | |
284 public: | |
285 RTCStatsCollectorTestHelper() | |
286 : worker_thread_(rtc::Thread::Current()), | |
287 network_thread_(rtc::Thread::Current()), | |
288 media_engine_(new cricket::FakeMediaEngine()), | |
289 channel_manager_( | |
290 new cricket::ChannelManager(media_engine_, | |
291 worker_thread_, | |
292 network_thread_)), | |
293 media_controller_( | |
294 MediaControllerInterface::Create(cricket::MediaConfig(), | |
295 worker_thread_, | |
296 channel_manager_.get(), | |
297 &event_log_)), | |
298 session_(media_controller_.get()), | |
299 pc_() { | |
300 // Default return values for mocks. | |
301 EXPECT_CALL(pc_, local_streams()).WillRepeatedly(Return(nullptr)); | |
302 EXPECT_CALL(pc_, remote_streams()).WillRepeatedly(Return(nullptr)); | |
303 EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_)); | |
304 EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly( | |
305 ReturnRef(data_channels_)); | |
306 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); | |
307 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); | |
308 EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false)); | |
309 EXPECT_CALL(session_, GetLocalCertificate(_, _)).WillRepeatedly( | |
310 Return(false)); | |
311 EXPECT_CALL(session_, GetRemoteSSLCertificate_ReturnsRawPointer(_)) | |
312 .WillRepeatedly(Return(nullptr)); | |
313 } | |
314 | |
315 rtc::ScopedFakeClock& fake_clock() { return fake_clock_; } | |
316 rtc::Thread* worker_thread() { return worker_thread_; } | |
317 rtc::Thread* network_thread() { return network_thread_; } | |
318 cricket::FakeMediaEngine* media_engine() { return media_engine_; } | |
319 MockWebRtcSession& session() { return session_; } | |
320 MockPeerConnection& pc() { return pc_; } | |
321 std::vector<rtc::scoped_refptr<DataChannel>>& data_channels() { | |
322 return data_channels_; | |
323 } | |
324 | |
325 // SetSessionDescriptionObserver overrides. | |
326 void OnSuccess() override {} | |
327 void OnFailure(const std::string& error) override { | |
328 RTC_NOTREACHED() << error; | |
329 } | |
330 | |
331 private: | |
332 rtc::ScopedFakeClock fake_clock_; | |
333 RtcEventLogNullImpl event_log_; | |
334 rtc::Thread* const worker_thread_; | |
335 rtc::Thread* const network_thread_; | |
336 cricket::FakeMediaEngine* media_engine_; | |
337 std::unique_ptr<cricket::ChannelManager> channel_manager_; | |
338 std::unique_ptr<MediaControllerInterface> media_controller_; | |
339 MockWebRtcSession session_; | |
340 MockPeerConnection pc_; | |
341 | |
342 std::vector<rtc::scoped_refptr<DataChannel>> data_channels_; | |
343 }; | |
344 | |
345 class RTCTestStats : public RTCStats { | |
346 public: | |
347 WEBRTC_RTCSTATS_DECL(); | |
348 | |
349 RTCTestStats(const std::string& id, int64_t timestamp_us) | |
350 : RTCStats(id, timestamp_us), | |
351 dummy_stat("dummyStat") {} | |
352 | |
353 RTCStatsMember<int32_t> dummy_stat; | |
354 }; | |
355 | |
356 WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", | |
357 &dummy_stat); | |
358 | |
359 // Overrides the stats collection to verify thread usage and that the resulting | |
360 // partial reports are merged. | |
361 class FakeRTCStatsCollector : public RTCStatsCollector, | |
362 public RTCStatsCollectorCallback { | |
363 public: | |
364 static rtc::scoped_refptr<FakeRTCStatsCollector> Create( | |
365 PeerConnection* pc, | |
366 int64_t cache_lifetime_us) { | |
367 return rtc::scoped_refptr<FakeRTCStatsCollector>( | |
368 new rtc::RefCountedObject<FakeRTCStatsCollector>( | |
369 pc, cache_lifetime_us)); | |
370 } | |
371 | |
372 // RTCStatsCollectorCallback implementation. | |
373 void OnStatsDelivered( | |
374 const rtc::scoped_refptr<const RTCStatsReport>& report) override { | |
375 EXPECT_TRUE(signaling_thread_->IsCurrent()); | |
376 rtc::CritScope cs(&lock_); | |
377 delivered_report_ = report; | |
378 } | |
379 | |
380 void VerifyThreadUsageAndResultsMerging() { | |
381 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this)); | |
382 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs); | |
383 } | |
384 | |
385 bool HasVerifiedResults() { | |
386 EXPECT_TRUE(signaling_thread_->IsCurrent()); | |
387 rtc::CritScope cs(&lock_); | |
388 if (!delivered_report_) | |
389 return false; | |
390 EXPECT_EQ(produced_on_signaling_thread_, 1); | |
391 EXPECT_EQ(produced_on_worker_thread_, 1); | |
392 EXPECT_EQ(produced_on_network_thread_, 1); | |
393 | |
394 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats")); | |
395 EXPECT_TRUE(delivered_report_->Get("WorkerThreadStats")); | |
396 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats")); | |
397 | |
398 produced_on_signaling_thread_ = 0; | |
399 produced_on_worker_thread_ = 0; | |
400 produced_on_network_thread_ = 0; | |
401 delivered_report_ = nullptr; | |
402 return true; | |
403 } | |
404 | |
405 protected: | |
406 FakeRTCStatsCollector( | |
407 PeerConnection* pc, | |
408 int64_t cache_lifetime) | |
409 : RTCStatsCollector(pc, cache_lifetime), | |
410 signaling_thread_(pc->session()->signaling_thread()), | |
411 worker_thread_(pc->session()->worker_thread()), | |
412 network_thread_(pc->session()->network_thread()) { | |
413 } | |
414 | |
415 void ProducePartialResultsOnSignalingThread(int64_t timestamp_us) override { | |
416 EXPECT_TRUE(signaling_thread_->IsCurrent()); | |
417 { | |
418 rtc::CritScope cs(&lock_); | |
419 EXPECT_FALSE(delivered_report_); | |
420 ++produced_on_signaling_thread_; | |
421 } | |
422 | |
423 rtc::scoped_refptr<RTCStatsReport> signaling_report = | |
424 RTCStatsReport::Create(0); | |
425 signaling_report->AddStats(std::unique_ptr<const RTCStats>( | |
426 new RTCTestStats("SignalingThreadStats", timestamp_us))); | |
427 AddPartialResults(signaling_report); | |
428 } | |
429 void ProducePartialResultsOnWorkerThread(int64_t timestamp_us) override { | |
430 EXPECT_TRUE(worker_thread_->IsCurrent()); | |
431 { | |
432 rtc::CritScope cs(&lock_); | |
433 EXPECT_FALSE(delivered_report_); | |
434 ++produced_on_worker_thread_; | |
435 } | |
436 | |
437 rtc::scoped_refptr<RTCStatsReport> worker_report = | |
438 RTCStatsReport::Create(0); | |
439 worker_report->AddStats(std::unique_ptr<const RTCStats>( | |
440 new RTCTestStats("WorkerThreadStats", timestamp_us))); | |
441 AddPartialResults(worker_report); | |
442 } | |
443 void ProducePartialResultsOnNetworkThread(int64_t timestamp_us) override { | |
444 EXPECT_TRUE(network_thread_->IsCurrent()); | |
445 { | |
446 rtc::CritScope cs(&lock_); | |
447 EXPECT_FALSE(delivered_report_); | |
448 ++produced_on_network_thread_; | |
449 } | |
450 | |
451 rtc::scoped_refptr<RTCStatsReport> network_report = | |
452 RTCStatsReport::Create(0); | |
453 network_report->AddStats(std::unique_ptr<const RTCStats>( | |
454 new RTCTestStats("NetworkThreadStats", timestamp_us))); | |
455 AddPartialResults(network_report); | |
456 } | |
457 | |
458 private: | |
459 rtc::Thread* const signaling_thread_; | |
460 rtc::Thread* const worker_thread_; | |
461 rtc::Thread* const network_thread_; | |
462 | |
463 rtc::CriticalSection lock_; | |
464 rtc::scoped_refptr<const RTCStatsReport> delivered_report_; | |
465 int produced_on_signaling_thread_ = 0; | |
466 int produced_on_worker_thread_ = 0; | |
467 int produced_on_network_thread_ = 0; | |
468 }; | |
469 | |
470 class StatsCallback : public RTCStatsCollectorCallback { | |
471 public: | |
472 static rtc::scoped_refptr<StatsCallback> Create( | |
473 rtc::scoped_refptr<const RTCStatsReport>* report_ptr = nullptr) { | |
474 return rtc::scoped_refptr<StatsCallback>( | |
475 new rtc::RefCountedObject<StatsCallback>(report_ptr)); | |
476 } | |
477 | |
478 void OnStatsDelivered( | |
479 const rtc::scoped_refptr<const RTCStatsReport>& report) override { | |
480 EXPECT_TRUE(thread_checker_.CalledOnValidThread()); | |
481 report_ = report; | |
482 if (report_ptr_) | |
483 *report_ptr_ = report_; | |
484 } | |
485 | |
486 rtc::scoped_refptr<const RTCStatsReport> report() const { | |
487 EXPECT_TRUE(thread_checker_.CalledOnValidThread()); | |
488 return report_; | |
489 } | |
490 | |
491 protected: | |
492 explicit StatsCallback(rtc::scoped_refptr<const RTCStatsReport>* report_ptr) | |
493 : report_ptr_(report_ptr) {} | |
494 | |
495 private: | |
496 rtc::ThreadChecker thread_checker_; | |
497 rtc::scoped_refptr<const RTCStatsReport> report_; | |
498 rtc::scoped_refptr<const RTCStatsReport>* report_ptr_; | |
499 }; | |
500 | |
501 class RTCStatsCollectorTest : public testing::Test { | |
502 public: | |
503 RTCStatsCollectorTest() | |
504 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()), | |
505 collector_(RTCStatsCollector::Create( | |
506 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) { | |
507 } | |
508 | |
509 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() { | |
510 rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create(); | |
511 collector_->GetStatsReport(callback); | |
512 EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs); | |
513 int64_t after = rtc::TimeUTCMicros(); | |
514 for (const RTCStats& stats : *callback->report()) { | |
515 EXPECT_LE(stats.timestamp_us(), after); | |
516 } | |
517 return callback->report(); | |
518 } | |
519 | |
520 const RTCIceCandidateStats* ExpectReportContainsCandidate( | |
521 const rtc::scoped_refptr<const RTCStatsReport>& report, | |
522 const cricket::Candidate& candidate, | |
523 bool is_local) { | |
524 const RTCStats* stats = report->Get("RTCIceCandidate_" + candidate.id()); | |
525 EXPECT_TRUE(stats); | |
526 const RTCIceCandidateStats* candidate_stats; | |
527 if (is_local) | |
528 candidate_stats = &stats->cast_to<RTCLocalIceCandidateStats>(); | |
529 else | |
530 candidate_stats = &stats->cast_to<RTCRemoteIceCandidateStats>(); | |
531 EXPECT_EQ(*candidate_stats->ip, candidate.address().ipaddr().ToString()); | |
532 EXPECT_EQ(*candidate_stats->port, | |
533 static_cast<int32_t>(candidate.address().port())); | |
534 EXPECT_EQ(*candidate_stats->protocol, candidate.protocol()); | |
535 EXPECT_EQ(*candidate_stats->candidate_type, | |
536 CandidateTypeToRTCIceCandidateTypeForTesting(candidate.type())); | |
537 EXPECT_EQ(*candidate_stats->priority, | |
538 static_cast<int32_t>(candidate.priority())); | |
539 // TODO(hbos): Define candidate_stats->url. crbug.com/632723 | |
540 EXPECT_FALSE(candidate_stats->url.is_defined()); | |
541 return candidate_stats; | |
542 } | |
543 | |
544 void ExpectReportContainsCandidatePair( | |
545 const rtc::scoped_refptr<const RTCStatsReport>& report, | |
546 const cricket::TransportStats& transport_stats) { | |
547 for (const auto& channel_stats : transport_stats.channel_stats) { | |
548 for (const cricket::ConnectionInfo& info : | |
549 channel_stats.connection_infos) { | |
550 const std::string& id = "RTCIceCandidatePair_" + | |
551 info.local_candidate.id() + "_" + info.remote_candidate.id(); | |
552 const RTCStats* stats = report->Get(id); | |
553 ASSERT_TRUE(stats); | |
554 const RTCIceCandidatePairStats& candidate_pair_stats = | |
555 stats->cast_to<RTCIceCandidatePairStats>(); | |
556 | |
557 // TODO(hbos): Define all the undefined |candidate_pair_stats| stats. | |
558 // The EXPECT_FALSE are for the undefined stats, see also todos listed | |
559 // in rtcstats_objects.h. crbug.com/633550 | |
560 EXPECT_FALSE(candidate_pair_stats.transport_id.is_defined()); | |
561 const RTCIceCandidateStats* local_candidate = | |
562 ExpectReportContainsCandidate(report, info.local_candidate, true); | |
563 EXPECT_EQ(*candidate_pair_stats.local_candidate_id, | |
564 local_candidate->id()); | |
565 const RTCIceCandidateStats* remote_candidate = | |
566 ExpectReportContainsCandidate(report, info.remote_candidate, false); | |
567 EXPECT_EQ(*candidate_pair_stats.remote_candidate_id, | |
568 remote_candidate->id()); | |
569 | |
570 EXPECT_FALSE(candidate_pair_stats.state.is_defined()); | |
571 EXPECT_FALSE(candidate_pair_stats.priority.is_defined()); | |
572 EXPECT_FALSE(candidate_pair_stats.nominated.is_defined()); | |
573 EXPECT_EQ(*candidate_pair_stats.writable, info.writable); | |
574 EXPECT_FALSE(candidate_pair_stats.readable.is_defined()); | |
575 EXPECT_EQ(*candidate_pair_stats.bytes_sent, | |
576 static_cast<uint64_t>(info.sent_total_bytes)); | |
577 EXPECT_EQ(*candidate_pair_stats.bytes_received, | |
578 static_cast<uint64_t>(info.recv_total_bytes)); | |
579 EXPECT_FALSE(candidate_pair_stats.total_rtt.is_defined()); | |
580 EXPECT_EQ(*candidate_pair_stats.current_rtt, | |
581 static_cast<double>(info.rtt) / 1000.0); | |
582 EXPECT_FALSE( | |
583 candidate_pair_stats.available_outgoing_bitrate.is_defined()); | |
584 EXPECT_FALSE( | |
585 candidate_pair_stats.available_incoming_bitrate.is_defined()); | |
586 EXPECT_FALSE(candidate_pair_stats.requests_received.is_defined()); | |
587 EXPECT_EQ(*candidate_pair_stats.requests_sent, | |
588 static_cast<uint64_t>(info.sent_ping_requests_total)); | |
589 EXPECT_EQ(*candidate_pair_stats.responses_received, | |
590 static_cast<uint64_t>(info.recv_ping_responses)); | |
591 EXPECT_EQ(*candidate_pair_stats.responses_sent, | |
592 static_cast<uint64_t>(info.sent_ping_responses)); | |
593 EXPECT_FALSE( | |
594 candidate_pair_stats.retransmissions_received.is_defined()); | |
595 EXPECT_FALSE(candidate_pair_stats.retransmissions_sent.is_defined()); | |
596 EXPECT_FALSE( | |
597 candidate_pair_stats.consent_requests_received.is_defined()); | |
598 EXPECT_FALSE(candidate_pair_stats.consent_requests_sent.is_defined()); | |
599 EXPECT_FALSE( | |
600 candidate_pair_stats.consent_responses_received.is_defined()); | |
601 EXPECT_FALSE(candidate_pair_stats.consent_responses_sent.is_defined()); | |
602 } | |
603 } | |
604 } | |
605 | |
606 void ExpectReportContainsCertificateInfo( | |
607 const rtc::scoped_refptr<const RTCStatsReport>& report, | |
608 const CertificateInfo& cert_info) { | |
609 for (size_t i = 0; i < cert_info.fingerprints.size(); ++i) { | |
610 const RTCStats* stats = report->Get( | |
611 "RTCCertificate_" + cert_info.fingerprints[i]); | |
612 ASSERT_TRUE(stats); | |
613 const RTCCertificateStats& cert_stats = | |
614 stats->cast_to<const RTCCertificateStats>(); | |
615 EXPECT_EQ(*cert_stats.fingerprint, cert_info.fingerprints[i]); | |
616 EXPECT_EQ(*cert_stats.fingerprint_algorithm, "sha-1"); | |
617 EXPECT_EQ(*cert_stats.base64_certificate, cert_info.pems[i]); | |
618 if (i + 1 < cert_info.fingerprints.size()) { | |
619 EXPECT_EQ(*cert_stats.issuer_certificate_id, | |
620 "RTCCertificate_" + cert_info.fingerprints[i + 1]); | |
621 } else { | |
622 EXPECT_FALSE(cert_stats.issuer_certificate_id.is_defined()); | |
623 } | |
624 } | |
625 } | |
626 | |
627 void ExpectReportContainsTransportStats( | |
628 const rtc::scoped_refptr<const RTCStatsReport>& report, | |
629 const cricket::TransportStats& transport, | |
630 const CertificateInfo* local_certinfo, | |
631 const CertificateInfo* remote_certinfo) { | |
632 std::string rtcp_transport_stats_id; | |
633 for (const auto& channel_stats : transport.channel_stats) { | |
634 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) { | |
635 rtcp_transport_stats_id = "RTCTransport_" + transport.transport_name + | |
636 "_" + rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTCP); | |
637 } | |
638 } | |
639 for (const auto& channel_stats : transport.channel_stats) { | |
640 const cricket::ConnectionInfo* best_connection_info = nullptr; | |
641 const RTCStats* stats = report->Get( | |
642 "RTCTransport_" + transport.transport_name + "_" + | |
643 rtc::ToString<>(channel_stats.component)); | |
644 ASSERT_TRUE(stats); | |
645 const RTCTransportStats& transport_stats = | |
646 stats->cast_to<const RTCTransportStats>(); | |
647 uint64_t bytes_sent = 0; | |
648 uint64_t bytes_received = 0; | |
649 for (const cricket::ConnectionInfo& info : | |
650 channel_stats.connection_infos) { | |
651 bytes_sent += info.sent_total_bytes; | |
652 bytes_received += info.recv_total_bytes; | |
653 if (info.best_connection) | |
654 best_connection_info = &info; | |
655 } | |
656 EXPECT_EQ(*transport_stats.bytes_sent, bytes_sent); | |
657 EXPECT_EQ(*transport_stats.bytes_received, bytes_received); | |
658 if (best_connection_info) { | |
659 EXPECT_EQ(*transport_stats.active_connection, true); | |
660 // TODO(hbos): Instead of testing how the ID looks, test that the | |
661 // corresponding pair's IP addresses are equal to the IP addresses of | |
662 // the |best_connection_info| data. crbug.com/653873 | |
663 EXPECT_EQ(*transport_stats.selected_candidate_pair_id, | |
664 "RTCIceCandidatePair_" + | |
665 best_connection_info->local_candidate.id() + "_" + | |
666 best_connection_info->remote_candidate.id()); | |
667 EXPECT_TRUE(report->Get(*transport_stats.selected_candidate_pair_id)); | |
668 } else { | |
669 EXPECT_EQ(*transport_stats.active_connection, false); | |
670 EXPECT_FALSE(transport_stats.selected_candidate_pair_id.is_defined()); | |
671 } | |
672 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP && | |
673 !rtcp_transport_stats_id.empty()) { | |
674 EXPECT_EQ(*transport_stats.rtcp_transport_stats_id, | |
675 rtcp_transport_stats_id); | |
676 } else { | |
677 EXPECT_FALSE(transport_stats.rtcp_transport_stats_id.is_defined()); | |
678 } | |
679 if (local_certinfo && remote_certinfo) { | |
680 EXPECT_EQ(*transport_stats.local_certificate_id, | |
681 "RTCCertificate_" + local_certinfo->fingerprints[0]); | |
682 EXPECT_EQ(*transport_stats.remote_certificate_id, | |
683 "RTCCertificate_" + remote_certinfo->fingerprints[0]); | |
684 EXPECT_TRUE(report->Get(*transport_stats.local_certificate_id)); | |
685 EXPECT_TRUE(report->Get(*transport_stats.remote_certificate_id)); | |
686 } else { | |
687 EXPECT_FALSE(transport_stats.local_certificate_id.is_defined()); | |
688 EXPECT_FALSE(transport_stats.remote_certificate_id.is_defined()); | |
689 } | |
690 } | |
691 } | |
692 | |
693 void ExpectReportContainsDataChannel( | |
694 const rtc::scoped_refptr<const RTCStatsReport>& report, | |
695 const DataChannel& data_channel) { | |
696 const RTCStats* stats = report->Get("RTCDataChannel_" + | |
697 rtc::ToString<>(data_channel.id())); | |
698 EXPECT_TRUE(stats); | |
699 const RTCDataChannelStats& data_channel_stats = | |
700 stats->cast_to<const RTCDataChannelStats>(); | |
701 EXPECT_EQ(*data_channel_stats.label, data_channel.label()); | |
702 EXPECT_EQ(*data_channel_stats.protocol, data_channel.protocol()); | |
703 EXPECT_EQ(*data_channel_stats.datachannelid, data_channel.id()); | |
704 EXPECT_EQ(*data_channel_stats.state, | |
705 DataStateToRTCDataChannelStateForTesting(data_channel.state())); | |
706 EXPECT_EQ(*data_channel_stats.messages_sent, data_channel.messages_sent()); | |
707 EXPECT_EQ(*data_channel_stats.bytes_sent, data_channel.bytes_sent()); | |
708 EXPECT_EQ(*data_channel_stats.messages_received, | |
709 data_channel.messages_received()); | |
710 EXPECT_EQ(*data_channel_stats.bytes_received, | |
711 data_channel.bytes_received()); | |
712 } | |
713 | |
714 protected: | |
715 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_; | |
716 rtc::scoped_refptr<RTCStatsCollector> collector_; | |
717 }; | |
718 | |
719 TEST_F(RTCStatsCollectorTest, SingleCallback) { | |
720 rtc::scoped_refptr<const RTCStatsReport> result; | |
721 collector_->GetStatsReport(StatsCallback::Create(&result)); | |
722 EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs); | |
723 } | |
724 | |
725 TEST_F(RTCStatsCollectorTest, MultipleCallbacks) { | |
726 rtc::scoped_refptr<const RTCStatsReport> a; | |
727 rtc::scoped_refptr<const RTCStatsReport> b; | |
728 rtc::scoped_refptr<const RTCStatsReport> c; | |
729 collector_->GetStatsReport(StatsCallback::Create(&a)); | |
730 collector_->GetStatsReport(StatsCallback::Create(&b)); | |
731 collector_->GetStatsReport(StatsCallback::Create(&c)); | |
732 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); | |
733 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); | |
734 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); | |
735 EXPECT_EQ(a.get(), b.get()); | |
736 EXPECT_EQ(b.get(), c.get()); | |
737 } | |
738 | |
739 TEST_F(RTCStatsCollectorTest, CachedStatsReports) { | |
740 // Caching should ensure |a| and |b| are the same report. | |
741 rtc::scoped_refptr<const RTCStatsReport> a = GetStatsReport(); | |
742 rtc::scoped_refptr<const RTCStatsReport> b = GetStatsReport(); | |
743 EXPECT_EQ(a.get(), b.get()); | |
744 // Invalidate cache by clearing it. | |
745 collector_->ClearCachedStatsReport(); | |
746 rtc::scoped_refptr<const RTCStatsReport> c = GetStatsReport(); | |
747 EXPECT_NE(b.get(), c.get()); | |
748 // Invalidate cache by advancing time. | |
749 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51)); | |
750 rtc::scoped_refptr<const RTCStatsReport> d = GetStatsReport(); | |
751 EXPECT_TRUE(d); | |
752 EXPECT_NE(c.get(), d.get()); | |
753 } | |
754 | |
755 TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) { | |
756 rtc::scoped_refptr<const RTCStatsReport> a; | |
757 rtc::scoped_refptr<const RTCStatsReport> b; | |
758 rtc::scoped_refptr<const RTCStatsReport> c; | |
759 collector_->GetStatsReport(StatsCallback::Create(&a)); | |
760 collector_->GetStatsReport(StatsCallback::Create(&b)); | |
761 // Cache is invalidated after 50 ms. | |
762 test_->fake_clock().AdvanceTime(rtc::TimeDelta::FromMilliseconds(51)); | |
763 collector_->GetStatsReport(StatsCallback::Create(&c)); | |
764 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); | |
765 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); | |
766 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); | |
767 EXPECT_EQ(a.get(), b.get()); | |
768 // The act of doing |AdvanceTime| processes all messages. If this was not the | |
769 // case we might not require |c| to be fresher than |b|. | |
770 EXPECT_NE(c.get(), b.get()); | |
771 } | |
772 | |
773 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) { | |
774 std::unique_ptr<CertificateInfo> local_certinfo = | |
775 CreateFakeCertificateAndInfoFromDers( | |
776 std::vector<std::string>({ "(local) single certificate" })); | |
777 std::unique_ptr<CertificateInfo> remote_certinfo = | |
778 CreateFakeCertificateAndInfoFromDers( | |
779 std::vector<std::string>({ "(remote) single certificate" })); | |
780 | |
781 // Mock the session to return the local and remote certificates. | |
782 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
783 [this](SessionStats* stats) { | |
784 stats->transport_stats["transport"].transport_name = "transport"; | |
785 return true; | |
786 })); | |
787 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( | |
788 Invoke([this, &local_certinfo](const std::string& transport_name, | |
789 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
790 if (transport_name == "transport") { | |
791 *certificate = local_certinfo->certificate; | |
792 return true; | |
793 } | |
794 return false; | |
795 })); | |
796 EXPECT_CALL(test_->session(), | |
797 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( | |
798 [this, &remote_certinfo](const std::string& transport_name) { | |
799 if (transport_name == "transport") | |
800 return remote_certinfo->certificate->ssl_certificate().GetReference(); | |
801 return static_cast<rtc::SSLCertificate*>(nullptr); | |
802 })); | |
803 | |
804 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
805 ExpectReportContainsCertificateInfo(report, *local_certinfo.get()); | |
806 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get()); | |
807 } | |
808 | |
809 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) { | |
810 std::unique_ptr<CertificateInfo> audio_local_certinfo = | |
811 CreateFakeCertificateAndInfoFromDers( | |
812 std::vector<std::string>({ "(local) audio" })); | |
813 audio_local_certinfo = CreateFakeCertificateAndInfoFromDers( | |
814 audio_local_certinfo->ders); | |
815 std::unique_ptr<CertificateInfo> audio_remote_certinfo = | |
816 CreateFakeCertificateAndInfoFromDers( | |
817 std::vector<std::string>({ "(remote) audio" })); | |
818 audio_remote_certinfo = CreateFakeCertificateAndInfoFromDers( | |
819 audio_remote_certinfo->ders); | |
820 | |
821 std::unique_ptr<CertificateInfo> video_local_certinfo = | |
822 CreateFakeCertificateAndInfoFromDers( | |
823 std::vector<std::string>({ "(local) video" })); | |
824 video_local_certinfo = CreateFakeCertificateAndInfoFromDers( | |
825 video_local_certinfo->ders); | |
826 std::unique_ptr<CertificateInfo> video_remote_certinfo = | |
827 CreateFakeCertificateAndInfoFromDers( | |
828 std::vector<std::string>({ "(remote) video" })); | |
829 video_remote_certinfo = CreateFakeCertificateAndInfoFromDers( | |
830 video_remote_certinfo->ders); | |
831 | |
832 // Mock the session to return the local and remote certificates. | |
833 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
834 [this](SessionStats* stats) { | |
835 stats->transport_stats["audio"].transport_name = "audio"; | |
836 stats->transport_stats["video"].transport_name = "video"; | |
837 return true; | |
838 })); | |
839 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( | |
840 Invoke([this, &audio_local_certinfo, &video_local_certinfo]( | |
841 const std::string& transport_name, | |
842 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
843 if (transport_name == "audio") { | |
844 *certificate = audio_local_certinfo->certificate; | |
845 return true; | |
846 } | |
847 if (transport_name == "video") { | |
848 *certificate = video_local_certinfo->certificate; | |
849 return true; | |
850 } | |
851 return false; | |
852 })); | |
853 EXPECT_CALL(test_->session(), | |
854 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( | |
855 [this, &audio_remote_certinfo, &video_remote_certinfo]( | |
856 const std::string& transport_name) { | |
857 if (transport_name == "audio") { | |
858 return audio_remote_certinfo->certificate->ssl_certificate() | |
859 .GetReference(); | |
860 } | |
861 if (transport_name == "video") { | |
862 return video_remote_certinfo->certificate->ssl_certificate() | |
863 .GetReference(); | |
864 } | |
865 return static_cast<rtc::SSLCertificate*>(nullptr); | |
866 })); | |
867 | |
868 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
869 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo.get()); | |
870 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo.get()); | |
871 ExpectReportContainsCertificateInfo(report, *video_local_certinfo.get()); | |
872 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo.get()); | |
873 } | |
874 | |
875 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) { | |
876 std::vector<std::string> local_ders; | |
877 local_ders.push_back("(local) this"); | |
878 local_ders.push_back("(local) is"); | |
879 local_ders.push_back("(local) a"); | |
880 local_ders.push_back("(local) chain"); | |
881 std::unique_ptr<CertificateInfo> local_certinfo = | |
882 CreateFakeCertificateAndInfoFromDers(local_ders); | |
883 std::vector<std::string> remote_ders; | |
884 remote_ders.push_back("(remote) this"); | |
885 remote_ders.push_back("(remote) is"); | |
886 remote_ders.push_back("(remote) another"); | |
887 remote_ders.push_back("(remote) chain"); | |
888 std::unique_ptr<CertificateInfo> remote_certinfo = | |
889 CreateFakeCertificateAndInfoFromDers(remote_ders); | |
890 | |
891 // Mock the session to return the local and remote certificates. | |
892 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
893 [this](SessionStats* stats) { | |
894 stats->transport_stats["transport"].transport_name = "transport"; | |
895 return true; | |
896 })); | |
897 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( | |
898 Invoke([this, &local_certinfo](const std::string& transport_name, | |
899 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
900 if (transport_name == "transport") { | |
901 *certificate = local_certinfo->certificate; | |
902 return true; | |
903 } | |
904 return false; | |
905 })); | |
906 EXPECT_CALL(test_->session(), | |
907 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( | |
908 [this, &remote_certinfo](const std::string& transport_name) { | |
909 if (transport_name == "transport") | |
910 return remote_certinfo->certificate->ssl_certificate().GetReference(); | |
911 return static_cast<rtc::SSLCertificate*>(nullptr); | |
912 })); | |
913 | |
914 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
915 ExpectReportContainsCertificateInfo(report, *local_certinfo.get()); | |
916 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get()); | |
917 } | |
918 | |
919 TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) { | |
920 test_->data_channels().push_back( | |
921 new MockDataChannel(0, DataChannelInterface::kConnecting)); | |
922 test_->data_channels().push_back( | |
923 new MockDataChannel(1, DataChannelInterface::kOpen)); | |
924 test_->data_channels().push_back( | |
925 new MockDataChannel(2, DataChannelInterface::kClosing)); | |
926 test_->data_channels().push_back( | |
927 new MockDataChannel(3, DataChannelInterface::kClosed)); | |
928 | |
929 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
930 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]); | |
931 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]); | |
932 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]); | |
933 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]); | |
934 | |
935 test_->data_channels().clear(); | |
936 test_->data_channels().push_back( | |
937 new MockDataChannel(0, DataChannelInterface::kConnecting, | |
938 1, 2, 3, 4)); | |
939 test_->data_channels().push_back( | |
940 new MockDataChannel(1, DataChannelInterface::kOpen, | |
941 5, 6, 7, 8)); | |
942 test_->data_channels().push_back( | |
943 new MockDataChannel(2, DataChannelInterface::kClosing, | |
944 9, 10, 11, 12)); | |
945 test_->data_channels().push_back( | |
946 new MockDataChannel(3, DataChannelInterface::kClosed, | |
947 13, 14, 15, 16)); | |
948 | |
949 collector_->ClearCachedStatsReport(); | |
950 report = GetStatsReport(); | |
951 ExpectReportContainsDataChannel(report, *test_->data_channels()[0]); | |
952 ExpectReportContainsDataChannel(report, *test_->data_channels()[1]); | |
953 ExpectReportContainsDataChannel(report, *test_->data_channels()[2]); | |
954 ExpectReportContainsDataChannel(report, *test_->data_channels()[3]); | |
955 } | |
956 | |
957 TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { | |
958 // Candidates in the first transport stats. | |
959 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate( | |
960 "1.2.3.4", 5, | |
961 "a_local_host's protocol", | |
962 cricket::LOCAL_PORT_TYPE, | |
963 0); | |
964 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate( | |
965 "6.7.8.9", 10, | |
966 "remote_srflx's protocol", | |
967 cricket::STUN_PORT_TYPE, | |
968 1); | |
969 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate( | |
970 "11.12.13.14", 15, | |
971 "a_local_prflx's protocol", | |
972 cricket::PRFLX_PORT_TYPE, | |
973 2); | |
974 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate( | |
975 "16.17.18.19", 20, | |
976 "a_remote_relay's protocol", | |
977 cricket::RELAY_PORT_TYPE, | |
978 3); | |
979 // Candidates in the second transport stats. | |
980 std::unique_ptr<cricket::Candidate> b_local = CreateFakeCandidate( | |
981 "42.42.42.42", 42, | |
982 "b_local's protocol", | |
983 cricket::LOCAL_PORT_TYPE, | |
984 42); | |
985 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate( | |
986 "42.42.42.42", 42, | |
987 "b_remote's protocol", | |
988 cricket::LOCAL_PORT_TYPE, | |
989 42); | |
990 | |
991 SessionStats session_stats; | |
992 | |
993 cricket::TransportChannelStats a_transport_channel_stats; | |
994 a_transport_channel_stats.connection_infos.push_back( | |
995 cricket::ConnectionInfo()); | |
996 a_transport_channel_stats.connection_infos[0].local_candidate = | |
997 *a_local_host.get(); | |
998 a_transport_channel_stats.connection_infos[0].remote_candidate = | |
999 *a_remote_srflx.get(); | |
1000 a_transport_channel_stats.connection_infos.push_back( | |
1001 cricket::ConnectionInfo()); | |
1002 a_transport_channel_stats.connection_infos[1].local_candidate = | |
1003 *a_local_prflx.get(); | |
1004 a_transport_channel_stats.connection_infos[1].remote_candidate = | |
1005 *a_remote_relay.get(); | |
1006 session_stats.transport_stats["a"].channel_stats.push_back( | |
1007 a_transport_channel_stats); | |
1008 | |
1009 cricket::TransportChannelStats b_transport_channel_stats; | |
1010 b_transport_channel_stats.connection_infos.push_back( | |
1011 cricket::ConnectionInfo()); | |
1012 b_transport_channel_stats.connection_infos[0].local_candidate = | |
1013 *b_local.get(); | |
1014 b_transport_channel_stats.connection_infos[0].remote_candidate = | |
1015 *b_remote.get(); | |
1016 session_stats.transport_stats["b"].channel_stats.push_back( | |
1017 b_transport_channel_stats); | |
1018 | |
1019 // Mock the session to return the desired candidates. | |
1020 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
1021 [this, &session_stats](SessionStats* stats) { | |
1022 *stats = session_stats; | |
1023 return true; | |
1024 })); | |
1025 | |
1026 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1027 ExpectReportContainsCandidate(report, *a_local_host.get(), true); | |
1028 ExpectReportContainsCandidate(report, *a_remote_srflx.get(), false); | |
1029 ExpectReportContainsCandidate(report, *a_local_prflx.get(), true); | |
1030 ExpectReportContainsCandidate(report, *a_remote_relay.get(), false); | |
1031 ExpectReportContainsCandidate(report, *b_local.get(), true); | |
1032 ExpectReportContainsCandidate(report, *b_remote.get(), false); | |
1033 } | |
1034 | |
1035 TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) { | |
1036 std::unique_ptr<cricket::Candidate> local_candidate = CreateFakeCandidate( | |
1037 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42); | |
1038 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate( | |
1039 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42); | |
1040 | |
1041 SessionStats session_stats; | |
1042 | |
1043 cricket::ConnectionInfo connection_info; | |
1044 connection_info.local_candidate = *local_candidate.get(); | |
1045 connection_info.remote_candidate = *remote_candidate.get(); | |
1046 connection_info.writable = true; | |
1047 connection_info.sent_total_bytes = 42; | |
1048 connection_info.recv_total_bytes = 1234; | |
1049 connection_info.rtt = 1337; | |
1050 connection_info.sent_ping_requests_total = 1010; | |
1051 connection_info.recv_ping_responses = 4321; | |
1052 connection_info.sent_ping_responses = 1000; | |
1053 | |
1054 cricket::TransportChannelStats transport_channel_stats; | |
1055 transport_channel_stats.connection_infos.push_back(connection_info); | |
1056 session_stats.transport_stats["transport"].transport_name = "transport"; | |
1057 session_stats.transport_stats["transport"].channel_stats.push_back( | |
1058 transport_channel_stats); | |
1059 | |
1060 // Mock the session to return the desired candidates. | |
1061 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
1062 [this, &session_stats](SessionStats* stats) { | |
1063 *stats = session_stats; | |
1064 return true; | |
1065 })); | |
1066 | |
1067 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1068 ExpectReportContainsCandidatePair( | |
1069 report, session_stats.transport_stats["transport"]); | |
1070 } | |
1071 | |
1072 TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) { | |
1073 { | |
1074 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1075 RTCPeerConnectionStats expected("RTCPeerConnection", | |
1076 report->timestamp_us()); | |
1077 expected.data_channels_opened = 0; | |
1078 expected.data_channels_closed = 0; | |
1079 EXPECT_TRUE(report->Get("RTCPeerConnection")); | |
1080 EXPECT_EQ(expected, | |
1081 report->Get("RTCPeerConnection")->cast_to< | |
1082 RTCPeerConnectionStats>()); | |
1083 } | |
1084 | |
1085 rtc::scoped_refptr<DataChannel> dummy_channel_a = DataChannel::Create( | |
1086 nullptr, cricket::DCT_NONE, "DummyChannelA", InternalDataChannelInit()); | |
1087 test_->pc().SignalDataChannelCreated(dummy_channel_a.get()); | |
1088 rtc::scoped_refptr<DataChannel> dummy_channel_b = DataChannel::Create( | |
1089 nullptr, cricket::DCT_NONE, "DummyChannelB", InternalDataChannelInit()); | |
1090 test_->pc().SignalDataChannelCreated(dummy_channel_b.get()); | |
1091 | |
1092 dummy_channel_a->SignalOpened(dummy_channel_a.get()); | |
1093 // Closing a channel that is not opened should not affect the counts. | |
1094 dummy_channel_b->SignalClosed(dummy_channel_b.get()); | |
1095 | |
1096 { | |
1097 collector_->ClearCachedStatsReport(); | |
1098 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1099 RTCPeerConnectionStats expected("RTCPeerConnection", | |
1100 report->timestamp_us()); | |
1101 expected.data_channels_opened = 1; | |
1102 expected.data_channels_closed = 0; | |
1103 EXPECT_TRUE(report->Get("RTCPeerConnection")); | |
1104 EXPECT_EQ(expected, | |
1105 report->Get("RTCPeerConnection")->cast_to< | |
1106 RTCPeerConnectionStats>()); | |
1107 } | |
1108 | |
1109 dummy_channel_b->SignalOpened(dummy_channel_b.get()); | |
1110 dummy_channel_b->SignalClosed(dummy_channel_b.get()); | |
1111 | |
1112 { | |
1113 collector_->ClearCachedStatsReport(); | |
1114 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1115 RTCPeerConnectionStats expected("RTCPeerConnection", | |
1116 report->timestamp_us()); | |
1117 expected.data_channels_opened = 2; | |
1118 expected.data_channels_closed = 1; | |
1119 EXPECT_TRUE(report->Get("RTCPeerConnection")); | |
1120 EXPECT_EQ(expected, | |
1121 report->Get("RTCPeerConnection")->cast_to< | |
1122 RTCPeerConnectionStats>()); | |
1123 } | |
1124 } | |
1125 | |
1126 TEST_F(RTCStatsCollectorTest, | |
1127 CollectRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) { | |
1128 rtc::scoped_refptr<StreamCollection> local_streams = | |
1129 StreamCollection::Create(); | |
1130 rtc::scoped_refptr<StreamCollection> remote_streams = | |
1131 StreamCollection::Create(); | |
1132 EXPECT_CALL(test_->pc(), local_streams()) | |
1133 .WillRepeatedly(Return(local_streams)); | |
1134 EXPECT_CALL(test_->pc(), remote_streams()) | |
1135 .WillRepeatedly(Return(remote_streams)); | |
1136 | |
1137 rtc::scoped_refptr<MediaStream> local_stream = | |
1138 MediaStream::Create("LocalStreamLabel"); | |
1139 local_streams->AddStream(local_stream); | |
1140 rtc::scoped_refptr<MediaStream> remote_stream = | |
1141 MediaStream::Create("RemoteStreamLabel"); | |
1142 remote_streams->AddStream(remote_stream); | |
1143 | |
1144 // Local audio track | |
1145 AudioProcessorInterface::AudioProcessorStats local_audio_processor_stats; | |
1146 local_audio_processor_stats.echo_return_loss = 42; | |
1147 local_audio_processor_stats.echo_return_loss_enhancement = 52; | |
1148 rtc::scoped_refptr<FakeAudioTrackForStats> local_audio_track = | |
1149 FakeAudioTrackForStats::Create( | |
1150 "LocalAudioTrackID", | |
1151 MediaStreamTrackInterface::TrackState::kEnded, | |
1152 32767, | |
1153 new FakeAudioProcessorForStats(local_audio_processor_stats)); | |
1154 local_stream->AddTrack(local_audio_track); | |
1155 | |
1156 // Remote audio track | |
1157 AudioProcessorInterface::AudioProcessorStats remote_audio_processor_stats; | |
1158 remote_audio_processor_stats.echo_return_loss = 13; | |
1159 remote_audio_processor_stats.echo_return_loss_enhancement = 37; | |
1160 rtc::scoped_refptr<FakeAudioTrackForStats> remote_audio_track = | |
1161 FakeAudioTrackForStats::Create( | |
1162 "RemoteAudioTrackID", | |
1163 MediaStreamTrackInterface::TrackState::kLive, | |
1164 0, | |
1165 new FakeAudioProcessorForStats(remote_audio_processor_stats)); | |
1166 remote_stream->AddTrack(remote_audio_track); | |
1167 | |
1168 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1169 | |
1170 RTCMediaStreamStats expected_local_stream( | |
1171 "RTCMediaStream_LocalStreamLabel", report->timestamp_us()); | |
1172 expected_local_stream.stream_identifier = local_stream->label(); | |
1173 expected_local_stream.track_ids = std::vector<std::string>(); | |
1174 expected_local_stream.track_ids->push_back( | |
1175 "RTCMediaStreamTrack_LocalAudioTrackID"); | |
1176 EXPECT_TRUE(report->Get(expected_local_stream.id())); | |
1177 EXPECT_EQ(expected_local_stream, | |
1178 report->Get(expected_local_stream.id())->cast_to< | |
1179 RTCMediaStreamStats>()); | |
1180 | |
1181 RTCMediaStreamStats expected_remote_stream( | |
1182 "RTCMediaStream_RemoteStreamLabel", report->timestamp_us()); | |
1183 expected_remote_stream.stream_identifier = remote_stream->label(); | |
1184 expected_remote_stream.track_ids = std::vector<std::string>(); | |
1185 expected_remote_stream.track_ids->push_back( | |
1186 "RTCMediaStreamTrack_RemoteAudioTrackID"); | |
1187 EXPECT_TRUE(report->Get(expected_remote_stream.id())); | |
1188 EXPECT_EQ(expected_remote_stream, | |
1189 report->Get(expected_remote_stream.id())->cast_to< | |
1190 RTCMediaStreamStats>()); | |
1191 | |
1192 RTCMediaStreamTrackStats expected_local_audio_track( | |
1193 "RTCMediaStreamTrack_LocalAudioTrackID", report->timestamp_us()); | |
1194 expected_local_audio_track.track_identifier = local_audio_track->id(); | |
1195 expected_local_audio_track.remote_source = false; | |
1196 expected_local_audio_track.ended = true; | |
1197 expected_local_audio_track.detached = false; | |
1198 expected_local_audio_track.audio_level = 1.0; | |
1199 expected_local_audio_track.echo_return_loss = 42.0; | |
1200 expected_local_audio_track.echo_return_loss_enhancement = 52.0; | |
1201 EXPECT_TRUE(report->Get(expected_local_audio_track.id())); | |
1202 EXPECT_EQ(expected_local_audio_track, | |
1203 report->Get(expected_local_audio_track.id())->cast_to< | |
1204 RTCMediaStreamTrackStats>()); | |
1205 | |
1206 RTCMediaStreamTrackStats expected_remote_audio_track( | |
1207 "RTCMediaStreamTrack_RemoteAudioTrackID", report->timestamp_us()); | |
1208 expected_remote_audio_track.track_identifier = remote_audio_track->id(); | |
1209 expected_remote_audio_track.remote_source = true; | |
1210 expected_remote_audio_track.ended = false; | |
1211 expected_remote_audio_track.detached = false; | |
1212 expected_remote_audio_track.audio_level = 0.0; | |
1213 expected_remote_audio_track.echo_return_loss = 13.0; | |
1214 expected_remote_audio_track.echo_return_loss_enhancement = 37.0; | |
1215 EXPECT_TRUE(report->Get(expected_remote_audio_track.id())); | |
1216 EXPECT_EQ(expected_remote_audio_track, | |
1217 report->Get(expected_remote_audio_track.id())->cast_to< | |
1218 RTCMediaStreamTrackStats>()); | |
1219 } | |
1220 | |
1221 TEST_F(RTCStatsCollectorTest, | |
1222 CollectRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) { | |
1223 rtc::scoped_refptr<StreamCollection> local_streams = | |
1224 StreamCollection::Create(); | |
1225 rtc::scoped_refptr<StreamCollection> remote_streams = | |
1226 StreamCollection::Create(); | |
1227 EXPECT_CALL(test_->pc(), local_streams()) | |
1228 .WillRepeatedly(Return(local_streams)); | |
1229 EXPECT_CALL(test_->pc(), remote_streams()) | |
1230 .WillRepeatedly(Return(remote_streams)); | |
1231 | |
1232 rtc::scoped_refptr<MediaStream> local_stream = | |
1233 MediaStream::Create("LocalStreamLabel"); | |
1234 local_streams->AddStream(local_stream); | |
1235 rtc::scoped_refptr<MediaStream> remote_stream = | |
1236 MediaStream::Create("RemoteStreamLabel"); | |
1237 remote_streams->AddStream(remote_stream); | |
1238 | |
1239 // Local video track | |
1240 VideoTrackSourceInterface::Stats local_video_track_source_stats; | |
1241 local_video_track_source_stats.input_width = 1234; | |
1242 local_video_track_source_stats.input_height = 4321; | |
1243 rtc::scoped_refptr<FakeVideoTrackSourceForStats> local_video_track_source = | |
1244 new FakeVideoTrackSourceForStats(local_video_track_source_stats); | |
1245 rtc::scoped_refptr<FakeVideoTrackForStats> local_video_track = | |
1246 FakeVideoTrackForStats::Create( | |
1247 "LocalVideoTrackID", | |
1248 MediaStreamTrackInterface::TrackState::kLive, | |
1249 local_video_track_source); | |
1250 local_stream->AddTrack(local_video_track); | |
1251 | |
1252 // Remote video track | |
1253 VideoTrackSourceInterface::Stats remote_video_track_source_stats; | |
1254 remote_video_track_source_stats.input_width = 1234; | |
1255 remote_video_track_source_stats.input_height = 4321; | |
1256 rtc::scoped_refptr<FakeVideoTrackSourceForStats> remote_video_track_source = | |
1257 new FakeVideoTrackSourceForStats(remote_video_track_source_stats); | |
1258 rtc::scoped_refptr<FakeVideoTrackForStats> remote_video_track = | |
1259 FakeVideoTrackForStats::Create( | |
1260 "RemoteVideoTrackID", | |
1261 MediaStreamTrackInterface::TrackState::kEnded, | |
1262 remote_video_track_source); | |
1263 remote_stream->AddTrack(remote_video_track); | |
1264 | |
1265 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1266 | |
1267 RTCMediaStreamStats expected_local_stream( | |
1268 "RTCMediaStream_LocalStreamLabel", report->timestamp_us()); | |
1269 expected_local_stream.stream_identifier = local_stream->label(); | |
1270 expected_local_stream.track_ids = std::vector<std::string>(); | |
1271 expected_local_stream.track_ids->push_back( | |
1272 "RTCMediaStreamTrack_LocalVideoTrackID"); | |
1273 EXPECT_TRUE(report->Get(expected_local_stream.id())); | |
1274 EXPECT_EQ(expected_local_stream, | |
1275 report->Get(expected_local_stream.id())->cast_to< | |
1276 RTCMediaStreamStats>()); | |
1277 | |
1278 RTCMediaStreamStats expected_remote_stream( | |
1279 "RTCMediaStream_RemoteStreamLabel", report->timestamp_us()); | |
1280 expected_remote_stream.stream_identifier = remote_stream->label(); | |
1281 expected_remote_stream.track_ids = std::vector<std::string>(); | |
1282 expected_remote_stream.track_ids->push_back( | |
1283 "RTCMediaStreamTrack_RemoteVideoTrackID"); | |
1284 EXPECT_TRUE(report->Get(expected_remote_stream.id())); | |
1285 EXPECT_EQ(expected_remote_stream, | |
1286 report->Get(expected_remote_stream.id())->cast_to< | |
1287 RTCMediaStreamStats>()); | |
1288 | |
1289 RTCMediaStreamTrackStats expected_local_video_track( | |
1290 "RTCMediaStreamTrack_LocalVideoTrackID", report->timestamp_us()); | |
1291 expected_local_video_track.track_identifier = local_video_track->id(); | |
1292 expected_local_video_track.remote_source = false; | |
1293 expected_local_video_track.ended = false; | |
1294 expected_local_video_track.detached = false; | |
1295 expected_local_video_track.frame_width = 1234; | |
1296 expected_local_video_track.frame_height = 4321; | |
1297 EXPECT_TRUE(report->Get(expected_local_video_track.id())); | |
1298 EXPECT_EQ(expected_local_video_track, | |
1299 report->Get(expected_local_video_track.id())->cast_to< | |
1300 RTCMediaStreamTrackStats>()); | |
1301 | |
1302 RTCMediaStreamTrackStats expected_remote_video_track( | |
1303 "RTCMediaStreamTrack_RemoteVideoTrackID", report->timestamp_us()); | |
1304 expected_remote_video_track.track_identifier = remote_video_track->id(); | |
1305 expected_remote_video_track.remote_source = true; | |
1306 expected_remote_video_track.ended = true; | |
1307 expected_remote_video_track.detached = false; | |
1308 expected_remote_video_track.frame_width = 1234; | |
1309 expected_remote_video_track.frame_height = 4321; | |
1310 EXPECT_TRUE(report->Get(expected_remote_video_track.id())); | |
1311 EXPECT_EQ(expected_remote_video_track, | |
1312 report->Get(expected_remote_video_track.id())->cast_to< | |
1313 RTCMediaStreamTrackStats>()); | |
1314 } | |
1315 | |
1316 TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) { | |
1317 MockVoiceMediaChannel* voice_media_channel = new MockVoiceMediaChannel(); | |
1318 cricket::VoiceChannel voice_channel( | |
1319 test_->worker_thread(), test_->network_thread(), test_->media_engine(), | |
1320 voice_media_channel, nullptr, "VoiceContentName", false); | |
1321 | |
1322 cricket::VoiceMediaInfo voice_media_info; | |
1323 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo()); | |
1324 voice_media_info.receivers[0].local_stats.push_back( | |
1325 cricket::SsrcReceiverInfo()); | |
1326 voice_media_info.receivers[0].local_stats[0].ssrc = 1; | |
1327 voice_media_info.receivers[0].packets_rcvd = 2; | |
1328 voice_media_info.receivers[0].bytes_rcvd = 3; | |
1329 voice_media_info.receivers[0].jitter_ms = 4500; | |
1330 voice_media_info.receivers[0].fraction_lost = 5.5f; | |
1331 EXPECT_CALL(*voice_media_channel, GetStats(_)) | |
1332 .WillOnce(DoAll(SetArgPointee<0>(voice_media_info), Return(true))); | |
1333 | |
1334 SessionStats session_stats; | |
1335 session_stats.proxy_to_transport["VoiceContentName"] = "TransportName"; | |
1336 session_stats.transport_stats["TransportName"].transport_name = | |
1337 "TransportName"; | |
1338 | |
1339 // Make sure the associated |RTCTransportStats| is created. | |
1340 cricket::TransportChannelStats channel_stats; | |
1341 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; | |
1342 session_stats.transport_stats["TransportName"].channel_stats.push_back( | |
1343 channel_stats); | |
1344 | |
1345 EXPECT_CALL(test_->session(), GetTransportStats(_)) | |
1346 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true))); | |
1347 EXPECT_CALL(test_->session(), voice_channel()) | |
1348 .WillRepeatedly(Return(&voice_channel)); | |
1349 | |
1350 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1351 | |
1352 RTCInboundRTPStreamStats expected_audio( | |
1353 "RTCInboundRTPAudioStream_1", report->timestamp_us()); | |
1354 expected_audio.ssrc = "1"; | |
1355 expected_audio.is_remote = false; | |
1356 expected_audio.media_type = "audio"; | |
1357 expected_audio.transport_id = "RTCTransport_TransportName_" + | |
1358 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP); | |
1359 expected_audio.packets_received = 2; | |
1360 expected_audio.bytes_received = 3; | |
1361 expected_audio.jitter = 4.5; | |
1362 expected_audio.fraction_lost = 5.5; | |
1363 | |
1364 ASSERT(report->Get(expected_audio.id())); | |
1365 const RTCInboundRTPStreamStats& audio = report->Get( | |
1366 expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(); | |
1367 EXPECT_EQ(audio, expected_audio); | |
1368 | |
1369 EXPECT_TRUE(report->Get(*expected_audio.transport_id)); | |
1370 } | |
1371 | |
1372 TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) { | |
1373 MockVideoMediaChannel* video_media_channel = new MockVideoMediaChannel(); | |
1374 cricket::VideoChannel video_channel( | |
1375 test_->worker_thread(), test_->network_thread(), video_media_channel, | |
1376 nullptr, "VideoContentName", false); | |
1377 | |
1378 cricket::VideoMediaInfo video_media_info; | |
1379 video_media_info.receivers.push_back(cricket::VideoReceiverInfo()); | |
1380 video_media_info.receivers[0].local_stats.push_back( | |
1381 cricket::SsrcReceiverInfo()); | |
1382 video_media_info.receivers[0].local_stats[0].ssrc = 1; | |
1383 video_media_info.receivers[0].packets_rcvd = 2; | |
1384 video_media_info.receivers[0].bytes_rcvd = 3; | |
1385 video_media_info.receivers[0].fraction_lost = 4.5f; | |
1386 EXPECT_CALL(*video_media_channel, GetStats(_)) | |
1387 .WillOnce(DoAll(SetArgPointee<0>(video_media_info), Return(true))); | |
1388 | |
1389 SessionStats session_stats; | |
1390 session_stats.proxy_to_transport["VideoContentName"] = "TransportName"; | |
1391 session_stats.transport_stats["TransportName"].transport_name = | |
1392 "TransportName"; | |
1393 | |
1394 // Make sure the associated |RTCTransportStats| is created. | |
1395 cricket::TransportChannelStats channel_stats; | |
1396 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; | |
1397 session_stats.transport_stats["TransportName"].channel_stats.push_back( | |
1398 channel_stats); | |
1399 | |
1400 EXPECT_CALL(test_->session(), GetTransportStats(_)) | |
1401 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true))); | |
1402 EXPECT_CALL(test_->session(), video_channel()) | |
1403 .WillRepeatedly(Return(&video_channel)); | |
1404 | |
1405 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1406 | |
1407 RTCInboundRTPStreamStats expected_audio( | |
1408 "RTCInboundRTPVideoStream_1", report->timestamp_us()); | |
1409 expected_audio.ssrc = "1"; | |
1410 expected_audio.is_remote = false; | |
1411 expected_audio.media_type = "video"; | |
1412 expected_audio.transport_id = "RTCTransport_TransportName_" + | |
1413 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP); | |
1414 expected_audio.packets_received = 2; | |
1415 expected_audio.bytes_received = 3; | |
1416 expected_audio.fraction_lost = 4.5; | |
1417 | |
1418 ASSERT(report->Get(expected_audio.id())); | |
1419 const RTCInboundRTPStreamStats& audio = report->Get( | |
1420 expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(); | |
1421 EXPECT_EQ(audio, expected_audio); | |
1422 | |
1423 EXPECT_TRUE(report->Get(*expected_audio.transport_id)); | |
1424 } | |
1425 | |
1426 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) { | |
1427 MockVoiceMediaChannel* voice_media_channel = new MockVoiceMediaChannel(); | |
1428 cricket::VoiceChannel voice_channel( | |
1429 test_->worker_thread(), test_->network_thread(), test_->media_engine(), | |
1430 voice_media_channel, nullptr, "VoiceContentName", false); | |
1431 | |
1432 cricket::VoiceMediaInfo voice_media_info; | |
1433 voice_media_info.senders.push_back(cricket::VoiceSenderInfo()); | |
1434 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo()); | |
1435 voice_media_info.senders[0].local_stats[0].ssrc = 1; | |
1436 voice_media_info.senders[0].packets_sent = 2; | |
1437 voice_media_info.senders[0].bytes_sent = 3; | |
1438 voice_media_info.senders[0].rtt_ms = 4500; | |
1439 EXPECT_CALL(*voice_media_channel, GetStats(_)) | |
1440 .WillOnce(DoAll(SetArgPointee<0>(voice_media_info), Return(true))); | |
1441 | |
1442 SessionStats session_stats; | |
1443 session_stats.proxy_to_transport["VoiceContentName"] = "TransportName"; | |
1444 session_stats.transport_stats["TransportName"].transport_name = | |
1445 "TransportName"; | |
1446 | |
1447 // Make sure the associated |RTCTransportStats| is created. | |
1448 cricket::TransportChannelStats channel_stats; | |
1449 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; | |
1450 session_stats.transport_stats["TransportName"].channel_stats.push_back( | |
1451 channel_stats); | |
1452 | |
1453 EXPECT_CALL(test_->session(), GetTransportStats(_)) | |
1454 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true))); | |
1455 EXPECT_CALL(test_->session(), voice_channel()) | |
1456 .WillRepeatedly(Return(&voice_channel)); | |
1457 | |
1458 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1459 | |
1460 RTCOutboundRTPStreamStats expected_audio( | |
1461 "RTCOutboundRTPAudioStream_1", report->timestamp_us()); | |
1462 expected_audio.ssrc = "1"; | |
1463 expected_audio.is_remote = false; | |
1464 expected_audio.media_type = "audio"; | |
1465 expected_audio.transport_id = "RTCTransport_TransportName_" + | |
1466 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP); | |
1467 expected_audio.packets_sent = 2; | |
1468 expected_audio.bytes_sent = 3; | |
1469 expected_audio.round_trip_time = 4.5; | |
1470 | |
1471 ASSERT(report->Get(expected_audio.id())); | |
1472 const RTCOutboundRTPStreamStats& audio = report->Get( | |
1473 expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(); | |
1474 EXPECT_EQ(audio, expected_audio); | |
1475 | |
1476 EXPECT_TRUE(report->Get(*expected_audio.transport_id)); | |
1477 } | |
1478 | |
1479 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) { | |
1480 MockVideoMediaChannel* video_media_channel = new MockVideoMediaChannel(); | |
1481 cricket::VideoChannel video_channel( | |
1482 test_->worker_thread(), test_->network_thread(), video_media_channel, | |
1483 nullptr, "VideoContentName", false); | |
1484 | |
1485 cricket::VideoMediaInfo video_media_info; | |
1486 video_media_info.senders.push_back(cricket::VideoSenderInfo()); | |
1487 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo()); | |
1488 video_media_info.senders[0].local_stats[0].ssrc = 1; | |
1489 video_media_info.senders[0].firs_rcvd = 2; | |
1490 video_media_info.senders[0].plis_rcvd = 3; | |
1491 video_media_info.senders[0].nacks_rcvd = 4; | |
1492 video_media_info.senders[0].packets_sent = 5; | |
1493 video_media_info.senders[0].bytes_sent = 6; | |
1494 video_media_info.senders[0].rtt_ms = 7500; | |
1495 EXPECT_CALL(*video_media_channel, GetStats(_)) | |
1496 .WillOnce(DoAll(SetArgPointee<0>(video_media_info), Return(true))); | |
1497 | |
1498 SessionStats session_stats; | |
1499 session_stats.proxy_to_transport["VideoContentName"] = "TransportName"; | |
1500 session_stats.transport_stats["TransportName"].transport_name = | |
1501 "TransportName"; | |
1502 | |
1503 // Make sure the associated |RTCTransportStats| is created. | |
1504 cricket::TransportChannelStats channel_stats; | |
1505 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; | |
1506 session_stats.transport_stats["TransportName"].channel_stats.push_back( | |
1507 channel_stats); | |
1508 | |
1509 EXPECT_CALL(test_->session(), GetTransportStats(_)) | |
1510 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats), Return(true))); | |
1511 EXPECT_CALL(test_->session(), video_channel()) | |
1512 .WillRepeatedly(Return(&video_channel)); | |
1513 | |
1514 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1515 | |
1516 RTCOutboundRTPStreamStats expected_video( | |
1517 "RTCOutboundRTPVideoStream_1", report->timestamp_us()); | |
1518 expected_video.ssrc = "1"; | |
1519 expected_video.is_remote = false; | |
1520 expected_video.media_type = "video"; | |
1521 expected_video.transport_id = "RTCTransport_TransportName_" + | |
1522 rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP); | |
1523 expected_video.fir_count = 2; | |
1524 expected_video.pli_count = 3; | |
1525 expected_video.nack_count = 4; | |
1526 expected_video.packets_sent = 5; | |
1527 expected_video.bytes_sent = 6; | |
1528 expected_video.round_trip_time = 7.5; | |
1529 | |
1530 ASSERT(report->Get(expected_video.id())); | |
1531 const RTCOutboundRTPStreamStats& video = report->Get( | |
1532 expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(); | |
1533 EXPECT_EQ(video, expected_video); | |
1534 | |
1535 EXPECT_TRUE(report->Get(*expected_video.transport_id)); | |
1536 } | |
1537 | |
1538 TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) { | |
1539 std::unique_ptr<cricket::Candidate> rtp_local_candidate = CreateFakeCandidate( | |
1540 "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42); | |
1541 std::unique_ptr<cricket::Candidate> rtp_remote_candidate = | |
1542 CreateFakeCandidate("42.42.42.42", 42, "protocol", | |
1543 cricket::LOCAL_PORT_TYPE, 42); | |
1544 std::unique_ptr<cricket::Candidate> rtcp_local_candidate = | |
1545 CreateFakeCandidate("42.42.42.42", 42, "protocol", | |
1546 cricket::LOCAL_PORT_TYPE, 42); | |
1547 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate = | |
1548 CreateFakeCandidate("42.42.42.42", 42, "protocol", | |
1549 cricket::LOCAL_PORT_TYPE, 42); | |
1550 | |
1551 SessionStats session_stats; | |
1552 session_stats.transport_stats["transport"].transport_name = "transport"; | |
1553 | |
1554 cricket::ConnectionInfo rtp_connection_info; | |
1555 rtp_connection_info.best_connection = false; | |
1556 rtp_connection_info.local_candidate = *rtp_local_candidate.get(); | |
1557 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get(); | |
1558 rtp_connection_info.sent_total_bytes = 42; | |
1559 rtp_connection_info.recv_total_bytes = 1337; | |
1560 cricket::TransportChannelStats rtp_transport_channel_stats; | |
1561 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; | |
1562 rtp_transport_channel_stats.connection_infos.push_back(rtp_connection_info); | |
1563 session_stats.transport_stats["transport"].channel_stats.push_back( | |
1564 rtp_transport_channel_stats); | |
1565 | |
1566 | |
1567 // Mock the session to return the desired candidates. | |
1568 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( | |
1569 [this, &session_stats](SessionStats* stats) { | |
1570 *stats = session_stats; | |
1571 return true; | |
1572 })); | |
1573 | |
1574 // Get stats without RTCP, an active connection or certificates. | |
1575 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | |
1576 ExpectReportContainsTransportStats( | |
1577 report, session_stats.transport_stats["transport"], nullptr, nullptr); | |
1578 | |
1579 cricket::ConnectionInfo rtcp_connection_info; | |
1580 rtcp_connection_info.best_connection = false; | |
1581 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get(); | |
1582 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get(); | |
1583 rtcp_connection_info.sent_total_bytes = 1337; | |
1584 rtcp_connection_info.recv_total_bytes = 42; | |
1585 cricket::TransportChannelStats rtcp_transport_channel_stats; | |
1586 rtcp_transport_channel_stats.component = | |
1587 cricket::ICE_CANDIDATE_COMPONENT_RTCP; | |
1588 rtcp_transport_channel_stats.connection_infos.push_back(rtcp_connection_info); | |
1589 session_stats.transport_stats["transport"].channel_stats.push_back( | |
1590 rtcp_transport_channel_stats); | |
1591 | |
1592 collector_->ClearCachedStatsReport(); | |
1593 // Get stats with RTCP and without an active connection or certificates. | |
1594 report = GetStatsReport(); | |
1595 ExpectReportContainsTransportStats( | |
1596 report, session_stats.transport_stats["transport"], nullptr, nullptr); | |
1597 | |
1598 // Get stats with an active connection. | |
1599 rtcp_connection_info.best_connection = true; | |
1600 | |
1601 collector_->ClearCachedStatsReport(); | |
1602 report = GetStatsReport(); | |
1603 ExpectReportContainsTransportStats( | |
1604 report, session_stats.transport_stats["transport"], nullptr, nullptr); | |
1605 | |
1606 // Get stats with certificates. | |
1607 std::unique_ptr<CertificateInfo> local_certinfo = | |
1608 CreateFakeCertificateAndInfoFromDers( | |
1609 std::vector<std::string>({ "(local) local", "(local) chain" })); | |
1610 std::unique_ptr<CertificateInfo> remote_certinfo = | |
1611 CreateFakeCertificateAndInfoFromDers( | |
1612 std::vector<std::string>({ "(remote) local", "(remote) chain" })); | |
1613 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( | |
1614 Invoke([this, &local_certinfo](const std::string& transport_name, | |
1615 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
1616 if (transport_name == "transport") { | |
1617 *certificate = local_certinfo->certificate; | |
1618 return true; | |
1619 } | |
1620 return false; | |
1621 })); | |
1622 EXPECT_CALL(test_->session(), | |
1623 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( | |
1624 [this, &remote_certinfo](const std::string& transport_name) { | |
1625 if (transport_name == "transport") | |
1626 return remote_certinfo->certificate->ssl_certificate().GetReference(); | |
1627 return static_cast<rtc::SSLCertificate*>(nullptr); | |
1628 })); | |
1629 | |
1630 collector_->ClearCachedStatsReport(); | |
1631 report = GetStatsReport(); | |
1632 ExpectReportContainsTransportStats( | |
1633 report, session_stats.transport_stats["transport"], | |
1634 local_certinfo.get(), remote_certinfo.get()); | |
1635 } | |
1636 | |
1637 class RTCStatsCollectorTestWithFakeCollector : public testing::Test { | |
1638 public: | |
1639 RTCStatsCollectorTestWithFakeCollector() | |
1640 : test_(new rtc::RefCountedObject<RTCStatsCollectorTestHelper>()), | |
1641 collector_(FakeRTCStatsCollector::Create( | |
1642 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) { | |
1643 } | |
1644 | |
1645 protected: | |
1646 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_; | |
1647 rtc::scoped_refptr<FakeRTCStatsCollector> collector_; | |
1648 }; | |
1649 | |
1650 TEST_F(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) { | |
1651 collector_->VerifyThreadUsageAndResultsMerging(); | |
1652 } | |
1653 | |
1654 } // namespace | |
1655 | |
1656 } // namespace webrtc | |
OLD | NEW |