Update libjingle to 53920541.

R=mallinath@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2371004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4945 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index cce1645bc..9829832 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -30,6 +30,8 @@
 
 #include "talk/app/webrtc/mediastream.h"
 #include "talk/app/webrtc/videotrack.h"
+#include "talk/base/base64.h"
+#include "talk/base/fakesslidentity.h"
 #include "talk/base/gunit.h"
 #include "talk/media/base/fakemediaengine.h"
 #include "talk/media/devices/fakedevicemanager.h"
@@ -60,11 +62,12 @@
  public:
   explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
     : WebRtcSession(channel_manager, talk_base::Thread::Current(),
-                    NULL, NULL, NULL) {
+                    talk_base::Thread::Current(), NULL, NULL) {
   }
   MOCK_METHOD0(video_channel, cricket::VideoChannel*());
   MOCK_METHOD2(GetTrackIdBySsrc, bool(uint32, std::string*));
   MOCK_METHOD1(GetStats, bool(cricket::SessionStats*));
+  MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&));
 };
 
 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
@@ -76,8 +79,21 @@
   MOCK_METHOD1(GetStats, bool(cricket::VideoMediaInfo*));
 };
 
+bool GetValue(const webrtc::StatsReport* report,
+              const std::string& name,
+              std::string* value) {
+  webrtc::StatsReport::Values::const_iterator it = report->values.begin();
+  for (; it != report->values.end(); ++it) {
+    if (it->name == name) {
+      *value = it->value;
+      return true;
+    }
+  }
+  return false;
+}
+
 std::string ExtractStatsValue(const std::string& type,
-                              webrtc::StatsReports reports,
+                              const webrtc::StatsReports& reports,
                               const std::string name) {
   if (reports.empty()) {
     return kNoReports;
@@ -85,12 +101,9 @@
   for (size_t i = 0; i < reports.size(); ++i) {
     if (reports[i].type != type)
       continue;
-    webrtc::StatsReport::Values::const_iterator it =
-        reports[i].values.begin();
-    for (; it != reports[i].values.end(); ++it) {
-      if (it->name == name) {
-        return it->value;
-      }
+    std::string ret;
+    if (GetValue(&reports[i], name, &ret)) {
+      return ret;
     }
   }
 
@@ -99,9 +112,8 @@
 
 // Finds the |n|-th report of type |type| in |reports|.
 // |n| starts from 1 for finding the first report.
-const webrtc::StatsReport* FindNthReportByType(webrtc::StatsReports reports,
-                                               const std::string& type,
-                                               int n) {
+const webrtc::StatsReport* FindNthReportByType(
+    const webrtc::StatsReports& reports, const std::string& type, int n) {
   for (size_t i = 0; i < reports.size(); ++i) {
     if (reports[i].type == type) {
       n--;
@@ -112,7 +124,7 @@
   return NULL;
 }
 
-const webrtc::StatsReport* FindReportById(webrtc::StatsReports reports,
+const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
                                           const std::string& id) {
   for (size_t i = 0; i < reports.size(); ++i) {
     if (reports[i].id == id) {
@@ -134,6 +146,42 @@
       webrtc::StatsReport::kStatsReportTypeBwe, reports, name);
 }
 
+std::string DerToPem(const std::string& der) {
+  return talk_base::SSLIdentity::DerToPem(
+        talk_base::kPemTypeCertificate,
+        reinterpret_cast<const unsigned char*>(der.c_str()),
+        der.length());
+}
+
+std::vector<std::string> DersToPems(
+    const std::vector<std::string>& ders) {
+  std::vector<std::string> pems(ders.size());
+  std::transform(ders.begin(), ders.end(), pems.begin(), DerToPem);
+  return pems;
+}
+
+void CheckCertChainReports(const webrtc::StatsReports& reports,
+                           const std::vector<std::string>& ders,
+                           const std::string& start_id) {
+  std::string certificate_id = start_id;
+  size_t i = 0;
+  while (true) {
+    const webrtc::StatsReport* report = FindReportById(reports, certificate_id);
+    ASSERT_TRUE(report != NULL);
+    std::string der_base64;
+    EXPECT_TRUE(GetValue(
+        report, webrtc::StatsReport::kStatsValueNameDer, &der_base64));
+    std::string der = talk_base::Base64::Decode(der_base64,
+                                                talk_base::Base64::DO_STRICT);
+    EXPECT_EQ(ders[i], der);
+    ++i;
+    if (!GetValue(
+        report, webrtc::StatsReport::kStatsValueNameIssuerId, &certificate_id))
+      break;
+  }
+  EXPECT_EQ(ders.size(), i);
+}
+
 class StatsCollectorTest : public testing::Test {
  protected:
   StatsCollectorTest()
@@ -147,6 +195,77 @@
     EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
   }
 
+  void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
+                              const std::vector<std::string>& local_ders,
+                              const talk_base::FakeSSLCertificate& remote_cert,
+                              const std::vector<std::string>& remote_ders) {
+    webrtc::StatsCollector stats;  // Implementation under test.
+    webrtc::StatsReports reports;  // returned values.
+    stats.set_session(&session_);
+
+    // Fake stats to process.
+    cricket::TransportChannelStats channel_stats;
+    channel_stats.component = 1;
+
+    cricket::TransportStats transport_stats;
+    transport_stats.content_name = "audio";
+    transport_stats.channel_stats.push_back(channel_stats);
+
+    cricket::SessionStats session_stats;
+    session_stats.transport_stats[transport_stats.content_name] =
+        transport_stats;
+
+    // Fake certificates to report.
+    talk_base::FakeSSLIdentity local_identity(local_cert);
+    talk_base::scoped_ptr<talk_base::FakeSSLCertificate> remote_cert_copy(
+        remote_cert.GetReference());
+
+    // Fake transport object.
+    talk_base::scoped_ptr<cricket::FakeTransport> transport(
+        new cricket::FakeTransport(
+            session_.signaling_thread(),
+            session_.worker_thread(),
+            transport_stats.content_name));
+    transport->SetIdentity(&local_identity);
+    cricket::FakeTransportChannel* channel =
+        static_cast<cricket::FakeTransportChannel*>(
+            transport->CreateChannel(channel_stats.component));
+    EXPECT_FALSE(channel == NULL);
+    channel->SetRemoteCertificate(remote_cert_copy.get());
+
+    // Configure MockWebRtcSession
+    EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+      .WillOnce(Return(transport.get()));
+    EXPECT_CALL(session_, GetStats(_))
+      .WillOnce(DoAll(SetArgPointee<0>(session_stats),
+                      Return(true)));
+    EXPECT_CALL(session_, video_channel())
+      .WillRepeatedly(ReturnNull());
+
+    stats.UpdateStats();
+
+    stats.GetStats(NULL, &reports);
+
+    const webrtc::StatsReport* channel_report = FindNthReportByType(
+        reports, webrtc::StatsReport::kStatsReportTypeComponent, 1);
+    EXPECT_TRUE(channel_report != NULL);
+
+    // Check local certificate chain.
+    std::string local_certificate_id = ExtractStatsValue(
+        webrtc::StatsReport::kStatsReportTypeComponent,
+        reports,
+        webrtc::StatsReport::kStatsValueNameLocalCertificateId);
+    EXPECT_NE(kNotFound, local_certificate_id);
+    CheckCertChainReports(reports, local_ders, local_certificate_id);
+
+    // Check remote certificate chain.
+    std::string remote_certificate_id = ExtractStatsValue(
+        webrtc::StatsReport::kStatsReportTypeComponent,
+        reports,
+        webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
+    EXPECT_NE(kNotFound, remote_certificate_id);
+    CheckCertChainReports(reports, remote_ders, remote_certificate_id);
+  }
   cricket::FakeMediaEngine* media_engine_;
   talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
   MockWebRtcSession session_;
@@ -439,4 +558,142 @@
   ASSERT_FALSE(transport_report == NULL);
 }
 
+// This test verifies that all chained certificates are correctly
+// reported
+TEST_F(StatsCollectorTest, DISABLED_ChainedCertificateReportsCreated) {
+  // Build local certificate chain.
+  std::vector<std::string> local_ders(5);
+  local_ders[0] = "These";
+  local_ders[1] = "are";
+  local_ders[2] = "some";
+  local_ders[3] = "der";
+  local_ders[4] = "values";
+  talk_base::FakeSSLCertificate local_cert(DersToPems(local_ders));
+
+  // Build remote certificate chain
+  std::vector<std::string> remote_ders(4);
+  remote_ders[0] = "A";
+  remote_ders[1] = "non-";
+  remote_ders[2] = "intersecting";
+  remote_ders[3] = "set";
+  talk_base::FakeSSLCertificate remote_cert(DersToPems(remote_ders));
+
+  TestCertificateReports(local_cert, local_ders, remote_cert, remote_ders);
+}
+
+// This test verifies that all certificates without chains are correctly
+// reported.
+TEST_F(StatsCollectorTest, DISABLED_ChainlessCertificateReportsCreated) {
+  // Build local certificate.
+  std::string local_der = "This is the local der.";
+  talk_base::FakeSSLCertificate local_cert(DerToPem(local_der));
+
+  // Build remote certificate.
+  std::string remote_der = "This is somebody else's der.";
+  talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
+
+  TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
+                         remote_cert, std::vector<std::string>(1, remote_der));
+}
+
+// This test verifies that the stats are generated correctly when no
+// transport is present.
+TEST_F(StatsCollectorTest, DISABLED_NoTransport) {
+  webrtc::StatsCollector stats;  // Implementation under test.
+  webrtc::StatsReports reports;  // returned values.
+  stats.set_session(&session_);
+
+  // Fake stats to process.
+  cricket::TransportChannelStats channel_stats;
+  channel_stats.component = 1;
+
+  cricket::TransportStats transport_stats;
+  transport_stats.content_name = "audio";
+  transport_stats.channel_stats.push_back(channel_stats);
+
+  cricket::SessionStats session_stats;
+  session_stats.transport_stats[transport_stats.content_name] =
+      transport_stats;
+
+  // Configure MockWebRtcSession
+  EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+    .WillOnce(ReturnNull());
+  EXPECT_CALL(session_, GetStats(_))
+    .WillOnce(DoAll(SetArgPointee<0>(session_stats),
+                    Return(true)));
+  EXPECT_CALL(session_, video_channel())
+    .WillRepeatedly(ReturnNull());
+
+  stats.UpdateStats();
+  stats.GetStats(NULL, &reports);
+
+  // Check that the local certificate is absent.
+  std::string local_certificate_id = ExtractStatsValue(
+      webrtc::StatsReport::kStatsReportTypeComponent,
+      reports,
+      webrtc::StatsReport::kStatsValueNameLocalCertificateId);
+  ASSERT_EQ(kNotFound, local_certificate_id);
+
+  // Check that the remote certificate is absent.
+  std::string remote_certificate_id = ExtractStatsValue(
+      webrtc::StatsReport::kStatsReportTypeComponent,
+      reports,
+      webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
+  ASSERT_EQ(kNotFound, remote_certificate_id);
+}
+
+// This test verifies that the stats are generated correctly when the transport
+// does not have any certificates.
+TEST_F(StatsCollectorTest, DISABLED_NoCertificates) {
+  webrtc::StatsCollector stats;  // Implementation under test.
+  webrtc::StatsReports reports;  // returned values.
+  stats.set_session(&session_);
+
+  // Fake stats to process.
+  cricket::TransportChannelStats channel_stats;
+  channel_stats.component = 1;
+
+  cricket::TransportStats transport_stats;
+  transport_stats.content_name = "audio";
+  transport_stats.channel_stats.push_back(channel_stats);
+
+  cricket::SessionStats session_stats;
+  session_stats.transport_stats[transport_stats.content_name] =
+      transport_stats;
+
+  // Fake transport object.
+  talk_base::scoped_ptr<cricket::FakeTransport> transport(
+      new cricket::FakeTransport(
+          session_.signaling_thread(),
+          session_.worker_thread(),
+          transport_stats.content_name));
+
+  // Configure MockWebRtcSession
+  EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+    .WillOnce(Return(transport.get()));
+  EXPECT_CALL(session_, GetStats(_))
+    .WillOnce(DoAll(SetArgPointee<0>(session_stats),
+                    Return(true)));
+  EXPECT_CALL(session_, video_channel())
+    .WillRepeatedly(ReturnNull());
+
+  stats.UpdateStats();
+  stats.GetStats(NULL, &reports);
+
+  // Check that the local certificate is absent.
+  std::string local_certificate_id = ExtractStatsValue(
+      webrtc::StatsReport::kStatsReportTypeComponent,
+      reports,
+      webrtc::StatsReport::kStatsValueNameLocalCertificateId);
+  ASSERT_EQ(kNotFound, local_certificate_id);
+
+  // Check that the remote certificate is absent.
+  std::string remote_certificate_id = ExtractStatsValue(
+      webrtc::StatsReport::kStatsReportTypeComponent,
+      reports,
+      webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
+  ASSERT_EQ(kNotFound, remote_certificate_id);
+}
+
+
 }  // namespace