4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "talk/app/webrtc/statscollector.h"
31 #include "talk/app/webrtc/mediastream.h"
32 #include "talk/app/webrtc/videotrack.h"
33 #include "talk/base/base64.h"
34 #include "talk/base/fakesslidentity.h"
35 #include "talk/base/gunit.h"
36 #include "talk/media/base/fakemediaengine.h"
37 #include "talk/media/devices/fakedevicemanager.h"
38 #include "talk/p2p/base/fakesession.h"
39 #include "talk/session/media/channelmanager.h"
40 #include "testing/base/public/gmock.h"
42 using cricket::StatsOptions;
46 using testing::Return;
47 using testing::ReturnNull;
48 using testing::SetArgPointee;
49 using webrtc::PeerConnectionInterface;
54 class FakeDeviceManager;
56 } // namespace cricket
60 // Error return values
61 const char kNotFound[] = "NOT FOUND";
62 const char kNoReports[] = "NO REPORTS";
64 // Constant names for track identification.
65 const char kTrackId[] = "somename";
66 const uint32 kSsrcOfTrack = 1234;
68 class MockWebRtcSession : public webrtc::WebRtcSession {
70 explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
71 : WebRtcSession(channel_manager, talk_base::Thread::Current(),
72 talk_base::Thread::Current(), NULL, NULL) {
74 MOCK_METHOD0(video_channel, cricket::VideoChannel*());
75 MOCK_METHOD2(GetTrackIdBySsrc, bool(uint32, std::string*));
76 MOCK_METHOD1(GetStats, bool(cricket::SessionStats*));
77 MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&));
80 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
82 MockVideoMediaChannel()
83 : cricket::FakeVideoMediaChannel(NULL) {
85 // MOCK_METHOD0(transport_channel, cricket::TransportChannel*());
86 MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
89 bool GetValue(const webrtc::StatsReport* report,
90 const std::string& name,
92 webrtc::StatsReport::Values::const_iterator it = report->values.begin();
93 for (; it != report->values.end(); ++it) {
94 if (it->name == name) {
102 std::string ExtractStatsValue(const std::string& type,
103 const webrtc::StatsReports& reports,
104 const std::string name) {
105 if (reports.empty()) {
108 for (size_t i = 0; i < reports.size(); ++i) {
109 if (reports[i].type != type)
112 if (GetValue(&reports[i], name, &ret)) {
120 // Finds the |n|-th report of type |type| in |reports|.
121 // |n| starts from 1 for finding the first report.
122 const webrtc::StatsReport* FindNthReportByType(
123 const webrtc::StatsReports& reports, const std::string& type, int n) {
124 for (size_t i = 0; i < reports.size(); ++i) {
125 if (reports[i].type == type) {
134 const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
135 const std::string& id) {
136 for (size_t i = 0; i < reports.size(); ++i) {
137 if (reports[i].id == id) {
144 std::string ExtractSsrcStatsValue(webrtc::StatsReports reports,
145 const std::string& name) {
146 return ExtractStatsValue(
147 webrtc::StatsReport::kStatsReportTypeSsrc, reports, name);
150 std::string ExtractBweStatsValue(webrtc::StatsReports reports,
151 const std::string& name) {
152 return ExtractStatsValue(
153 webrtc::StatsReport::kStatsReportTypeBwe, reports, name);
156 std::string DerToPem(const std::string& der) {
157 return talk_base::SSLIdentity::DerToPem(
158 talk_base::kPemTypeCertificate,
159 reinterpret_cast<const unsigned char*>(der.c_str()),
163 std::vector<std::string> DersToPems(
164 const std::vector<std::string>& ders) {
165 std::vector<std::string> pems(ders.size());
166 std::transform(ders.begin(), ders.end(), pems.begin(), DerToPem);
170 void CheckCertChainReports(const webrtc::StatsReports& reports,
171 const std::vector<std::string>& ders,
172 const std::string& start_id) {
173 std::string certificate_id = start_id;
176 const webrtc::StatsReport* report = FindReportById(reports, certificate_id);
177 ASSERT_TRUE(report != NULL);
179 std::string der_base64;
180 EXPECT_TRUE(GetValue(
181 report, webrtc::StatsReport::kStatsValueNameDer, &der_base64));
182 std::string der = talk_base::Base64::Decode(der_base64,
183 talk_base::Base64::DO_STRICT);
184 EXPECT_EQ(ders[i], der);
186 std::string fingerprint_algorithm;
187 EXPECT_TRUE(GetValue(
189 webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
190 &fingerprint_algorithm));
191 // The digest algorithm for a FakeSSLCertificate is always SHA-1.
192 std::string sha_1_str = talk_base::DIGEST_SHA_1;
193 EXPECT_EQ(sha_1_str, fingerprint_algorithm);
195 std::string dummy_fingerprint; // Value is not checked.
196 EXPECT_TRUE(GetValue(
198 webrtc::StatsReport::kStatsValueNameFingerprint,
199 &dummy_fingerprint));
203 report, webrtc::StatsReport::kStatsValueNameIssuerId, &certificate_id))
206 EXPECT_EQ(ders.size(), i);
209 class StatsCollectorTest : public testing::Test {
212 : media_engine_(new cricket::FakeMediaEngine),
214 new cricket::ChannelManager(media_engine_,
215 new cricket::FakeDeviceManager(),
216 talk_base::Thread::Current())),
217 session_(channel_manager_.get()),
218 track_id_(kTrackId) {
219 // By default, we ignore session GetStats calls.
220 EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
223 // This creates a standard setup with a transport called "trspname"
224 // having one transport channel
225 // and the specified virtual connection name.
226 void InitSessionStats(const std::string vc_name) {
227 const std::string kTransportName("trspname");
228 cricket::TransportStats transport_stats;
229 cricket::TransportChannelStats channel_stats;
230 channel_stats.component = 1;
231 transport_stats.content_name = kTransportName;
232 transport_stats.channel_stats.push_back(channel_stats);
234 session_stats_.transport_stats[kTransportName] = transport_stats;
235 session_stats_.proxy_to_transport[vc_name] = kTransportName;
238 // Adds a track with a given SSRC into the stats.
239 void AddVideoTrackStats() {
240 stream_ = webrtc::MediaStream::Create("streamlabel");
241 track_= webrtc::VideoTrack::Create(kTrackId, NULL);
242 stream_->AddTrack(track_);
243 EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
244 .WillRepeatedly(DoAll(SetArgPointee<1>(track_id_),
248 void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
249 const std::vector<std::string>& local_ders,
250 const talk_base::FakeSSLCertificate& remote_cert,
251 const std::vector<std::string>& remote_ders) {
252 webrtc::StatsCollector stats; // Implementation under test.
253 webrtc::StatsReports reports; // returned values.
254 stats.set_session(&session_);
256 // Fake stats to process.
257 cricket::TransportChannelStats channel_stats;
258 channel_stats.component = 1;
260 cricket::TransportStats transport_stats;
261 transport_stats.content_name = "audio";
262 transport_stats.channel_stats.push_back(channel_stats);
264 cricket::SessionStats session_stats;
265 session_stats.transport_stats[transport_stats.content_name] =
268 // Fake certificates to report.
269 talk_base::FakeSSLIdentity local_identity(local_cert);
270 talk_base::scoped_ptr<talk_base::FakeSSLCertificate> remote_cert_copy(
271 remote_cert.GetReference());
273 // Fake transport object.
274 talk_base::scoped_ptr<cricket::FakeTransport> transport(
275 new cricket::FakeTransport(
276 session_.signaling_thread(),
277 session_.worker_thread(),
278 transport_stats.content_name));
279 transport->SetIdentity(&local_identity);
280 cricket::FakeTransportChannel* channel =
281 static_cast<cricket::FakeTransportChannel*>(
282 transport->CreateChannel(channel_stats.component));
283 EXPECT_FALSE(channel == NULL);
284 channel->SetRemoteCertificate(remote_cert_copy.get());
286 // Configure MockWebRtcSession
287 EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
288 .WillOnce(Return(transport.get()));
289 EXPECT_CALL(session_, GetStats(_))
290 .WillOnce(DoAll(SetArgPointee<0>(session_stats),
292 EXPECT_CALL(session_, video_channel())
293 .WillRepeatedly(ReturnNull());
295 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
297 stats.GetStats(NULL, &reports);
299 const webrtc::StatsReport* channel_report = FindNthReportByType(
300 reports, webrtc::StatsReport::kStatsReportTypeComponent, 1);
301 EXPECT_TRUE(channel_report != NULL);
303 // Check local certificate chain.
304 std::string local_certificate_id = ExtractStatsValue(
305 webrtc::StatsReport::kStatsReportTypeComponent,
307 webrtc::StatsReport::kStatsValueNameLocalCertificateId);
308 if (local_ders.size() > 0) {
309 EXPECT_NE(kNotFound, local_certificate_id);
310 CheckCertChainReports(reports, local_ders, local_certificate_id);
312 EXPECT_EQ(kNotFound, local_certificate_id);
315 // Check remote certificate chain.
316 std::string remote_certificate_id = ExtractStatsValue(
317 webrtc::StatsReport::kStatsReportTypeComponent,
319 webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
320 if (remote_ders.size() > 0) {
321 EXPECT_NE(kNotFound, remote_certificate_id);
322 CheckCertChainReports(reports, remote_ders, remote_certificate_id);
324 EXPECT_EQ(kNotFound, remote_certificate_id);
328 cricket::FakeMediaEngine* media_engine_;
329 talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
330 MockWebRtcSession session_;
331 cricket::SessionStats session_stats_;
332 talk_base::scoped_refptr<webrtc::MediaStream> stream_;
333 talk_base::scoped_refptr<webrtc::VideoTrack> track_;
334 std::string track_id_;
337 // This test verifies that 64-bit counters are passed successfully.
338 TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
339 webrtc::StatsCollector stats; // Implementation under test.
340 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
341 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
342 media_engine_, media_channel, &session_, "", false, NULL);
343 webrtc::StatsReports reports; // returned values.
344 cricket::VideoSenderInfo video_sender_info;
345 cricket::VideoMediaInfo stats_read;
346 // The number of bytes must be larger than 0xFFFFFFFF for this test.
347 const int64 kBytesSent = 12345678901234LL;
348 const std::string kBytesSentString("12345678901234");
350 stats.set_session(&session_);
351 AddVideoTrackStats();
352 stats.AddStream(stream_);
354 // Construct a stats value to read.
355 video_sender_info.add_ssrc(1234);
356 video_sender_info.bytes_sent = kBytesSent;
357 stats_read.senders.push_back(video_sender_info);
359 EXPECT_CALL(session_, video_channel())
360 .WillRepeatedly(Return(&video_channel));
361 EXPECT_CALL(*media_channel, GetStats(_, _))
362 .WillOnce(DoAll(SetArgPointee<1>(stats_read),
364 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
365 stats.GetStats(NULL, &reports);
366 std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
367 EXPECT_EQ(kBytesSentString, result);
370 // Test that BWE information is reported via stats.
371 TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
372 webrtc::StatsCollector stats; // Implementation under test.
373 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
374 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
375 media_engine_, media_channel, &session_, "", false, NULL);
376 webrtc::StatsReports reports; // returned values.
377 cricket::VideoSenderInfo video_sender_info;
378 cricket::VideoMediaInfo stats_read;
379 // Set up an SSRC just to test that we get both kinds of stats back: SSRC and
381 const int64 kBytesSent = 12345678901234LL;
382 const std::string kBytesSentString("12345678901234");
384 stats.set_session(&session_);
385 AddVideoTrackStats();
386 stats.AddStream(stream_);
388 // Construct a stats value to read.
389 video_sender_info.add_ssrc(1234);
390 video_sender_info.bytes_sent = kBytesSent;
391 stats_read.senders.push_back(video_sender_info);
392 cricket::BandwidthEstimationInfo bwe;
393 const int kTargetEncBitrate = 123456;
394 const std::string kTargetEncBitrateString("123456");
395 bwe.target_enc_bitrate = kTargetEncBitrate;
396 stats_read.bw_estimations.push_back(bwe);
398 EXPECT_CALL(session_, video_channel())
399 .WillRepeatedly(Return(&video_channel));
400 EXPECT_CALL(*media_channel, GetStats(_, _))
401 .WillOnce(DoAll(SetArgPointee<1>(stats_read),
404 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
405 stats.GetStats(NULL, &reports);
406 std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
407 EXPECT_EQ(kBytesSentString, result);
408 result = ExtractBweStatsValue(reports, "googTargetEncBitrate");
409 EXPECT_EQ(kTargetEncBitrateString, result);
412 // This test verifies that an object of type "googSession" always
413 // exists in the returned stats.
414 TEST_F(StatsCollectorTest, SessionObjectExists) {
415 webrtc::StatsCollector stats; // Implementation under test.
416 webrtc::StatsReports reports; // returned values.
417 stats.set_session(&session_);
418 EXPECT_CALL(session_, video_channel())
419 .WillRepeatedly(ReturnNull());
420 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
421 stats.GetStats(NULL, &reports);
422 const webrtc::StatsReport* session_report = FindNthReportByType(
423 reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
424 EXPECT_FALSE(session_report == NULL);
427 // This test verifies that only one object of type "googSession" exists
428 // in the returned stats.
429 TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
430 webrtc::StatsCollector stats; // Implementation under test.
431 webrtc::StatsReports reports; // returned values.
432 stats.set_session(&session_);
433 EXPECT_CALL(session_, video_channel())
434 .WillRepeatedly(ReturnNull());
435 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
436 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
437 stats.GetStats(NULL, &reports);
438 const webrtc::StatsReport* session_report = FindNthReportByType(
439 reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
440 EXPECT_FALSE(session_report == NULL);
441 session_report = FindNthReportByType(
442 reports, webrtc::StatsReport::kStatsReportTypeSession, 2);
443 EXPECT_EQ(NULL, session_report);
446 // This test verifies that the empty track report exists in the returned stats
447 // without calling StatsCollector::UpdateStats.
448 TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) {
449 webrtc::StatsCollector stats; // Implementation under test.
450 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
451 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
452 media_engine_, media_channel, &session_, "", false, NULL);
453 AddVideoTrackStats();
454 stats.AddStream(stream_);
456 stats.set_session(&session_);
458 webrtc::StatsReports reports;
460 // Verfies the existence of the track report.
461 stats.GetStats(NULL, &reports);
462 EXPECT_EQ((size_t)1, reports.size());
463 EXPECT_EQ(std::string(webrtc::StatsReport::kStatsReportTypeTrack),
466 std::string trackValue =
467 ExtractStatsValue(webrtc::StatsReport::kStatsReportTypeTrack,
469 webrtc::StatsReport::kStatsValueNameTrackId);
470 EXPECT_EQ(kTrackId, trackValue);
473 // This test verifies that the empty track report exists in the returned stats
474 // when StatsCollector::UpdateStats is called with ssrc stats.
475 TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
476 webrtc::StatsCollector stats; // Implementation under test.
477 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
478 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
479 media_engine_, media_channel, &session_, "", false, NULL);
480 AddVideoTrackStats();
481 stats.AddStream(stream_);
483 stats.set_session(&session_);
485 webrtc::StatsReports reports;
487 // Constructs an ssrc stats update.
488 cricket::VideoSenderInfo video_sender_info;
489 cricket::VideoMediaInfo stats_read;
490 const int64 kBytesSent = 12345678901234LL;
492 // Construct a stats value to read.
493 video_sender_info.add_ssrc(1234);
494 video_sender_info.bytes_sent = kBytesSent;
495 stats_read.senders.push_back(video_sender_info);
497 EXPECT_CALL(session_, video_channel())
498 .WillRepeatedly(Return(&video_channel));
499 EXPECT_CALL(*media_channel, GetStats(_, _))
500 .WillOnce(DoAll(SetArgPointee<1>(stats_read),
503 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
504 stats.GetStats(NULL, &reports);
505 // |reports| should contain at least one session report, one track report,
506 // and one ssrc report.
507 EXPECT_LE((size_t)3, reports.size());
508 const webrtc::StatsReport* track_report = FindNthReportByType(
509 reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
510 EXPECT_FALSE(track_report == NULL);
512 stats.GetStats(track_, &reports);
513 // |reports| should contain at least one session report, one track report,
514 // and one ssrc report.
515 EXPECT_LE((size_t)3, reports.size());
516 track_report = FindNthReportByType(
517 reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
518 EXPECT_FALSE(track_report == NULL);
520 std::string ssrc_id = ExtractSsrcStatsValue(
521 reports, webrtc::StatsReport::kStatsValueNameSsrc);
522 EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
524 std::string track_id = ExtractSsrcStatsValue(
525 reports, webrtc::StatsReport::kStatsValueNameTrackId);
526 EXPECT_EQ(kTrackId, track_id);
529 // This test verifies that an SSRC object has the identifier of a Transport
530 // stats object, and that this transport stats object exists in stats.
531 TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
532 webrtc::StatsCollector stats; // Implementation under test.
533 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
534 // The content_name known by the video channel.
535 const std::string kVcName("vcname");
536 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
537 media_engine_, media_channel, &session_, kVcName, false, NULL);
538 AddVideoTrackStats();
539 stats.AddStream(stream_);
541 stats.set_session(&session_);
543 webrtc::StatsReports reports;
545 // Constructs an ssrc stats update.
546 cricket::VideoSenderInfo video_sender_info;
547 cricket::VideoMediaInfo stats_read;
548 const int64 kBytesSent = 12345678901234LL;
550 // Construct a stats value to read.
551 video_sender_info.add_ssrc(1234);
552 video_sender_info.bytes_sent = kBytesSent;
553 stats_read.senders.push_back(video_sender_info);
555 EXPECT_CALL(session_, video_channel())
556 .WillRepeatedly(Return(&video_channel));
557 EXPECT_CALL(*media_channel, GetStats(_, _))
558 .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
561 InitSessionStats(kVcName);
562 EXPECT_CALL(session_, GetStats(_))
563 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
566 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
567 stats.GetStats(NULL, &reports);
568 std::string transport_id = ExtractStatsValue(
569 webrtc::StatsReport::kStatsReportTypeSsrc,
571 webrtc::StatsReport::kStatsValueNameTransportId);
572 ASSERT_NE(kNotFound, transport_id);
573 const webrtc::StatsReport* transport_report = FindReportById(reports,
575 ASSERT_FALSE(transport_report == NULL);
578 // This test verifies that a remote stats object will not be created for
579 // an outgoing SSRC where remote stats are not returned.
580 TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
581 webrtc::StatsCollector stats; // Implementation under test.
582 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
583 // The content_name known by the video channel.
584 const std::string kVcName("vcname");
585 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
586 media_engine_, media_channel, &session_, kVcName, false, NULL);
587 AddVideoTrackStats();
588 stats.AddStream(stream_);
590 stats.set_session(&session_);
592 EXPECT_CALL(session_, video_channel())
593 .WillRepeatedly(ReturnNull());
595 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
596 webrtc::StatsReports reports;
597 stats.GetStats(NULL, &reports);
598 const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
599 webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
600 EXPECT_TRUE(remote_report == NULL);
603 // This test verifies that a remote stats object will be created for
604 // an outgoing SSRC where stats are returned.
605 TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
606 webrtc::StatsCollector stats; // Implementation under test.
607 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
608 // The content_name known by the video channel.
609 const std::string kVcName("vcname");
610 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
611 media_engine_, media_channel, &session_, kVcName, false, NULL);
612 AddVideoTrackStats();
613 stats.AddStream(stream_);
615 stats.set_session(&session_);
617 webrtc::StatsReports reports;
619 // Instruct the session to return stats containing the transport channel.
620 InitSessionStats(kVcName);
621 EXPECT_CALL(session_, GetStats(_))
622 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
625 // Constructs an ssrc stats update.
626 cricket::VideoMediaInfo stats_read;
628 cricket::SsrcReceiverInfo remote_ssrc_stats;
629 remote_ssrc_stats.timestamp = 12345.678;
630 remote_ssrc_stats.ssrc = kSsrcOfTrack;
631 cricket::VideoSenderInfo video_sender_info;
632 video_sender_info.add_ssrc(kSsrcOfTrack);
633 video_sender_info.remote_stats.push_back(remote_ssrc_stats);
634 stats_read.senders.push_back(video_sender_info);
636 EXPECT_CALL(session_, video_channel())
637 .WillRepeatedly(Return(&video_channel));
638 EXPECT_CALL(*media_channel, GetStats(_, _))
639 .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
642 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
643 stats.GetStats(NULL, &reports);
644 const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
645 webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
646 EXPECT_FALSE(remote_report == NULL);
647 EXPECT_NE(0, remote_report->timestamp);
650 // This test verifies that all chained certificates are correctly
652 TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) {
653 // Build local certificate chain.
654 std::vector<std::string> local_ders(5);
655 local_ders[0] = "These";
656 local_ders[1] = "are";
657 local_ders[2] = "some";
658 local_ders[3] = "der";
659 local_ders[4] = "values";
660 talk_base::FakeSSLCertificate local_cert(DersToPems(local_ders));
662 // Build remote certificate chain
663 std::vector<std::string> remote_ders(4);
664 remote_ders[0] = "A";
665 remote_ders[1] = "non-";
666 remote_ders[2] = "intersecting";
667 remote_ders[3] = "set";
668 talk_base::FakeSSLCertificate remote_cert(DersToPems(remote_ders));
670 TestCertificateReports(local_cert, local_ders, remote_cert, remote_ders);
673 // This test verifies that all certificates without chains are correctly
675 TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) {
676 // Build local certificate.
677 std::string local_der = "This is the local der.";
678 talk_base::FakeSSLCertificate local_cert(DerToPem(local_der));
680 // Build remote certificate.
681 std::string remote_der = "This is somebody else's der.";
682 talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
684 TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
685 remote_cert, std::vector<std::string>(1, remote_der));
688 // This test verifies that the stats are generated correctly when no
689 // transport is present.
690 TEST_F(StatsCollectorTest, NoTransport) {
691 webrtc::StatsCollector stats; // Implementation under test.
692 webrtc::StatsReports reports; // returned values.
693 stats.set_session(&session_);
695 // Fake stats to process.
696 cricket::TransportChannelStats channel_stats;
697 channel_stats.component = 1;
699 cricket::TransportStats transport_stats;
700 transport_stats.content_name = "audio";
701 transport_stats.channel_stats.push_back(channel_stats);
703 cricket::SessionStats session_stats;
704 session_stats.transport_stats[transport_stats.content_name] =
707 // Configure MockWebRtcSession
708 EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
709 .WillOnce(ReturnNull());
710 EXPECT_CALL(session_, GetStats(_))
711 .WillOnce(DoAll(SetArgPointee<0>(session_stats),
714 EXPECT_CALL(session_, video_channel())
715 .WillRepeatedly(ReturnNull());
717 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
718 stats.GetStats(NULL, &reports);
720 // Check that the local certificate is absent.
721 std::string local_certificate_id = ExtractStatsValue(
722 webrtc::StatsReport::kStatsReportTypeComponent,
724 webrtc::StatsReport::kStatsValueNameLocalCertificateId);
725 ASSERT_EQ(kNotFound, local_certificate_id);
727 // Check that the remote certificate is absent.
728 std::string remote_certificate_id = ExtractStatsValue(
729 webrtc::StatsReport::kStatsReportTypeComponent,
731 webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
732 ASSERT_EQ(kNotFound, remote_certificate_id);
735 // This test verifies that the stats are generated correctly when the transport
736 // does not have any certificates.
737 TEST_F(StatsCollectorTest, NoCertificates) {
738 webrtc::StatsCollector stats; // Implementation under test.
739 webrtc::StatsReports reports; // returned values.
740 stats.set_session(&session_);
742 // Fake stats to process.
743 cricket::TransportChannelStats channel_stats;
744 channel_stats.component = 1;
746 cricket::TransportStats transport_stats;
747 transport_stats.content_name = "audio";
748 transport_stats.channel_stats.push_back(channel_stats);
750 cricket::SessionStats session_stats;
751 session_stats.transport_stats[transport_stats.content_name] =
754 // Fake transport object.
755 talk_base::scoped_ptr<cricket::FakeTransport> transport(
756 new cricket::FakeTransport(
757 session_.signaling_thread(),
758 session_.worker_thread(),
759 transport_stats.content_name));
761 // Configure MockWebRtcSession
762 EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
763 .WillOnce(Return(transport.get()));
764 EXPECT_CALL(session_, GetStats(_))
765 .WillOnce(DoAll(SetArgPointee<0>(session_stats),
767 EXPECT_CALL(session_, video_channel())
768 .WillRepeatedly(ReturnNull());
770 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
771 stats.GetStats(NULL, &reports);
773 // Check that the local certificate is absent.
774 std::string local_certificate_id = ExtractStatsValue(
775 webrtc::StatsReport::kStatsReportTypeComponent,
777 webrtc::StatsReport::kStatsValueNameLocalCertificateId);
778 ASSERT_EQ(kNotFound, local_certificate_id);
780 // Check that the remote certificate is absent.
781 std::string remote_certificate_id = ExtractStatsValue(
782 webrtc::StatsReport::kStatsReportTypeComponent,
784 webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
785 ASSERT_EQ(kNotFound, remote_certificate_id);
788 // This test verifies that a remote certificate with an unsupported digest
789 // algorithm is correctly ignored.
790 TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) {
791 // Build a local certificate.
792 std::string local_der = "This is the local der.";
793 talk_base::FakeSSLCertificate local_cert(DerToPem(local_der));
795 // Build a remote certificate with an unsupported digest algorithm.
796 std::string remote_der = "This is somebody else's der.";
797 talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
798 remote_cert.set_digest_algorithm("foobar");
800 TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
801 remote_cert, std::vector<std::string>());
804 // Verifies the correct optons are passed to the VideoMediaChannel when using
805 // verbose output level.
806 TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
807 webrtc::StatsCollector stats; // Implementation under test.
808 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
809 cricket::VideoChannel video_channel(talk_base::Thread::Current(),
810 media_engine_, media_channel, &session_, "", false, NULL);
811 stats.set_session(&session_);
813 webrtc::StatsReports reports; // returned values.
814 cricket::VideoMediaInfo stats_read;
815 cricket::BandwidthEstimationInfo bwe;
816 bwe.total_received_propagation_delta_ms = 10;
817 bwe.recent_received_propagation_delta_ms.push_back(100);
818 bwe.recent_received_propagation_delta_ms.push_back(200);
819 bwe.recent_received_packet_group_arrival_time_ms.push_back(1000);
820 bwe.recent_received_packet_group_arrival_time_ms.push_back(2000);
821 stats_read.bw_estimations.push_back(bwe);
823 EXPECT_CALL(session_, video_channel())
824 .WillRepeatedly(Return(&video_channel));
826 StatsOptions options;
827 options.include_received_propagation_stats = true;
828 EXPECT_CALL(*media_channel, GetStats(
829 Field(&StatsOptions::include_received_propagation_stats, true),
831 .WillOnce(DoAll(SetArgPointee<1>(stats_read),
834 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelDebug);
835 stats.GetStats(NULL, &reports);
836 std::string result = ExtractBweStatsValue(
837 reports, "googReceivedPacketGroupPropagationDeltaSumDebug");
838 EXPECT_EQ("10", result);
839 result = ExtractBweStatsValue(
840 reports, "googReceivedPacketGroupPropagationDeltaDebug");
841 EXPECT_EQ("[100, 200]", result);
842 result = ExtractBweStatsValue(
843 reports, "googReceivedPacketGroupArrivalTimeDebug");
844 EXPECT_EQ("[1000, 2000]", result);