OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/api/rtcstatscollector.h" | 11 #include "webrtc/api/rtcstatscollector.h" |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 #include <string> | 14 #include <string> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "webrtc/api/jsepsessiondescription.h" | 17 #include "webrtc/api/jsepsessiondescription.h" |
18 #include "webrtc/api/stats/rtcstats_objects.h" | 18 #include "webrtc/api/stats/rtcstats_objects.h" |
19 #include "webrtc/api/stats/rtcstatsreport.h" | 19 #include "webrtc/api/stats/rtcstatsreport.h" |
20 #include "webrtc/api/test/mock_datachannel.h" | 20 #include "webrtc/api/test/mock_datachannel.h" |
21 #include "webrtc/api/test/mock_peerconnection.h" | 21 #include "webrtc/api/test/mock_peerconnection.h" |
22 #include "webrtc/api/test/mock_webrtcsession.h" | 22 #include "webrtc/api/test/mock_webrtcsession.h" |
23 #include "webrtc/base/checks.h" | 23 #include "webrtc/base/checks.h" |
24 #include "webrtc/base/fakeclock.h" | 24 #include "webrtc/base/fakeclock.h" |
| 25 #include "webrtc/base/fakesslidentity.h" |
25 #include "webrtc/base/gunit.h" | 26 #include "webrtc/base/gunit.h" |
26 #include "webrtc/base/logging.h" | 27 #include "webrtc/base/logging.h" |
27 #include "webrtc/base/thread_checker.h" | 28 #include "webrtc/base/thread_checker.h" |
28 #include "webrtc/base/timedelta.h" | 29 #include "webrtc/base/timedelta.h" |
29 #include "webrtc/base/timeutils.h" | 30 #include "webrtc/base/timeutils.h" |
30 #include "webrtc/media/base/fakemediaengine.h" | 31 #include "webrtc/media/base/fakemediaengine.h" |
31 | 32 |
| 33 using testing::_; |
| 34 using testing::Invoke; |
32 using testing::Return; | 35 using testing::Return; |
33 using testing::ReturnRef; | 36 using testing::ReturnRef; |
34 | 37 |
35 namespace webrtc { | 38 namespace webrtc { |
36 | 39 |
37 namespace { | 40 namespace { |
38 | 41 |
39 const int64_t kGetStatsReportTimeoutMs = 1000; | 42 const int64_t kGetStatsReportTimeoutMs = 1000; |
40 | 43 |
| 44 struct CertificateInfo { |
| 45 rtc::scoped_refptr<rtc::RTCCertificate> certificate; |
| 46 std::vector<std::string> ders; |
| 47 std::vector<std::string> pems; |
| 48 std::vector<std::string> fingerprints; |
| 49 }; |
| 50 |
| 51 std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers( |
| 52 const std::vector<std::string>& ders) { |
| 53 RTC_CHECK(!ders.empty()); |
| 54 std::unique_ptr<CertificateInfo> info(new CertificateInfo()); |
| 55 info->ders = ders; |
| 56 for (const std::string& der : ders) { |
| 57 info->pems.push_back(rtc::SSLIdentity::DerToPem( |
| 58 "CERTIFICATE", |
| 59 reinterpret_cast<const unsigned char*>(der.c_str()), |
| 60 der.length())); |
| 61 } |
| 62 info->certificate = |
| 63 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>( |
| 64 new rtc::FakeSSLIdentity(rtc::FakeSSLCertificate(info->pems)))); |
| 65 // Strip header/footer and newline characters of PEM strings. |
| 66 for (size_t i = 0; i < info->pems.size(); ++i) { |
| 67 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, |
| 68 "", 0, &info->pems[i]); |
| 69 rtc::replace_substrs("-----END CERTIFICATE-----", 25, |
| 70 "", 0, &info->pems[i]); |
| 71 rtc::replace_substrs("\n", 1, |
| 72 "", 0, &info->pems[i]); |
| 73 } |
| 74 // Fingerprint of leaf certificate. |
| 75 std::unique_ptr<rtc::SSLFingerprint> fp( |
| 76 rtc::SSLFingerprint::Create("sha-1", |
| 77 &info->certificate->ssl_certificate())); |
| 78 EXPECT_TRUE(fp); |
| 79 info->fingerprints.push_back(fp->GetRfc4572Fingerprint()); |
| 80 // Fingerprints of the rest of the chain. |
| 81 std::unique_ptr<rtc::SSLCertChain> chain = |
| 82 info->certificate->ssl_certificate().GetChain(); |
| 83 if (chain) { |
| 84 for (size_t i = 0; i < chain->GetSize(); i++) { |
| 85 fp.reset(rtc::SSLFingerprint::Create("sha-1", &chain->Get(i))); |
| 86 EXPECT_TRUE(fp); |
| 87 info->fingerprints.push_back(fp->GetRfc4572Fingerprint()); |
| 88 } |
| 89 } |
| 90 EXPECT_EQ(info->ders.size(), info->fingerprints.size()); |
| 91 return info; |
| 92 } |
| 93 |
41 class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver { | 94 class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver { |
42 public: | 95 public: |
43 RTCStatsCollectorTestHelper() | 96 RTCStatsCollectorTestHelper() |
44 : worker_thread_(rtc::Thread::Current()), | 97 : worker_thread_(rtc::Thread::Current()), |
45 network_thread_(rtc::Thread::Current()), | 98 network_thread_(rtc::Thread::Current()), |
46 channel_manager_(new cricket::ChannelManager( | 99 channel_manager_(new cricket::ChannelManager( |
47 new cricket::FakeMediaEngine(), | 100 new cricket::FakeMediaEngine(), |
48 worker_thread_, | 101 worker_thread_, |
49 network_thread_)), | 102 network_thread_)), |
50 media_controller_( | 103 media_controller_( |
51 MediaControllerInterface::Create(cricket::MediaConfig(), | 104 MediaControllerInterface::Create(cricket::MediaConfig(), |
52 worker_thread_, | 105 worker_thread_, |
53 channel_manager_.get())), | 106 channel_manager_.get())), |
54 session_(media_controller_.get()), | 107 session_(media_controller_.get()), |
55 pc_() { | 108 pc_() { |
| 109 // Default return values for mocks. |
56 EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_)); | 110 EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_)); |
57 EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly( | 111 EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly( |
58 ReturnRef(data_channels_)); | 112 ReturnRef(data_channels_)); |
| 113 EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false)); |
59 } | 114 } |
60 | 115 |
61 rtc::ScopedFakeClock& fake_clock() { return fake_clock_; } | 116 rtc::ScopedFakeClock& fake_clock() { return fake_clock_; } |
62 MockWebRtcSession& session() { return session_; } | 117 MockWebRtcSession& session() { return session_; } |
63 MockPeerConnection& pc() { return pc_; } | 118 MockPeerConnection& pc() { return pc_; } |
64 std::vector<rtc::scoped_refptr<DataChannel>>& data_channels() { | 119 std::vector<rtc::scoped_refptr<DataChannel>>& data_channels() { |
65 return data_channels_; | 120 return data_channels_; |
66 } | 121 } |
67 | 122 |
68 // SetSessionDescriptionObserver overrides. | 123 // SetSessionDescriptionObserver overrides. |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) { | 301 &test_->pc(), 50 * rtc::kNumMicrosecsPerMillisec)) { |
247 } | 302 } |
248 | 303 |
249 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() { | 304 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() { |
250 rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create(); | 305 rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create(); |
251 collector_->GetStatsReport(callback); | 306 collector_->GetStatsReport(callback); |
252 EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs); | 307 EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs); |
253 return callback->report(); | 308 return callback->report(); |
254 } | 309 } |
255 | 310 |
| 311 void ExpectReportContainsCertificateInfo( |
| 312 const rtc::scoped_refptr<const RTCStatsReport>& report, |
| 313 const CertificateInfo& cert_info) { |
| 314 for (size_t i = 0; i < cert_info.fingerprints.size(); ++i) { |
| 315 const RTCStats* stats = report->Get( |
| 316 "RTCCertificate_" + cert_info.fingerprints[i]); |
| 317 EXPECT_TRUE(stats); |
| 318 const RTCCertificateStats& cert_stats = |
| 319 stats->cast_to<const RTCCertificateStats>(); |
| 320 EXPECT_EQ(*cert_stats.fingerprint, cert_info.fingerprints[i]); |
| 321 EXPECT_EQ(*cert_stats.fingerprint_algorithm, "sha-1"); |
| 322 EXPECT_EQ(*cert_stats.base64_certificate, cert_info.pems[i]); |
| 323 if (i + 1 < cert_info.fingerprints.size()) { |
| 324 EXPECT_EQ(*cert_stats.issuer_certificate_id, |
| 325 "RTCCertificate_" + cert_info.fingerprints[i + 1]); |
| 326 } else { |
| 327 EXPECT_FALSE(cert_stats.issuer_certificate_id.is_defined()); |
| 328 } |
| 329 } |
| 330 } |
| 331 |
256 protected: | 332 protected: |
257 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_; | 333 rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_; |
258 rtc::scoped_refptr<RTCStatsCollector> collector_; | 334 rtc::scoped_refptr<RTCStatsCollector> collector_; |
259 }; | 335 }; |
260 | 336 |
261 TEST_F(RTCStatsCollectorTest, SingleCallback) { | 337 TEST_F(RTCStatsCollectorTest, SingleCallback) { |
262 rtc::scoped_refptr<const RTCStatsReport> result; | 338 rtc::scoped_refptr<const RTCStatsReport> result; |
263 collector_->GetStatsReport(StatsCallback::Create(&result)); | 339 collector_->GetStatsReport(StatsCallback::Create(&result)); |
264 EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs); | 340 EXPECT_TRUE_WAIT(result, kGetStatsReportTimeoutMs); |
265 } | 341 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 collector_->GetStatsReport(StatsCallback::Create(&c)); | 381 collector_->GetStatsReport(StatsCallback::Create(&c)); |
306 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); | 382 EXPECT_TRUE_WAIT(a, kGetStatsReportTimeoutMs); |
307 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); | 383 EXPECT_TRUE_WAIT(b, kGetStatsReportTimeoutMs); |
308 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); | 384 EXPECT_TRUE_WAIT(c, kGetStatsReportTimeoutMs); |
309 EXPECT_EQ(a.get(), b.get()); | 385 EXPECT_EQ(a.get(), b.get()); |
310 // The act of doing |AdvanceTime| processes all messages. If this was not the | 386 // The act of doing |AdvanceTime| processes all messages. If this was not the |
311 // case we might not require |c| to be fresher than |b|. | 387 // case we might not require |c| to be fresher than |b|. |
312 EXPECT_NE(c.get(), b.get()); | 388 EXPECT_NE(c.get(), b.get()); |
313 } | 389 } |
314 | 390 |
| 391 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) { |
| 392 std::unique_ptr<CertificateInfo> local_certinfo = |
| 393 CreateFakeCertificateAndInfoFromDers( |
| 394 std::vector<std::string>({ "(local) single certificate" })); |
| 395 std::unique_ptr<CertificateInfo> remote_certinfo = |
| 396 CreateFakeCertificateAndInfoFromDers( |
| 397 std::vector<std::string>({ "(remote) single certificate" })); |
| 398 |
| 399 // Mock the session to return the local and remote certificates. |
| 400 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( |
| 401 [this](SessionStats* stats) { |
| 402 stats->transport_stats["transport"].transport_name = "transport"; |
| 403 return true; |
| 404 })); |
| 405 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( |
| 406 Invoke([this, &local_certinfo](const std::string& transport_name, |
| 407 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { |
| 408 if (transport_name == "transport") { |
| 409 *certificate = local_certinfo->certificate; |
| 410 return true; |
| 411 } |
| 412 return false; |
| 413 })); |
| 414 EXPECT_CALL(test_->session(), |
| 415 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( |
| 416 [this, &remote_certinfo](const std::string& transport_name) { |
| 417 if (transport_name == "transport") |
| 418 return remote_certinfo->certificate->ssl_certificate().GetReference(); |
| 419 return static_cast<rtc::SSLCertificate*>(nullptr); |
| 420 })); |
| 421 |
| 422 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); |
| 423 ExpectReportContainsCertificateInfo(report, *local_certinfo.get()); |
| 424 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get()); |
| 425 } |
| 426 |
| 427 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) { |
| 428 std::unique_ptr<CertificateInfo> audio_local_certinfo = |
| 429 CreateFakeCertificateAndInfoFromDers( |
| 430 std::vector<std::string>({ "(local) audio" })); |
| 431 audio_local_certinfo = CreateFakeCertificateAndInfoFromDers( |
| 432 audio_local_certinfo->ders); |
| 433 std::unique_ptr<CertificateInfo> audio_remote_certinfo = |
| 434 CreateFakeCertificateAndInfoFromDers( |
| 435 std::vector<std::string>({ "(remote) audio" })); |
| 436 audio_remote_certinfo = CreateFakeCertificateAndInfoFromDers( |
| 437 audio_remote_certinfo->ders); |
| 438 |
| 439 std::unique_ptr<CertificateInfo> video_local_certinfo = |
| 440 CreateFakeCertificateAndInfoFromDers( |
| 441 std::vector<std::string>({ "(local) video" })); |
| 442 video_local_certinfo = CreateFakeCertificateAndInfoFromDers( |
| 443 video_local_certinfo->ders); |
| 444 std::unique_ptr<CertificateInfo> video_remote_certinfo = |
| 445 CreateFakeCertificateAndInfoFromDers( |
| 446 std::vector<std::string>({ "(remote) video" })); |
| 447 video_remote_certinfo = CreateFakeCertificateAndInfoFromDers( |
| 448 video_remote_certinfo->ders); |
| 449 |
| 450 // Mock the session to return the local and remote certificates. |
| 451 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( |
| 452 [this](SessionStats* stats) { |
| 453 stats->transport_stats["audio"].transport_name = "audio"; |
| 454 stats->transport_stats["video"].transport_name = "video"; |
| 455 return true; |
| 456 })); |
| 457 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( |
| 458 Invoke([this, &audio_local_certinfo, &video_local_certinfo]( |
| 459 const std::string& transport_name, |
| 460 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { |
| 461 if (transport_name == "audio") { |
| 462 *certificate = audio_local_certinfo->certificate; |
| 463 return true; |
| 464 } |
| 465 if (transport_name == "video") { |
| 466 *certificate = video_local_certinfo->certificate; |
| 467 return true; |
| 468 } |
| 469 return false; |
| 470 })); |
| 471 EXPECT_CALL(test_->session(), |
| 472 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( |
| 473 [this, &audio_remote_certinfo, &video_remote_certinfo]( |
| 474 const std::string& transport_name) { |
| 475 if (transport_name == "audio") { |
| 476 return audio_remote_certinfo->certificate->ssl_certificate() |
| 477 .GetReference(); |
| 478 } |
| 479 if (transport_name == "video") { |
| 480 return video_remote_certinfo->certificate->ssl_certificate() |
| 481 .GetReference(); |
| 482 } |
| 483 return static_cast<rtc::SSLCertificate*>(nullptr); |
| 484 })); |
| 485 |
| 486 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); |
| 487 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo.get()); |
| 488 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo.get()); |
| 489 ExpectReportContainsCertificateInfo(report, *video_local_certinfo.get()); |
| 490 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo.get()); |
| 491 } |
| 492 |
| 493 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) { |
| 494 std::vector<std::string> local_ders; |
| 495 local_ders.push_back("(local) this"); |
| 496 local_ders.push_back("(local) is"); |
| 497 local_ders.push_back("(local) a"); |
| 498 local_ders.push_back("(local) chain"); |
| 499 std::unique_ptr<CertificateInfo> local_certinfo = |
| 500 CreateFakeCertificateAndInfoFromDers(local_ders); |
| 501 std::vector<std::string> remote_ders; |
| 502 remote_ders.push_back("(remote) this"); |
| 503 remote_ders.push_back("(remote) is"); |
| 504 remote_ders.push_back("(remote) another"); |
| 505 remote_ders.push_back("(remote) chain"); |
| 506 std::unique_ptr<CertificateInfo> remote_certinfo = |
| 507 CreateFakeCertificateAndInfoFromDers(remote_ders); |
| 508 |
| 509 // Mock the session to return the local and remote certificates. |
| 510 EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke( |
| 511 [this](SessionStats* stats) { |
| 512 stats->transport_stats["transport"].transport_name = "transport"; |
| 513 return true; |
| 514 })); |
| 515 EXPECT_CALL(test_->session(), GetLocalCertificate(_, _)).WillRepeatedly( |
| 516 Invoke([this, &local_certinfo](const std::string& transport_name, |
| 517 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { |
| 518 if (transport_name == "transport") { |
| 519 *certificate = local_certinfo->certificate; |
| 520 return true; |
| 521 } |
| 522 return false; |
| 523 })); |
| 524 EXPECT_CALL(test_->session(), |
| 525 GetRemoteSSLCertificate_ReturnsRawPointer(_)).WillRepeatedly(Invoke( |
| 526 [this, &remote_certinfo](const std::string& transport_name) { |
| 527 if (transport_name == "transport") |
| 528 return remote_certinfo->certificate->ssl_certificate().GetReference(); |
| 529 return static_cast<rtc::SSLCertificate*>(nullptr); |
| 530 })); |
| 531 |
| 532 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); |
| 533 ExpectReportContainsCertificateInfo(report, *local_certinfo.get()); |
| 534 ExpectReportContainsCertificateInfo(report, *remote_certinfo.get()); |
| 535 } |
| 536 |
315 TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) { | 537 TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) { |
316 int64_t before = rtc::TimeUTCMicros(); | 538 int64_t before = rtc::TimeUTCMicros(); |
317 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); | 539 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport(); |
318 int64_t after = rtc::TimeUTCMicros(); | 540 int64_t after = rtc::TimeUTCMicros(); |
319 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(), | 541 EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(), |
320 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats."; | 542 static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats."; |
321 const RTCStats* stats = report->Get("RTCPeerConnection"); | 543 const RTCStats* stats = report->Get("RTCPeerConnection"); |
322 EXPECT_TRUE(stats); | 544 EXPECT_TRUE(stats); |
323 EXPECT_LE(before, stats->timestamp_us()); | 545 EXPECT_LE(before, stats->timestamp_us()); |
324 EXPECT_LE(stats->timestamp_us(), after); | 546 EXPECT_LE(stats->timestamp_us(), after); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 rtc::scoped_refptr<FakeRTCStatsCollector> collector_; | 593 rtc::scoped_refptr<FakeRTCStatsCollector> collector_; |
372 }; | 594 }; |
373 | 595 |
374 TEST_F(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) { | 596 TEST_F(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) { |
375 collector_->VerifyThreadUsageAndResultsMerging(); | 597 collector_->VerifyThreadUsageAndResultsMerging(); |
376 } | 598 } |
377 | 599 |
378 } // namespace | 600 } // namespace |
379 | 601 |
380 } // namespace webrtc | 602 } // namespace webrtc |
OLD | NEW |