1/*
2 * libjingle
3 * Copyright 2014, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <stdio.h>
29
30#include "talk/app/webrtc/statscollector.h"
31
32#include "talk/app/webrtc/mediastream.h"
33#include "talk/app/webrtc/mediastreaminterface.h"
34#include "talk/app/webrtc/mediastreamtrack.h"
35#include "talk/app/webrtc/videotrack.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/gmock/include/gmock/gmock.h"
41#include "testing/gtest/include/gtest/gtest.h"
42#include "webrtc/base/base64.h"
43#include "webrtc/base/fakesslidentity.h"
44#include "webrtc/base/gunit.h"
45
46using cricket::StatsOptions;
47using testing::_;
48using testing::DoAll;
49using testing::Field;
50using testing::Return;
51using testing::ReturnNull;
52using testing::SetArgPointee;
53using webrtc::PeerConnectionInterface;
54using webrtc::StatsReport;
55using webrtc::StatsReports;
56
57namespace cricket {
58
59class ChannelManager;
60class FakeDeviceManager;
61
62}  // namespace cricket
63
64namespace {
65
66// Error return values
67const char kNotFound[] = "NOT FOUND";
68const char kNoReports[] = "NO REPORTS";
69
70// Constant names for track identification.
71const char kLocalTrackId[] = "local_track_id";
72const char kRemoteTrackId[] = "remote_track_id";
73const uint32 kSsrcOfTrack = 1234;
74
75class MockWebRtcSession : public webrtc::WebRtcSession {
76 public:
77  explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
78    : WebRtcSession(channel_manager, rtc::Thread::Current(),
79                    rtc::Thread::Current(), NULL, NULL) {
80  }
81  MOCK_METHOD0(voice_channel, cricket::VoiceChannel*());
82  MOCK_METHOD0(video_channel, cricket::VideoChannel*());
83  // Libjingle uses "local" for a outgoing track, and "remote" for a incoming
84  // track.
85  MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32, std::string*));
86  MOCK_METHOD2(GetRemoteTrackIdBySsrc, bool(uint32, std::string*));
87  MOCK_METHOD1(GetStats, bool(cricket::SessionStats*));
88  MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&));
89};
90
91class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
92 public:
93  MockVideoMediaChannel()
94    : cricket::FakeVideoMediaChannel(NULL) {
95  }
96  // MOCK_METHOD0(transport_channel, cricket::TransportChannel*());
97  MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
98};
99
100class MockVoiceMediaChannel : public cricket::FakeVoiceMediaChannel {
101 public:
102  MockVoiceMediaChannel() : cricket::FakeVoiceMediaChannel(NULL) {
103  }
104  MOCK_METHOD1(GetStats, bool(cricket::VoiceMediaInfo*));
105};
106
107class FakeAudioProcessor : public webrtc::AudioProcessorInterface {
108 public:
109  FakeAudioProcessor() {}
110  ~FakeAudioProcessor() {}
111
112 private:
113  virtual void GetStats(
114      AudioProcessorInterface::AudioProcessorStats* stats) OVERRIDE {
115    stats->typing_noise_detected = true;
116    stats->echo_return_loss = 2;
117    stats->echo_return_loss_enhancement = 3;
118    stats->echo_delay_median_ms = 4;
119    stats->aec_quality_min = 5.1f;
120    stats->echo_delay_std_ms = 6;
121  }
122};
123
124class FakeAudioTrack
125    : public webrtc::MediaStreamTrack<webrtc::AudioTrackInterface> {
126 public:
127  explicit FakeAudioTrack(const std::string& id)
128      : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(id),
129        processor_(new rtc::RefCountedObject<FakeAudioProcessor>()) {}
130  std::string kind() const OVERRIDE {
131    return "audio";
132  }
133  virtual webrtc::AudioSourceInterface* GetSource() const OVERRIDE {
134    return NULL;
135  }
136  virtual void AddSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
137  virtual void RemoveSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
138  virtual bool GetSignalLevel(int* level) OVERRIDE {
139    *level = 1;
140    return true;
141  }
142  virtual rtc::scoped_refptr<webrtc::AudioProcessorInterface>
143      GetAudioProcessor() OVERRIDE {
144    return processor_;
145  }
146
147 private:
148  rtc::scoped_refptr<FakeAudioProcessor> processor_;
149};
150
151bool GetValue(const StatsReport* report,
152              StatsReport::StatsValueName name,
153              std::string* value) {
154  StatsReport::Values::const_iterator it = report->values.begin();
155  for (; it != report->values.end(); ++it) {
156    if (it->name == name) {
157      *value = it->value;
158      return true;
159    }
160  }
161  return false;
162}
163
164std::string ExtractStatsValue(const std::string& type,
165                              const StatsReports& reports,
166                              StatsReport::StatsValueName name) {
167  if (reports.empty()) {
168    return kNoReports;
169  }
170  for (size_t i = 0; i < reports.size(); ++i) {
171    if (reports[i]->type != type)
172      continue;
173    std::string ret;
174    if (GetValue(reports[i], name, &ret)) {
175      return ret;
176    }
177  }
178
179  return kNotFound;
180}
181
182// Finds the |n|-th report of type |type| in |reports|.
183// |n| starts from 1 for finding the first report.
184const StatsReport* FindNthReportByType(
185    const StatsReports& reports, const std::string& type, int n) {
186  for (size_t i = 0; i < reports.size(); ++i) {
187    if (reports[i]->type == type) {
188      n--;
189      if (n == 0)
190        return reports[i];
191    }
192  }
193  return NULL;
194}
195
196const StatsReport* FindReportById(const StatsReports& reports,
197                                  const std::string& id) {
198  for (size_t i = 0; i < reports.size(); ++i) {
199    if (reports[i]->id == id) {
200      return reports[i];
201    }
202  }
203  return NULL;
204}
205
206std::string ExtractSsrcStatsValue(StatsReports reports,
207                                  StatsReport::StatsValueName name) {
208  return ExtractStatsValue(
209      StatsReport::kStatsReportTypeSsrc, reports, name);
210}
211
212std::string ExtractBweStatsValue(StatsReports reports,
213                                 StatsReport::StatsValueName name) {
214  return ExtractStatsValue(
215      StatsReport::kStatsReportTypeBwe, reports, name);
216}
217
218std::string DerToPem(const std::string& der) {
219  return rtc::SSLIdentity::DerToPem(
220        rtc::kPemTypeCertificate,
221        reinterpret_cast<const unsigned char*>(der.c_str()),
222        der.length());
223}
224
225std::vector<std::string> DersToPems(
226    const std::vector<std::string>& ders) {
227  std::vector<std::string> pems(ders.size());
228  std::transform(ders.begin(), ders.end(), pems.begin(), DerToPem);
229  return pems;
230}
231
232void CheckCertChainReports(const StatsReports& reports,
233                           const std::vector<std::string>& ders,
234                           const std::string& start_id) {
235  std::string certificate_id = start_id;
236  size_t i = 0;
237  while (true) {
238    const StatsReport* report = FindReportById(reports, certificate_id);
239    ASSERT_TRUE(report != NULL);
240
241    std::string der_base64;
242    EXPECT_TRUE(GetValue(
243        report, StatsReport::kStatsValueNameDer, &der_base64));
244    std::string der = rtc::Base64::Decode(der_base64,
245                                                rtc::Base64::DO_STRICT);
246    EXPECT_EQ(ders[i], der);
247
248    std::string fingerprint_algorithm;
249    EXPECT_TRUE(GetValue(
250        report,
251        StatsReport::kStatsValueNameFingerprintAlgorithm,
252        &fingerprint_algorithm));
253    // The digest algorithm for a FakeSSLCertificate is always SHA-1.
254    std::string sha_1_str = rtc::DIGEST_SHA_1;
255    EXPECT_EQ(sha_1_str, fingerprint_algorithm);
256
257    std::string dummy_fingerprint;  // Value is not checked.
258    EXPECT_TRUE(GetValue(
259        report,
260        StatsReport::kStatsValueNameFingerprint,
261        &dummy_fingerprint));
262
263    ++i;
264    if (!GetValue(
265        report, StatsReport::kStatsValueNameIssuerId, &certificate_id))
266      break;
267  }
268  EXPECT_EQ(ders.size(), i);
269}
270
271void VerifyVoiceReceiverInfoReport(
272    const StatsReport* report,
273    const cricket::VoiceReceiverInfo& info) {
274  std::string value_in_report;
275  EXPECT_TRUE(GetValue(
276      report, StatsReport::kStatsValueNameAudioOutputLevel, &value_in_report));
277  EXPECT_EQ(rtc::ToString<int>(info.audio_level), value_in_report);
278  EXPECT_TRUE(GetValue(
279      report, StatsReport::kStatsValueNameBytesReceived, &value_in_report));
280  EXPECT_EQ(rtc::ToString<int64>(info.bytes_rcvd), value_in_report);
281  EXPECT_TRUE(GetValue(
282      report, StatsReport::kStatsValueNameJitterReceived, &value_in_report));
283  EXPECT_EQ(rtc::ToString<int>(info.jitter_ms), value_in_report);
284  EXPECT_TRUE(GetValue(
285      report, StatsReport::kStatsValueNameJitterBufferMs, &value_in_report));
286  EXPECT_EQ(rtc::ToString<int>(info.jitter_buffer_ms), value_in_report);
287  EXPECT_TRUE(GetValue(
288      report, StatsReport::kStatsValueNamePreferredJitterBufferMs,
289      &value_in_report));
290  EXPECT_EQ(rtc::ToString<int>(info.jitter_buffer_preferred_ms),
291      value_in_report);
292  EXPECT_TRUE(GetValue(
293      report, StatsReport::kStatsValueNameCurrentDelayMs, &value_in_report));
294  EXPECT_EQ(rtc::ToString<int>(info.delay_estimate_ms), value_in_report);
295  EXPECT_TRUE(GetValue(
296      report, StatsReport::kStatsValueNameExpandRate, &value_in_report));
297  EXPECT_EQ(rtc::ToString<float>(info.expand_rate), value_in_report);
298  EXPECT_TRUE(GetValue(
299      report, StatsReport::kStatsValueNamePacketsReceived, &value_in_report));
300  EXPECT_EQ(rtc::ToString<int>(info.packets_rcvd), value_in_report);
301  EXPECT_TRUE(GetValue(
302      report, StatsReport::kStatsValueNameDecodingCTSG, &value_in_report));
303  EXPECT_EQ(rtc::ToString<int>(info.decoding_calls_to_silence_generator),
304      value_in_report);
305  EXPECT_TRUE(GetValue(
306      report, StatsReport::kStatsValueNameDecodingCTN, &value_in_report));
307  EXPECT_EQ(rtc::ToString<int>(info.decoding_calls_to_neteq),
308      value_in_report);
309  EXPECT_TRUE(GetValue(
310      report, StatsReport::kStatsValueNameDecodingNormal, &value_in_report));
311  EXPECT_EQ(rtc::ToString<int>(info.decoding_normal), value_in_report);
312  EXPECT_TRUE(GetValue(
313      report, StatsReport::kStatsValueNameDecodingPLC, &value_in_report));
314  EXPECT_EQ(rtc::ToString<int>(info.decoding_plc), value_in_report);
315  EXPECT_TRUE(GetValue(
316      report, StatsReport::kStatsValueNameDecodingCNG, &value_in_report));
317  EXPECT_EQ(rtc::ToString<int>(info.decoding_cng), value_in_report);
318  EXPECT_TRUE(GetValue(
319      report, StatsReport::kStatsValueNameDecodingPLCCNG, &value_in_report));
320  EXPECT_EQ(rtc::ToString<int>(info.decoding_plc_cng), value_in_report);
321  EXPECT_TRUE(GetValue(
322      report, StatsReport::kStatsValueNameCodecName, &value_in_report));
323}
324
325
326void VerifyVoiceSenderInfoReport(const StatsReport* report,
327                                 const cricket::VoiceSenderInfo& sinfo) {
328  std::string value_in_report;
329  EXPECT_TRUE(GetValue(
330      report, StatsReport::kStatsValueNameCodecName, &value_in_report));
331  EXPECT_EQ(sinfo.codec_name, value_in_report);
332  EXPECT_TRUE(GetValue(
333      report, StatsReport::kStatsValueNameBytesSent, &value_in_report));
334  EXPECT_EQ(rtc::ToString<int64>(sinfo.bytes_sent), value_in_report);
335  EXPECT_TRUE(GetValue(
336      report, StatsReport::kStatsValueNamePacketsSent, &value_in_report));
337  EXPECT_EQ(rtc::ToString<int>(sinfo.packets_sent), value_in_report);
338  EXPECT_TRUE(GetValue(
339      report, StatsReport::kStatsValueNamePacketsLost, &value_in_report));
340  EXPECT_EQ(rtc::ToString<int>(sinfo.packets_lost), value_in_report);
341  EXPECT_TRUE(GetValue(
342      report, StatsReport::kStatsValueNameRtt, &value_in_report));
343  EXPECT_EQ(rtc::ToString<int>(sinfo.rtt_ms), value_in_report);
344  EXPECT_TRUE(GetValue(
345      report, StatsReport::kStatsValueNameRtt, &value_in_report));
346  EXPECT_EQ(rtc::ToString<int>(sinfo.rtt_ms), value_in_report);
347  EXPECT_TRUE(GetValue(
348      report, StatsReport::kStatsValueNameJitterReceived, &value_in_report));
349  EXPECT_EQ(rtc::ToString<int>(sinfo.jitter_ms), value_in_report);
350  EXPECT_TRUE(GetValue(
351      report, StatsReport::kStatsValueNameEchoCancellationQualityMin,
352      &value_in_report));
353  EXPECT_EQ(rtc::ToString<float>(sinfo.aec_quality_min), value_in_report);
354  EXPECT_TRUE(GetValue(
355      report, StatsReport::kStatsValueNameEchoDelayMedian, &value_in_report));
356  EXPECT_EQ(rtc::ToString<int>(sinfo.echo_delay_median_ms),
357            value_in_report);
358  EXPECT_TRUE(GetValue(
359      report, StatsReport::kStatsValueNameEchoDelayStdDev, &value_in_report));
360  EXPECT_EQ(rtc::ToString<int>(sinfo.echo_delay_std_ms),
361            value_in_report);
362  EXPECT_TRUE(GetValue(
363      report, StatsReport::kStatsValueNameEchoReturnLoss, &value_in_report));
364  EXPECT_EQ(rtc::ToString<int>(sinfo.echo_return_loss),
365            value_in_report);
366  EXPECT_TRUE(GetValue(
367      report, StatsReport::kStatsValueNameEchoReturnLossEnhancement,
368      &value_in_report));
369  EXPECT_EQ(rtc::ToString<int>(sinfo.echo_return_loss_enhancement),
370            value_in_report);
371  EXPECT_TRUE(GetValue(
372      report, StatsReport::kStatsValueNameAudioInputLevel, &value_in_report));
373  EXPECT_EQ(rtc::ToString<int>(sinfo.audio_level), value_in_report);
374  EXPECT_TRUE(GetValue(
375      report, StatsReport::kStatsValueNameTypingNoiseState, &value_in_report));
376  std::string typing_detected = sinfo.typing_noise_detected ? "true" : "false";
377  EXPECT_EQ(typing_detected, value_in_report);
378}
379
380// Helper methods to avoid duplication of code.
381void InitVoiceSenderInfo(cricket::VoiceSenderInfo* voice_sender_info) {
382  voice_sender_info->add_ssrc(kSsrcOfTrack);
383  voice_sender_info->codec_name = "fake_codec";
384  voice_sender_info->bytes_sent = 100;
385  voice_sender_info->packets_sent = 101;
386  voice_sender_info->rtt_ms = 102;
387  voice_sender_info->fraction_lost = 103;
388  voice_sender_info->jitter_ms = 104;
389  voice_sender_info->packets_lost = 105;
390  voice_sender_info->ext_seqnum = 106;
391  voice_sender_info->audio_level = 107;
392  voice_sender_info->echo_return_loss = 108;
393  voice_sender_info->echo_return_loss_enhancement = 109;
394  voice_sender_info->echo_delay_median_ms = 110;
395  voice_sender_info->echo_delay_std_ms = 111;
396  voice_sender_info->aec_quality_min = 112.0f;
397  voice_sender_info->typing_noise_detected = false;
398}
399
400void UpdateVoiceSenderInfoFromAudioTrack(
401    FakeAudioTrack* audio_track, cricket::VoiceSenderInfo* voice_sender_info) {
402  audio_track->GetSignalLevel(&voice_sender_info->audio_level);
403  webrtc::AudioProcessorInterface::AudioProcessorStats audio_processor_stats;
404  audio_track->GetAudioProcessor()->GetStats(&audio_processor_stats);
405  voice_sender_info->typing_noise_detected =
406      audio_processor_stats.typing_noise_detected;
407  voice_sender_info->echo_return_loss = audio_processor_stats.echo_return_loss;
408  voice_sender_info->echo_return_loss_enhancement =
409      audio_processor_stats.echo_return_loss_enhancement;
410  voice_sender_info->echo_delay_median_ms =
411      audio_processor_stats.echo_delay_median_ms;
412  voice_sender_info->aec_quality_min = audio_processor_stats.aec_quality_min;
413  voice_sender_info->echo_delay_std_ms =
414      audio_processor_stats.echo_delay_std_ms;
415}
416
417void InitVoiceReceiverInfo(cricket::VoiceReceiverInfo* voice_receiver_info) {
418  voice_receiver_info->add_ssrc(kSsrcOfTrack);
419  voice_receiver_info->bytes_rcvd = 110;
420  voice_receiver_info->packets_rcvd = 111;
421  voice_receiver_info->packets_lost = 112;
422  voice_receiver_info->fraction_lost = 113;
423  voice_receiver_info->packets_lost = 114;
424  voice_receiver_info->ext_seqnum = 115;
425  voice_receiver_info->jitter_ms = 116;
426  voice_receiver_info->jitter_buffer_ms = 117;
427  voice_receiver_info->jitter_buffer_preferred_ms = 118;
428  voice_receiver_info->delay_estimate_ms = 119;
429  voice_receiver_info->audio_level = 120;
430  voice_receiver_info->expand_rate = 121;
431}
432
433class StatsCollectorTest : public testing::Test {
434 protected:
435  StatsCollectorTest()
436    : media_engine_(new cricket::FakeMediaEngine()),
437      channel_manager_(
438          new cricket::ChannelManager(media_engine_,
439                                      new cricket::FakeDeviceManager(),
440                                      rtc::Thread::Current())),
441      session_(channel_manager_.get()) {
442    // By default, we ignore session GetStats calls.
443    EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
444  }
445
446  ~StatsCollectorTest() {}
447
448  // This creates a standard setup with a transport called "trspname"
449  // having one transport channel
450  // and the specified virtual connection name.
451  void InitSessionStats(const std::string& vc_name) {
452    const std::string kTransportName("trspname");
453    cricket::TransportStats transport_stats;
454    cricket::TransportChannelStats channel_stats;
455    channel_stats.component = 1;
456    transport_stats.content_name = kTransportName;
457    transport_stats.channel_stats.push_back(channel_stats);
458
459    session_stats_.transport_stats[kTransportName] = transport_stats;
460    session_stats_.proxy_to_transport[vc_name] = kTransportName;
461  }
462
463  // Adds a outgoing video track with a given SSRC into the stats.
464  void AddOutgoingVideoTrackStats() {
465    stream_ = webrtc::MediaStream::Create("streamlabel");
466    track_= webrtc::VideoTrack::Create(kLocalTrackId, NULL);
467    stream_->AddTrack(track_);
468    EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
469        .WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true)));
470  }
471
472  // Adds a incoming video track with a given SSRC into the stats.
473  void AddIncomingVideoTrackStats() {
474    stream_ = webrtc::MediaStream::Create("streamlabel");
475    track_= webrtc::VideoTrack::Create(kRemoteTrackId, NULL);
476    stream_->AddTrack(track_);
477    EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
478        .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
479    }
480
481  // Adds a outgoing audio track with a given SSRC into the stats.
482  void AddOutgoingAudioTrackStats() {
483    if (stream_ == NULL)
484      stream_ = webrtc::MediaStream::Create("streamlabel");
485
486    audio_track_ = new rtc::RefCountedObject<FakeAudioTrack>(
487        kLocalTrackId);
488    stream_->AddTrack(audio_track_);
489    EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
490        .WillOnce(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true)));
491  }
492
493  // Adds a incoming audio track with a given SSRC into the stats.
494  void AddIncomingAudioTrackStats() {
495    if (stream_ == NULL)
496      stream_ = webrtc::MediaStream::Create("streamlabel");
497
498    audio_track_ = new rtc::RefCountedObject<FakeAudioTrack>(
499        kRemoteTrackId);
500    stream_->AddTrack(audio_track_);
501    EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
502        .WillOnce(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
503  }
504
505  void SetupAndVerifyAudioTrackStats(
506      FakeAudioTrack* audio_track,
507      webrtc::MediaStream* stream,
508      webrtc::StatsCollector* stats,
509      cricket::VoiceChannel* voice_channel,
510      const std::string& vc_name,
511      MockVoiceMediaChannel* media_channel,
512      cricket::VoiceSenderInfo* voice_sender_info,
513      cricket::VoiceReceiverInfo* voice_receiver_info,
514      cricket::VoiceMediaInfo* stats_read,
515      StatsReports* reports) {
516    // A track can't have both sender report and recv report at the same time
517    // for now, this might change in the future though.
518    ASSERT((voice_sender_info == NULL) ^ (voice_receiver_info == NULL));
519
520    // Instruct the session to return stats containing the transport channel.
521    InitSessionStats(vc_name);
522    EXPECT_CALL(session_, GetStats(_))
523        .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
524                              Return(true)));
525
526    // Constructs an ssrc stats update.
527    if (voice_sender_info)
528      stats_read->senders.push_back(*voice_sender_info);
529    if (voice_receiver_info)
530      stats_read->receivers.push_back(*voice_receiver_info);
531
532    EXPECT_CALL(session_, voice_channel()).WillRepeatedly(
533        Return(voice_channel));
534    EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
535    EXPECT_CALL(*media_channel, GetStats(_))
536        .WillOnce(DoAll(SetArgPointee<0>(*stats_read), Return(true)));
537
538    stats->UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
539    stats->ClearUpdateStatsCache();
540    stats->GetStats(NULL, reports);
541
542    // Verify the existence of the track report.
543    const StatsReport* report = FindNthReportByType(
544        *reports, StatsReport::kStatsReportTypeSsrc, 1);
545    EXPECT_FALSE(report == NULL);
546    std::string track_id = ExtractSsrcStatsValue(
547        *reports, StatsReport::kStatsValueNameTrackId);
548    EXPECT_EQ(audio_track->id(), track_id);
549    std::string ssrc_id = ExtractSsrcStatsValue(
550        *reports, StatsReport::kStatsValueNameSsrc);
551    EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id);
552
553    // Verifies the values in the track report.
554    if (voice_sender_info) {
555      UpdateVoiceSenderInfoFromAudioTrack(audio_track, voice_sender_info);
556      VerifyVoiceSenderInfoReport(report, *voice_sender_info);
557    }
558    if (voice_receiver_info) {
559      VerifyVoiceReceiverInfoReport(report, *voice_receiver_info);
560    }
561
562    // Verify we get the same result by passing a track to GetStats().
563    StatsReports track_reports;  // returned values.
564    stats->GetStats(audio_track, &track_reports);
565    const StatsReport* track_report = FindNthReportByType(
566        track_reports, StatsReport::kStatsReportTypeSsrc, 1);
567    EXPECT_TRUE(track_report);
568    track_id = ExtractSsrcStatsValue(track_reports,
569                                     StatsReport::kStatsValueNameTrackId);
570    EXPECT_EQ(audio_track->id(), track_id);
571    ssrc_id = ExtractSsrcStatsValue(track_reports,
572                                    StatsReport::kStatsValueNameSsrc);
573    EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id);
574    if (voice_sender_info)
575      VerifyVoiceSenderInfoReport(track_report, *voice_sender_info);
576    if (voice_receiver_info)
577    VerifyVoiceReceiverInfoReport(track_report, *voice_receiver_info);
578  }
579
580  void TestCertificateReports(const rtc::FakeSSLCertificate& local_cert,
581                              const std::vector<std::string>& local_ders,
582                              const rtc::FakeSSLCertificate& remote_cert,
583                              const std::vector<std::string>& remote_ders) {
584    webrtc::StatsCollector stats(&session_);  // Implementation under test.
585    StatsReports reports;  // returned values.
586
587    // Fake stats to process.
588    cricket::TransportChannelStats channel_stats;
589    channel_stats.component = 1;
590
591    cricket::TransportStats transport_stats;
592    transport_stats.content_name = "audio";
593    transport_stats.channel_stats.push_back(channel_stats);
594
595    cricket::SessionStats session_stats;
596    session_stats.transport_stats[transport_stats.content_name] =
597        transport_stats;
598
599    // Fake certificates to report.
600    rtc::FakeSSLIdentity local_identity(local_cert);
601    rtc::scoped_ptr<rtc::FakeSSLCertificate> remote_cert_copy(
602        remote_cert.GetReference());
603
604    // Fake transport object.
605    rtc::scoped_ptr<cricket::FakeTransport> transport(
606        new cricket::FakeTransport(
607            session_.signaling_thread(),
608            session_.worker_thread(),
609            transport_stats.content_name));
610    transport->SetIdentity(&local_identity);
611    cricket::FakeTransportChannel* channel =
612        static_cast<cricket::FakeTransportChannel*>(
613            transport->CreateChannel(channel_stats.component));
614    EXPECT_FALSE(channel == NULL);
615    channel->SetRemoteCertificate(remote_cert_copy.get());
616
617    // Configure MockWebRtcSession
618    EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
619      .WillRepeatedly(Return(transport.get()));
620    EXPECT_CALL(session_, GetStats(_))
621      .WillOnce(DoAll(SetArgPointee<0>(session_stats),
622                      Return(true)));
623    EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
624    EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
625
626    stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
627
628    stats.GetStats(NULL, &reports);
629
630    const StatsReport* channel_report = FindNthReportByType(
631        reports, StatsReport::kStatsReportTypeComponent, 1);
632    EXPECT_TRUE(channel_report != NULL);
633
634    // Check local certificate chain.
635    std::string local_certificate_id = ExtractStatsValue(
636        StatsReport::kStatsReportTypeComponent,
637        reports,
638        StatsReport::kStatsValueNameLocalCertificateId);
639    if (local_ders.size() > 0) {
640      EXPECT_NE(kNotFound, local_certificate_id);
641      CheckCertChainReports(reports, local_ders, local_certificate_id);
642    } else {
643      EXPECT_EQ(kNotFound, local_certificate_id);
644    }
645
646    // Check remote certificate chain.
647    std::string remote_certificate_id = ExtractStatsValue(
648        StatsReport::kStatsReportTypeComponent,
649        reports,
650        StatsReport::kStatsValueNameRemoteCertificateId);
651    if (remote_ders.size() > 0) {
652      EXPECT_NE(kNotFound, remote_certificate_id);
653      CheckCertChainReports(reports, remote_ders, remote_certificate_id);
654    } else {
655      EXPECT_EQ(kNotFound, remote_certificate_id);
656    }
657  }
658
659  cricket::FakeMediaEngine* media_engine_;
660  rtc::scoped_ptr<cricket::ChannelManager> channel_manager_;
661  MockWebRtcSession session_;
662  cricket::SessionStats session_stats_;
663  rtc::scoped_refptr<webrtc::MediaStream> stream_;
664  rtc::scoped_refptr<webrtc::VideoTrack> track_;
665  rtc::scoped_refptr<FakeAudioTrack> audio_track_;
666};
667
668// This test verifies that 64-bit counters are passed successfully.
669TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
670  webrtc::StatsCollector stats(&session_);  // Implementation under test.
671  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
672  cricket::VideoChannel video_channel(rtc::Thread::Current(),
673      media_engine_, media_channel, &session_, "", false, NULL);
674  StatsReports reports;  // returned values.
675  cricket::VideoSenderInfo video_sender_info;
676  cricket::VideoMediaInfo stats_read;
677  // The number of bytes must be larger than 0xFFFFFFFF for this test.
678  const int64 kBytesSent = 12345678901234LL;
679  const std::string kBytesSentString("12345678901234");
680
681  AddOutgoingVideoTrackStats();
682  stats.AddStream(stream_);
683
684  // Construct a stats value to read.
685  video_sender_info.add_ssrc(1234);
686  video_sender_info.bytes_sent = kBytesSent;
687  stats_read.senders.push_back(video_sender_info);
688
689  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
690  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
691  EXPECT_CALL(*media_channel, GetStats(_, _))
692      .WillOnce(DoAll(SetArgPointee<1>(stats_read),
693                      Return(true)));
694  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
695  stats.GetStats(NULL, &reports);
696  std::string result = ExtractSsrcStatsValue(reports,
697      StatsReport::kStatsValueNameBytesSent);
698  EXPECT_EQ(kBytesSentString, result);
699}
700
701// Test that BWE information is reported via stats.
702TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
703  webrtc::StatsCollector stats(&session_);  // Implementation under test.
704  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
705  cricket::VideoChannel video_channel(rtc::Thread::Current(),
706      media_engine_, media_channel, &session_, "", false, NULL);
707  StatsReports reports;  // returned values.
708  cricket::VideoSenderInfo video_sender_info;
709  cricket::VideoMediaInfo stats_read;
710  // Set up an SSRC just to test that we get both kinds of stats back: SSRC and
711  // BWE.
712  const int64 kBytesSent = 12345678901234LL;
713  const std::string kBytesSentString("12345678901234");
714
715  AddOutgoingVideoTrackStats();
716  stats.AddStream(stream_);
717
718  // Construct a stats value to read.
719  video_sender_info.add_ssrc(1234);
720  video_sender_info.bytes_sent = kBytesSent;
721  stats_read.senders.push_back(video_sender_info);
722  cricket::BandwidthEstimationInfo bwe;
723  const int kTargetEncBitrate = 123456;
724  const std::string kTargetEncBitrateString("123456");
725  bwe.target_enc_bitrate = kTargetEncBitrate;
726  stats_read.bw_estimations.push_back(bwe);
727
728  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
729  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
730  EXPECT_CALL(*media_channel, GetStats(_, _))
731    .WillOnce(DoAll(SetArgPointee<1>(stats_read),
732                    Return(true)));
733
734  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
735  stats.GetStats(NULL, &reports);
736  std::string result = ExtractSsrcStatsValue(reports,
737      StatsReport::kStatsValueNameBytesSent);
738  EXPECT_EQ(kBytesSentString, result);
739  result = ExtractBweStatsValue(reports,
740      StatsReport::kStatsValueNameTargetEncBitrate);
741  EXPECT_EQ(kTargetEncBitrateString, result);
742}
743
744// This test verifies that an object of type "googSession" always
745// exists in the returned stats.
746TEST_F(StatsCollectorTest, SessionObjectExists) {
747  webrtc::StatsCollector stats(&session_);  // Implementation under test.
748  StatsReports reports;  // returned values.
749  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
750  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
751  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
752  stats.GetStats(NULL, &reports);
753  const StatsReport* session_report = FindNthReportByType(
754      reports, StatsReport::kStatsReportTypeSession, 1);
755  EXPECT_FALSE(session_report == NULL);
756}
757
758// This test verifies that only one object of type "googSession" exists
759// in the returned stats.
760TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
761  webrtc::StatsCollector stats(&session_);  // Implementation under test.
762  StatsReports reports;  // returned values.
763  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
764  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
765  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
766  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
767  stats.GetStats(NULL, &reports);
768  const StatsReport* session_report = FindNthReportByType(
769      reports, StatsReport::kStatsReportTypeSession, 1);
770  EXPECT_FALSE(session_report == NULL);
771  session_report = FindNthReportByType(
772      reports, StatsReport::kStatsReportTypeSession, 2);
773  EXPECT_EQ(NULL, session_report);
774}
775
776// This test verifies that the empty track report exists in the returned stats
777// without calling StatsCollector::UpdateStats.
778TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) {
779  webrtc::StatsCollector stats(&session_);  // Implementation under test.
780  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
781  cricket::VideoChannel video_channel(rtc::Thread::Current(),
782      media_engine_, media_channel, &session_, "", false, NULL);
783  AddOutgoingVideoTrackStats();
784  stats.AddStream(stream_);
785
786  // Verfies the existence of the track report.
787  StatsReports reports;
788  stats.GetStats(NULL, &reports);
789  EXPECT_EQ((size_t)1, reports.size());
790  EXPECT_EQ(std::string(StatsReport::kStatsReportTypeTrack),
791            reports[0]->type);
792
793  std::string trackValue =
794      ExtractStatsValue(StatsReport::kStatsReportTypeTrack,
795                        reports,
796                        StatsReport::kStatsValueNameTrackId);
797  EXPECT_EQ(kLocalTrackId, trackValue);
798}
799
800// This test verifies that the empty track report exists in the returned stats
801// when StatsCollector::UpdateStats is called with ssrc stats.
802TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
803  webrtc::StatsCollector stats(&session_);  // Implementation under test.
804  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
805  cricket::VideoChannel video_channel(rtc::Thread::Current(),
806      media_engine_, media_channel, &session_, "", false, NULL);
807  AddOutgoingVideoTrackStats();
808  stats.AddStream(stream_);
809
810  // Constructs an ssrc stats update.
811  cricket::VideoSenderInfo video_sender_info;
812  cricket::VideoMediaInfo stats_read;
813  const int64 kBytesSent = 12345678901234LL;
814
815  // Construct a stats value to read.
816  video_sender_info.add_ssrc(1234);
817  video_sender_info.bytes_sent = kBytesSent;
818  stats_read.senders.push_back(video_sender_info);
819
820  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
821  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
822  EXPECT_CALL(*media_channel, GetStats(_, _))
823    .WillOnce(DoAll(SetArgPointee<1>(stats_read),
824                    Return(true)));
825
826  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
827  StatsReports reports;
828  stats.GetStats(NULL, &reports);
829  // |reports| should contain at least one session report, one track report,
830  // and one ssrc report.
831  EXPECT_LE((size_t)3, reports.size());
832  const StatsReport* track_report = FindNthReportByType(
833      reports, StatsReport::kStatsReportTypeTrack, 1);
834  EXPECT_TRUE(track_report);
835
836  // Get report for the specific |track|.
837  reports.clear();
838  stats.GetStats(track_, &reports);
839  // |reports| should contain at least one session report, one track report,
840  // and one ssrc report.
841  EXPECT_LE((size_t)3, reports.size());
842  track_report = FindNthReportByType(
843      reports, StatsReport::kStatsReportTypeTrack, 1);
844  EXPECT_TRUE(track_report);
845
846  std::string ssrc_id = ExtractSsrcStatsValue(
847      reports, StatsReport::kStatsValueNameSsrc);
848  EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id);
849
850  std::string track_id = ExtractSsrcStatsValue(
851      reports, StatsReport::kStatsValueNameTrackId);
852  EXPECT_EQ(kLocalTrackId, track_id);
853}
854
855// This test verifies that an SSRC object has the identifier of a Transport
856// stats object, and that this transport stats object exists in stats.
857TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
858  webrtc::StatsCollector stats(&session_);  // Implementation under test.
859  // Ignore unused callback (logspam).
860  EXPECT_CALL(session_, GetTransport(_))
861      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
862  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
863  // The content_name known by the video channel.
864  const std::string kVcName("vcname");
865  cricket::VideoChannel video_channel(rtc::Thread::Current(),
866      media_engine_, media_channel, &session_, kVcName, false, NULL);
867  AddOutgoingVideoTrackStats();
868  stats.AddStream(stream_);
869
870  // Constructs an ssrc stats update.
871  cricket::VideoSenderInfo video_sender_info;
872  cricket::VideoMediaInfo stats_read;
873  const int64 kBytesSent = 12345678901234LL;
874
875  // Construct a stats value to read.
876  video_sender_info.add_ssrc(1234);
877  video_sender_info.bytes_sent = kBytesSent;
878  stats_read.senders.push_back(video_sender_info);
879
880  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
881  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
882  EXPECT_CALL(*media_channel, GetStats(_, _))
883    .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
884                          Return(true)));
885
886  InitSessionStats(kVcName);
887  EXPECT_CALL(session_, GetStats(_))
888      .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
889                            Return(true)));
890
891  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
892  StatsReports reports;
893  stats.GetStats(NULL, &reports);
894  std::string transport_id = ExtractStatsValue(
895      StatsReport::kStatsReportTypeSsrc,
896      reports,
897      StatsReport::kStatsValueNameTransportId);
898  ASSERT_NE(kNotFound, transport_id);
899  const StatsReport* transport_report = FindReportById(reports,
900                                                       transport_id);
901  ASSERT_FALSE(transport_report == NULL);
902}
903
904// This test verifies that a remote stats object will not be created for
905// an outgoing SSRC where remote stats are not returned.
906TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
907  webrtc::StatsCollector stats(&session_);  // Implementation under test.
908  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
909  // The content_name known by the video channel.
910  const std::string kVcName("vcname");
911  cricket::VideoChannel video_channel(rtc::Thread::Current(),
912      media_engine_, media_channel, &session_, kVcName, false, NULL);
913  AddOutgoingVideoTrackStats();
914  stats.AddStream(stream_);
915
916  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
917  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
918
919  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
920  StatsReports reports;
921  stats.GetStats(NULL, &reports);
922  const StatsReport* remote_report = FindNthReportByType(reports,
923      StatsReport::kStatsReportTypeRemoteSsrc, 1);
924  EXPECT_TRUE(remote_report == NULL);
925}
926
927// This test verifies that a remote stats object will be created for
928// an outgoing SSRC where stats are returned.
929TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
930  webrtc::StatsCollector stats(&session_);  // Implementation under test.
931  // Ignore unused callback (logspam).
932  EXPECT_CALL(session_, GetTransport(_))
933      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
934  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
935  // The content_name known by the video channel.
936  const std::string kVcName("vcname");
937  cricket::VideoChannel video_channel(rtc::Thread::Current(),
938      media_engine_, media_channel, &session_, kVcName, false, NULL);
939  AddOutgoingVideoTrackStats();
940  stats.AddStream(stream_);
941
942  // Instruct the session to return stats containing the transport channel.
943  InitSessionStats(kVcName);
944  EXPECT_CALL(session_, GetStats(_))
945      .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
946                            Return(true)));
947
948  // Constructs an ssrc stats update.
949  cricket::VideoMediaInfo stats_read;
950
951  cricket::SsrcReceiverInfo remote_ssrc_stats;
952  remote_ssrc_stats.timestamp = 12345.678;
953  remote_ssrc_stats.ssrc = kSsrcOfTrack;
954  cricket::VideoSenderInfo video_sender_info;
955  video_sender_info.add_ssrc(kSsrcOfTrack);
956  video_sender_info.remote_stats.push_back(remote_ssrc_stats);
957  stats_read.senders.push_back(video_sender_info);
958
959  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
960  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
961  EXPECT_CALL(*media_channel, GetStats(_, _))
962    .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
963                          Return(true)));
964
965  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
966  StatsReports reports;
967  stats.GetStats(NULL, &reports);
968
969  const StatsReport* remote_report = FindNthReportByType(reports,
970      StatsReport::kStatsReportTypeRemoteSsrc, 1);
971  EXPECT_FALSE(remote_report == NULL);
972  EXPECT_NE(0, remote_report->timestamp);
973}
974
975// This test verifies that the empty track report exists in the returned stats
976// when StatsCollector::UpdateStats is called with ssrc stats.
977TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) {
978  webrtc::StatsCollector stats(&session_);  // Implementation under test.
979  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
980  cricket::VideoChannel video_channel(rtc::Thread::Current(),
981      media_engine_, media_channel, &session_, "", false, NULL);
982  AddIncomingVideoTrackStats();
983  stats.AddStream(stream_);
984
985  // Constructs an ssrc stats update.
986  cricket::VideoReceiverInfo video_receiver_info;
987  cricket::VideoMediaInfo stats_read;
988  const int64 kNumOfPacketsConcealed = 54321;
989
990  // Construct a stats value to read.
991  video_receiver_info.add_ssrc(1234);
992  video_receiver_info.packets_concealed = kNumOfPacketsConcealed;
993  stats_read.receivers.push_back(video_receiver_info);
994
995  EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
996  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
997  EXPECT_CALL(*media_channel, GetStats(_, _))
998      .WillOnce(DoAll(SetArgPointee<1>(stats_read),
999                      Return(true)));
1000
1001  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1002  StatsReports reports;
1003  stats.GetStats(NULL, &reports);
1004  // |reports| should contain at least one session report, one track report,
1005  // and one ssrc report.
1006  EXPECT_LE(static_cast<size_t>(3), reports.size());
1007  const StatsReport* track_report = FindNthReportByType(
1008      reports, StatsReport::kStatsReportTypeTrack, 1);
1009  EXPECT_TRUE(track_report);
1010
1011  std::string ssrc_id = ExtractSsrcStatsValue(
1012      reports, StatsReport::kStatsValueNameSsrc);
1013  EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id);
1014
1015  std::string track_id = ExtractSsrcStatsValue(
1016      reports, StatsReport::kStatsValueNameTrackId);
1017  EXPECT_EQ(kRemoteTrackId, track_id);
1018}
1019
1020// This test verifies that all chained certificates are correctly
1021// reported
1022TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) {
1023  // Build local certificate chain.
1024  std::vector<std::string> local_ders(5);
1025  local_ders[0] = "These";
1026  local_ders[1] = "are";
1027  local_ders[2] = "some";
1028  local_ders[3] = "der";
1029  local_ders[4] = "values";
1030  rtc::FakeSSLCertificate local_cert(DersToPems(local_ders));
1031
1032  // Build remote certificate chain
1033  std::vector<std::string> remote_ders(4);
1034  remote_ders[0] = "A";
1035  remote_ders[1] = "non-";
1036  remote_ders[2] = "intersecting";
1037  remote_ders[3] = "set";
1038  rtc::FakeSSLCertificate remote_cert(DersToPems(remote_ders));
1039
1040  TestCertificateReports(local_cert, local_ders, remote_cert, remote_ders);
1041}
1042
1043// This test verifies that all certificates without chains are correctly
1044// reported.
1045TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) {
1046  // Build local certificate.
1047  std::string local_der = "This is the local der.";
1048  rtc::FakeSSLCertificate local_cert(DerToPem(local_der));
1049
1050  // Build remote certificate.
1051  std::string remote_der = "This is somebody else's der.";
1052  rtc::FakeSSLCertificate remote_cert(DerToPem(remote_der));
1053
1054  TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
1055                         remote_cert, std::vector<std::string>(1, remote_der));
1056}
1057
1058// This test verifies that the stats are generated correctly when no
1059// transport is present.
1060TEST_F(StatsCollectorTest, NoTransport) {
1061  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1062  StatsReports reports;  // returned values.
1063
1064  // Fake stats to process.
1065  cricket::TransportChannelStats channel_stats;
1066  channel_stats.component = 1;
1067
1068  cricket::TransportStats transport_stats;
1069  transport_stats.content_name = "audio";
1070  transport_stats.channel_stats.push_back(channel_stats);
1071
1072  cricket::SessionStats session_stats;
1073  session_stats.transport_stats[transport_stats.content_name] =
1074      transport_stats;
1075
1076  // Configure MockWebRtcSession
1077  EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
1078    .WillRepeatedly(ReturnNull());
1079  EXPECT_CALL(session_, GetStats(_))
1080    .WillOnce(DoAll(SetArgPointee<0>(session_stats),
1081                    Return(true)));
1082
1083  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
1084  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
1085
1086  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1087  stats.GetStats(NULL, &reports);
1088
1089  // Check that the local certificate is absent.
1090  std::string local_certificate_id = ExtractStatsValue(
1091      StatsReport::kStatsReportTypeComponent,
1092      reports,
1093      StatsReport::kStatsValueNameLocalCertificateId);
1094  ASSERT_EQ(kNotFound, local_certificate_id);
1095
1096  // Check that the remote certificate is absent.
1097  std::string remote_certificate_id = ExtractStatsValue(
1098      StatsReport::kStatsReportTypeComponent,
1099      reports,
1100      StatsReport::kStatsValueNameRemoteCertificateId);
1101  ASSERT_EQ(kNotFound, remote_certificate_id);
1102}
1103
1104// This test verifies that the stats are generated correctly when the transport
1105// does not have any certificates.
1106TEST_F(StatsCollectorTest, NoCertificates) {
1107  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1108  StatsReports reports;  // returned values.
1109
1110  // Fake stats to process.
1111  cricket::TransportChannelStats channel_stats;
1112  channel_stats.component = 1;
1113
1114  cricket::TransportStats transport_stats;
1115  transport_stats.content_name = "audio";
1116  transport_stats.channel_stats.push_back(channel_stats);
1117
1118  cricket::SessionStats session_stats;
1119  session_stats.transport_stats[transport_stats.content_name] =
1120      transport_stats;
1121
1122  // Fake transport object.
1123  rtc::scoped_ptr<cricket::FakeTransport> transport(
1124      new cricket::FakeTransport(
1125          session_.signaling_thread(),
1126          session_.worker_thread(),
1127          transport_stats.content_name));
1128
1129  // Configure MockWebRtcSession
1130  EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
1131    .WillRepeatedly(Return(transport.get()));
1132  EXPECT_CALL(session_, GetStats(_))
1133    .WillOnce(DoAll(SetArgPointee<0>(session_stats),
1134                    Return(true)));
1135  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
1136  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
1137
1138  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1139  stats.GetStats(NULL, &reports);
1140
1141  // Check that the local certificate is absent.
1142  std::string local_certificate_id = ExtractStatsValue(
1143      StatsReport::kStatsReportTypeComponent,
1144      reports,
1145      StatsReport::kStatsValueNameLocalCertificateId);
1146  ASSERT_EQ(kNotFound, local_certificate_id);
1147
1148  // Check that the remote certificate is absent.
1149  std::string remote_certificate_id = ExtractStatsValue(
1150      StatsReport::kStatsReportTypeComponent,
1151      reports,
1152      StatsReport::kStatsValueNameRemoteCertificateId);
1153  ASSERT_EQ(kNotFound, remote_certificate_id);
1154}
1155
1156// This test verifies that a remote certificate with an unsupported digest
1157// algorithm is correctly ignored.
1158TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) {
1159  // Build a local certificate.
1160  std::string local_der = "This is the local der.";
1161  rtc::FakeSSLCertificate local_cert(DerToPem(local_der));
1162
1163  // Build a remote certificate with an unsupported digest algorithm.
1164  std::string remote_der = "This is somebody else's der.";
1165  rtc::FakeSSLCertificate remote_cert(DerToPem(remote_der));
1166  remote_cert.set_digest_algorithm("foobar");
1167
1168  TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
1169                         remote_cert, std::vector<std::string>());
1170}
1171
1172// Verifies the correct optons are passed to the VideoMediaChannel when using
1173// verbose output level.
1174TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
1175  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1176  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
1177  cricket::VideoChannel video_channel(rtc::Thread::Current(),
1178      media_engine_, media_channel, &session_, "", false, NULL);
1179
1180  cricket::VideoMediaInfo stats_read;
1181  cricket::BandwidthEstimationInfo bwe;
1182  bwe.total_received_propagation_delta_ms = 10;
1183  bwe.recent_received_propagation_delta_ms.push_back(100);
1184  bwe.recent_received_propagation_delta_ms.push_back(200);
1185  bwe.recent_received_packet_group_arrival_time_ms.push_back(1000);
1186  bwe.recent_received_packet_group_arrival_time_ms.push_back(2000);
1187  stats_read.bw_estimations.push_back(bwe);
1188
1189  EXPECT_CALL(session_, video_channel())
1190    .WillRepeatedly(Return(&video_channel));
1191  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
1192
1193  StatsOptions options;
1194  options.include_received_propagation_stats = true;
1195  EXPECT_CALL(*media_channel, GetStats(
1196      Field(&StatsOptions::include_received_propagation_stats, true),
1197      _))
1198    .WillOnce(DoAll(SetArgPointee<1>(stats_read),
1199                    Return(true)));
1200
1201  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelDebug);
1202  StatsReports reports;  // returned values.
1203  stats.GetStats(NULL, &reports);
1204  std::string result = ExtractBweStatsValue(
1205      reports,
1206      StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug);
1207  EXPECT_EQ("10", result);
1208  result = ExtractBweStatsValue(
1209      reports,
1210      StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug);
1211  EXPECT_EQ("[100, 200]", result);
1212  result = ExtractBweStatsValue(
1213      reports, StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug);
1214  EXPECT_EQ("[1000, 2000]", result);
1215}
1216
1217// This test verifies that a local stats object can get statistics via
1218// AudioTrackInterface::GetStats() method.
1219TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) {
1220  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1221  // Ignore unused callback (logspam).
1222  EXPECT_CALL(session_, GetTransport(_))
1223      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
1224
1225  MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
1226  // The content_name known by the voice channel.
1227  const std::string kVcName("vcname");
1228  cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
1229      media_engine_, media_channel, &session_, kVcName, false);
1230  AddOutgoingAudioTrackStats();
1231  stats.AddStream(stream_);
1232  stats.AddLocalAudioTrack(audio_track_, kSsrcOfTrack);
1233
1234  cricket::VoiceSenderInfo voice_sender_info;
1235  InitVoiceSenderInfo(&voice_sender_info);
1236
1237  cricket::VoiceMediaInfo stats_read;
1238  StatsReports reports;  // returned values.
1239  SetupAndVerifyAudioTrackStats(
1240      audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName,
1241      media_channel, &voice_sender_info, NULL, &stats_read, &reports);
1242
1243  // Verify that there is no remote report for the local audio track because
1244  // we did not set it up.
1245  const StatsReport* remote_report = FindNthReportByType(reports,
1246      StatsReport::kStatsReportTypeRemoteSsrc, 1);
1247  EXPECT_TRUE(remote_report == NULL);
1248}
1249
1250// This test verifies that audio receive streams populate stats reports
1251// correctly.
1252TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) {
1253  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1254  // Ignore unused callback (logspam).
1255  EXPECT_CALL(session_, GetTransport(_))
1256      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
1257  MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
1258  // The content_name known by the voice channel.
1259  const std::string kVcName("vcname");
1260  cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
1261      media_engine_, media_channel, &session_, kVcName, false);
1262  AddIncomingAudioTrackStats();
1263  stats.AddStream(stream_);
1264
1265  cricket::VoiceReceiverInfo voice_receiver_info;
1266  InitVoiceReceiverInfo(&voice_receiver_info);
1267  voice_receiver_info.codec_name = "fake_codec";
1268
1269  cricket::VoiceMediaInfo stats_read;
1270  StatsReports reports;  // returned values.
1271  SetupAndVerifyAudioTrackStats(
1272      audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName,
1273      media_channel, NULL, &voice_receiver_info, &stats_read, &reports);
1274}
1275
1276// This test verifies that a local stats object won't update its statistics
1277// after a RemoveLocalAudioTrack() call.
1278TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) {
1279  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1280  // Ignore unused callback (logspam).
1281  EXPECT_CALL(session_, GetTransport(_))
1282      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
1283  MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
1284  // The content_name known by the voice channel.
1285  const std::string kVcName("vcname");
1286  cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
1287      media_engine_, media_channel, &session_, kVcName, false);
1288  AddOutgoingAudioTrackStats();
1289  stats.AddStream(stream_);
1290  stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
1291
1292  // Instruct the session to return stats containing the transport channel.
1293  InitSessionStats(kVcName);
1294  EXPECT_CALL(session_, GetStats(_))
1295      .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
1296                            Return(true)));
1297
1298  stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
1299  cricket::VoiceSenderInfo voice_sender_info;
1300  InitVoiceSenderInfo(&voice_sender_info);
1301
1302  // Constructs an ssrc stats update.
1303  cricket::VoiceMediaInfo stats_read;
1304  stats_read.senders.push_back(voice_sender_info);
1305
1306  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
1307  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
1308  EXPECT_CALL(*media_channel, GetStats(_))
1309      .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
1310                            Return(true)));
1311
1312  StatsReports reports;  // returned values.
1313  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1314  stats.GetStats(NULL, &reports);
1315
1316  // The report will exist since we don't remove them in RemoveStream().
1317  const StatsReport* report = FindNthReportByType(
1318      reports, StatsReport::kStatsReportTypeSsrc, 1);
1319  EXPECT_FALSE(report == NULL);
1320  std::string track_id = ExtractSsrcStatsValue(
1321      reports, StatsReport::kStatsValueNameTrackId);
1322  EXPECT_EQ(kLocalTrackId, track_id);
1323  std::string ssrc_id = ExtractSsrcStatsValue(
1324      reports, StatsReport::kStatsValueNameSsrc);
1325  EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id);
1326
1327  // Verifies the values in the track report, no value will be changed by the
1328  // AudioTrackInterface::GetSignalValue() and
1329  // AudioProcessorInterface::AudioProcessorStats::GetStats();
1330  VerifyVoiceSenderInfoReport(report, voice_sender_info);
1331}
1332
1333// This test verifies that when ongoing and incoming audio tracks are using
1334// the same ssrc, they populate stats reports correctly.
1335TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) {
1336  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1337  // Ignore unused callback (logspam).
1338  EXPECT_CALL(session_, GetTransport(_))
1339      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
1340  MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
1341  // The content_name known by the voice channel.
1342  const std::string kVcName("vcname");
1343  cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
1344      media_engine_, media_channel, &session_, kVcName, false);
1345
1346  // Create a local stream with a local audio track and adds it to the stats.
1347  AddOutgoingAudioTrackStats();
1348  stats.AddStream(stream_);
1349  stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
1350
1351  // Create a remote stream with a remote audio track and adds it to the stats.
1352  rtc::scoped_refptr<webrtc::MediaStream> remote_stream(
1353      webrtc::MediaStream::Create("remotestreamlabel"));
1354  rtc::scoped_refptr<FakeAudioTrack> remote_track(
1355      new rtc::RefCountedObject<FakeAudioTrack>(kRemoteTrackId));
1356  EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
1357      .WillOnce(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
1358  remote_stream->AddTrack(remote_track);
1359  stats.AddStream(remote_stream);
1360
1361  // Instruct the session to return stats containing the transport channel.
1362  InitSessionStats(kVcName);
1363  EXPECT_CALL(session_, GetStats(_))
1364      .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
1365                            Return(true)));
1366
1367  cricket::VoiceSenderInfo voice_sender_info;
1368  InitVoiceSenderInfo(&voice_sender_info);
1369
1370  // Some of the contents in |voice_sender_info| needs to be updated from the
1371  // |audio_track_|.
1372  UpdateVoiceSenderInfoFromAudioTrack(audio_track_.get(), &voice_sender_info);
1373
1374  cricket::VoiceReceiverInfo voice_receiver_info;
1375  InitVoiceReceiverInfo(&voice_receiver_info);
1376
1377  // Constructs an ssrc stats update.
1378  cricket::VoiceMediaInfo stats_read;
1379  stats_read.senders.push_back(voice_sender_info);
1380  stats_read.receivers.push_back(voice_receiver_info);
1381
1382  EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
1383  EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
1384  EXPECT_CALL(*media_channel, GetStats(_))
1385      .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
1386                            Return(true)));
1387
1388  StatsReports reports;  // returned values.
1389  stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1390
1391  // Get stats for the local track.
1392  stats.GetStats(audio_track_.get(), &reports);
1393  const StatsReport* track_report = FindNthReportByType(
1394      reports, StatsReport::kStatsReportTypeSsrc, 1);
1395  EXPECT_TRUE(track_report);
1396  std::string track_id = ExtractSsrcStatsValue(
1397      reports, StatsReport::kStatsValueNameTrackId);
1398  EXPECT_EQ(kLocalTrackId, track_id);
1399  VerifyVoiceSenderInfoReport(track_report, voice_sender_info);
1400
1401  // Get stats for the remote track.
1402  reports.clear();
1403  stats.GetStats(remote_track.get(), &reports);
1404  track_report = FindNthReportByType(reports,
1405                                     StatsReport::kStatsReportTypeSsrc, 1);
1406  EXPECT_TRUE(track_report);
1407  track_id = ExtractSsrcStatsValue(reports,
1408                                   StatsReport::kStatsValueNameTrackId);
1409  EXPECT_EQ(kRemoteTrackId, track_id);
1410  VerifyVoiceReceiverInfoReport(track_report, voice_receiver_info);
1411}
1412
1413// This test verifies that when two outgoing audio tracks are using the same
1414// ssrc at different times, they populate stats reports correctly.
1415// TODO(xians): Figure out if it is possible to encapsulate the setup and
1416// avoid duplication of code in test cases.
1417TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) {
1418  webrtc::StatsCollector stats(&session_);  // Implementation under test.
1419  // Ignore unused callback (logspam).
1420  EXPECT_CALL(session_, GetTransport(_))
1421      .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
1422  MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
1423  // The content_name known by the voice channel.
1424  const std::string kVcName("vcname");
1425  cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
1426      media_engine_, media_channel, &session_, kVcName, false);
1427
1428  // Create a local stream with a local audio track and adds it to the stats.
1429  AddOutgoingAudioTrackStats();
1430  stats.AddStream(stream_);
1431  stats.AddLocalAudioTrack(audio_track_, kSsrcOfTrack);
1432
1433  cricket::VoiceSenderInfo voice_sender_info;
1434  voice_sender_info.add_ssrc(kSsrcOfTrack);
1435
1436  cricket::VoiceMediaInfo stats_read;
1437  StatsReports reports;  // returned values.
1438  SetupAndVerifyAudioTrackStats(
1439      audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName,
1440      media_channel, &voice_sender_info, NULL, &stats_read, &reports);
1441
1442  // Remove the previous audio track from the stream.
1443  stream_->RemoveTrack(audio_track_.get());
1444  stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
1445
1446  // Create a new audio track and adds it to the stream and stats.
1447  static const std::string kNewTrackId = "new_track_id";
1448  rtc::scoped_refptr<FakeAudioTrack> new_audio_track(
1449      new rtc::RefCountedObject<FakeAudioTrack>(kNewTrackId));
1450  EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
1451      .WillOnce(DoAll(SetArgPointee<1>(kNewTrackId), Return(true)));
1452  stream_->AddTrack(new_audio_track);
1453
1454  stats.AddLocalAudioTrack(new_audio_track, kSsrcOfTrack);
1455  stats.ClearUpdateStatsCache();
1456  cricket::VoiceSenderInfo new_voice_sender_info;
1457  InitVoiceSenderInfo(&new_voice_sender_info);
1458  cricket::VoiceMediaInfo new_stats_read;
1459  reports.clear();
1460  SetupAndVerifyAudioTrackStats(
1461      new_audio_track.get(), stream_.get(), &stats, &voice_channel, kVcName,
1462      media_channel, &new_voice_sender_info, NULL, &new_stats_read, &reports);
1463}
1464
1465}  // namespace
1466