Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / app / webrtc / statscollector_unittest.cc
1 /*
2  * libjingle
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
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.
14  *
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.
25  */
26
27 #include <stdio.h>
28
29 #include "talk/app/webrtc/statscollector.h"
30
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"
41
42 using cricket::StatsOptions;
43 using testing::_;
44 using testing::DoAll;
45 using testing::Field;
46 using testing::Return;
47 using testing::ReturnNull;
48 using testing::SetArgPointee;
49 using webrtc::PeerConnectionInterface;
50
51 namespace cricket {
52
53 class ChannelManager;
54 class FakeDeviceManager;
55
56 }  // namespace cricket
57
58 namespace {
59
60 // Error return values
61 const char kNotFound[] = "NOT FOUND";
62 const char kNoReports[] = "NO REPORTS";
63
64 // Constant names for track identification.
65 const char kTrackId[] = "somename";
66 const uint32 kSsrcOfTrack = 1234;
67
68 class MockWebRtcSession : public webrtc::WebRtcSession {
69  public:
70   explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
71     : WebRtcSession(channel_manager, talk_base::Thread::Current(),
72                     talk_base::Thread::Current(), NULL, NULL) {
73   }
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&));
78 };
79
80 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
81  public:
82   MockVideoMediaChannel()
83     : cricket::FakeVideoMediaChannel(NULL) {
84   }
85   // MOCK_METHOD0(transport_channel, cricket::TransportChannel*());
86   MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
87 };
88
89 bool GetValue(const webrtc::StatsReport* report,
90               const std::string& name,
91               std::string* value) {
92   webrtc::StatsReport::Values::const_iterator it = report->values.begin();
93   for (; it != report->values.end(); ++it) {
94     if (it->name == name) {
95       *value = it->value;
96       return true;
97     }
98   }
99   return false;
100 }
101
102 std::string ExtractStatsValue(const std::string& type,
103                               const webrtc::StatsReports& reports,
104                               const std::string name) {
105   if (reports.empty()) {
106     return kNoReports;
107   }
108   for (size_t i = 0; i < reports.size(); ++i) {
109     if (reports[i].type != type)
110       continue;
111     std::string ret;
112     if (GetValue(&reports[i], name, &ret)) {
113       return ret;
114     }
115   }
116
117   return kNotFound;
118 }
119
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) {
126       n--;
127       if (n == 0)
128         return &reports[i];
129     }
130   }
131   return NULL;
132 }
133
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) {
138       return &reports[i];
139     }
140   }
141   return NULL;
142 }
143
144 std::string ExtractSsrcStatsValue(webrtc::StatsReports reports,
145                                   const std::string& name) {
146   return ExtractStatsValue(
147       webrtc::StatsReport::kStatsReportTypeSsrc, reports, name);
148 }
149
150 std::string ExtractBweStatsValue(webrtc::StatsReports reports,
151                                   const std::string& name) {
152   return ExtractStatsValue(
153       webrtc::StatsReport::kStatsReportTypeBwe, reports, name);
154 }
155
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()),
160         der.length());
161 }
162
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);
167   return pems;
168 }
169
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;
174   size_t i = 0;
175   while (true) {
176     const webrtc::StatsReport* report = FindReportById(reports, certificate_id);
177     ASSERT_TRUE(report != NULL);
178
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);
185
186     std::string fingerprint_algorithm;
187     EXPECT_TRUE(GetValue(
188         report,
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);
194
195     std::string dummy_fingerprint;  // Value is not checked.
196     EXPECT_TRUE(GetValue(
197         report,
198         webrtc::StatsReport::kStatsValueNameFingerprint,
199         &dummy_fingerprint));
200
201     ++i;
202     if (!GetValue(
203         report, webrtc::StatsReport::kStatsValueNameIssuerId, &certificate_id))
204       break;
205   }
206   EXPECT_EQ(ders.size(), i);
207 }
208
209 class StatsCollectorTest : public testing::Test {
210  protected:
211   StatsCollectorTest()
212     : media_engine_(new cricket::FakeMediaEngine),
213       channel_manager_(
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));
221   }
222
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);
233
234     session_stats_.transport_stats[kTransportName] = transport_stats;
235     session_stats_.proxy_to_transport[vc_name] = kTransportName;
236   }
237
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_),
245                             Return(true)));
246   }
247
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_);
255
256     // Fake stats to process.
257     cricket::TransportChannelStats channel_stats;
258     channel_stats.component = 1;
259
260     cricket::TransportStats transport_stats;
261     transport_stats.content_name = "audio";
262     transport_stats.channel_stats.push_back(channel_stats);
263
264     cricket::SessionStats session_stats;
265     session_stats.transport_stats[transport_stats.content_name] =
266         transport_stats;
267
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());
272
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());
285
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),
291                       Return(true)));
292     EXPECT_CALL(session_, video_channel())
293       .WillRepeatedly(ReturnNull());
294
295     stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
296
297     stats.GetStats(NULL, &reports);
298
299     const webrtc::StatsReport* channel_report = FindNthReportByType(
300         reports, webrtc::StatsReport::kStatsReportTypeComponent, 1);
301     EXPECT_TRUE(channel_report != NULL);
302
303     // Check local certificate chain.
304     std::string local_certificate_id = ExtractStatsValue(
305         webrtc::StatsReport::kStatsReportTypeComponent,
306         reports,
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);
311     } else {
312       EXPECT_EQ(kNotFound, local_certificate_id);
313     }
314
315     // Check remote certificate chain.
316     std::string remote_certificate_id = ExtractStatsValue(
317         webrtc::StatsReport::kStatsReportTypeComponent,
318         reports,
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);
323     } else {
324       EXPECT_EQ(kNotFound, remote_certificate_id);
325     }
326   }
327
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_;
335 };
336
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");
349
350   stats.set_session(&session_);
351   AddVideoTrackStats();
352   stats.AddStream(stream_);
353
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);
358
359   EXPECT_CALL(session_, video_channel())
360     .WillRepeatedly(Return(&video_channel));
361   EXPECT_CALL(*media_channel, GetStats(_, _))
362     .WillOnce(DoAll(SetArgPointee<1>(stats_read),
363                     Return(true)));
364   stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
365   stats.GetStats(NULL, &reports);
366   std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
367   EXPECT_EQ(kBytesSentString, result);
368 }
369
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
380   // BWE.
381   const int64 kBytesSent = 12345678901234LL;
382   const std::string kBytesSentString("12345678901234");
383
384   stats.set_session(&session_);
385   AddVideoTrackStats();
386   stats.AddStream(stream_);
387
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);
397
398   EXPECT_CALL(session_, video_channel())
399     .WillRepeatedly(Return(&video_channel));
400   EXPECT_CALL(*media_channel, GetStats(_, _))
401     .WillOnce(DoAll(SetArgPointee<1>(stats_read),
402                     Return(true)));
403
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);
410 }
411
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);
425 }
426
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);
444 }
445
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_);
455
456   stats.set_session(&session_);
457
458   webrtc::StatsReports reports;
459
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),
464             reports[0].type);
465
466   std::string trackValue =
467       ExtractStatsValue(webrtc::StatsReport::kStatsReportTypeTrack,
468                         reports,
469                         webrtc::StatsReport::kStatsValueNameTrackId);
470   EXPECT_EQ(kTrackId, trackValue);
471 }
472
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_);
482
483   stats.set_session(&session_);
484
485   webrtc::StatsReports reports;
486
487   // Constructs an ssrc stats update.
488   cricket::VideoSenderInfo video_sender_info;
489   cricket::VideoMediaInfo stats_read;
490   const int64 kBytesSent = 12345678901234LL;
491
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);
496
497   EXPECT_CALL(session_, video_channel())
498     .WillRepeatedly(Return(&video_channel));
499   EXPECT_CALL(*media_channel, GetStats(_, _))
500     .WillOnce(DoAll(SetArgPointee<1>(stats_read),
501                     Return(true)));
502
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);
511
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);
519
520   std::string ssrc_id = ExtractSsrcStatsValue(
521       reports, webrtc::StatsReport::kStatsValueNameSsrc);
522   EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
523
524   std::string track_id = ExtractSsrcStatsValue(
525       reports, webrtc::StatsReport::kStatsValueNameTrackId);
526   EXPECT_EQ(kTrackId, track_id);
527 }
528
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_);
540
541   stats.set_session(&session_);
542
543   webrtc::StatsReports reports;
544
545   // Constructs an ssrc stats update.
546   cricket::VideoSenderInfo video_sender_info;
547   cricket::VideoMediaInfo stats_read;
548   const int64 kBytesSent = 12345678901234LL;
549
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);
554
555   EXPECT_CALL(session_, video_channel())
556     .WillRepeatedly(Return(&video_channel));
557   EXPECT_CALL(*media_channel, GetStats(_, _))
558     .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
559                           Return(true)));
560
561   InitSessionStats(kVcName);
562   EXPECT_CALL(session_, GetStats(_))
563     .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
564                           Return(true)));
565
566   stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
567   stats.GetStats(NULL, &reports);
568   std::string transport_id = ExtractStatsValue(
569       webrtc::StatsReport::kStatsReportTypeSsrc,
570       reports,
571       webrtc::StatsReport::kStatsValueNameTransportId);
572   ASSERT_NE(kNotFound, transport_id);
573   const webrtc::StatsReport* transport_report = FindReportById(reports,
574                                                                transport_id);
575   ASSERT_FALSE(transport_report == NULL);
576 }
577
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_);
589
590   stats.set_session(&session_);
591
592   EXPECT_CALL(session_, video_channel())
593     .WillRepeatedly(ReturnNull());
594
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);
601 }
602
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_);
614
615   stats.set_session(&session_);
616
617   webrtc::StatsReports reports;
618
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_),
623                           Return(true)));
624
625   // Constructs an ssrc stats update.
626   cricket::VideoMediaInfo stats_read;
627
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);
635
636   EXPECT_CALL(session_, video_channel())
637     .WillRepeatedly(Return(&video_channel));
638   EXPECT_CALL(*media_channel, GetStats(_, _))
639     .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
640                           Return(true)));
641
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);
648 }
649
650 // This test verifies that all chained certificates are correctly
651 // reported
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));
661
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));
669
670   TestCertificateReports(local_cert, local_ders, remote_cert, remote_ders);
671 }
672
673 // This test verifies that all certificates without chains are correctly
674 // reported.
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));
679
680   // Build remote certificate.
681   std::string remote_der = "This is somebody else's der.";
682   talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
683
684   TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
685                          remote_cert, std::vector<std::string>(1, remote_der));
686 }
687
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_);
694
695   // Fake stats to process.
696   cricket::TransportChannelStats channel_stats;
697   channel_stats.component = 1;
698
699   cricket::TransportStats transport_stats;
700   transport_stats.content_name = "audio";
701   transport_stats.channel_stats.push_back(channel_stats);
702
703   cricket::SessionStats session_stats;
704   session_stats.transport_stats[transport_stats.content_name] =
705       transport_stats;
706
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),
712                     Return(true)));
713
714   EXPECT_CALL(session_, video_channel())
715     .WillRepeatedly(ReturnNull());
716
717   stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
718   stats.GetStats(NULL, &reports);
719
720   // Check that the local certificate is absent.
721   std::string local_certificate_id = ExtractStatsValue(
722       webrtc::StatsReport::kStatsReportTypeComponent,
723       reports,
724       webrtc::StatsReport::kStatsValueNameLocalCertificateId);
725   ASSERT_EQ(kNotFound, local_certificate_id);
726
727   // Check that the remote certificate is absent.
728   std::string remote_certificate_id = ExtractStatsValue(
729       webrtc::StatsReport::kStatsReportTypeComponent,
730       reports,
731       webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
732   ASSERT_EQ(kNotFound, remote_certificate_id);
733 }
734
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_);
741
742   // Fake stats to process.
743   cricket::TransportChannelStats channel_stats;
744   channel_stats.component = 1;
745
746   cricket::TransportStats transport_stats;
747   transport_stats.content_name = "audio";
748   transport_stats.channel_stats.push_back(channel_stats);
749
750   cricket::SessionStats session_stats;
751   session_stats.transport_stats[transport_stats.content_name] =
752       transport_stats;
753
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));
760
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),
766                     Return(true)));
767   EXPECT_CALL(session_, video_channel())
768     .WillRepeatedly(ReturnNull());
769
770   stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
771   stats.GetStats(NULL, &reports);
772
773   // Check that the local certificate is absent.
774   std::string local_certificate_id = ExtractStatsValue(
775       webrtc::StatsReport::kStatsReportTypeComponent,
776       reports,
777       webrtc::StatsReport::kStatsValueNameLocalCertificateId);
778   ASSERT_EQ(kNotFound, local_certificate_id);
779
780   // Check that the remote certificate is absent.
781   std::string remote_certificate_id = ExtractStatsValue(
782       webrtc::StatsReport::kStatsReportTypeComponent,
783       reports,
784       webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
785   ASSERT_EQ(kNotFound, remote_certificate_id);
786 }
787
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));
794
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");
799
800   TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
801                          remote_cert, std::vector<std::string>());
802 }
803
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_);
812
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);
822
823   EXPECT_CALL(session_, video_channel())
824     .WillRepeatedly(Return(&video_channel));
825
826   StatsOptions options;
827   options.include_received_propagation_stats = true;
828   EXPECT_CALL(*media_channel, GetStats(
829       Field(&StatsOptions::include_received_propagation_stats, true),
830       _))
831     .WillOnce(DoAll(SetArgPointee<1>(stats_read),
832                     Return(true)));
833
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);
845 }
846
847 }  // namespace