Chromium Code Reviews| Index: chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc |
| diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc |
| index 07de07b85dbeaa828a7b46a72acd5a6258657e33..c4a8d23ce6095ca839e00f27a733762c73cbcc5d 100644 |
| --- a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc |
| +++ b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc |
| @@ -10,11 +10,15 @@ |
| #include "base/bind_helpers.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| +#include "base/test/histogram_tester.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/test/thread_test_helper.h" |
| #include "base/time/clock.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h" |
| +#include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| +#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" |
| +#include "chrome/test/base/testing_profile.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/test_browser_thread.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| @@ -25,16 +29,67 @@ |
| #include "net/url_request/url_request_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| +using certificate_reporting_test_utils::ReportExpectation; |
| + |
| namespace { |
| // Maximum number of reports kept in the certificate reporting service's retry |
| // queue. |
| const size_t kMaxReportCountInQueue = 3; |
| +const char* kFailedReportHistogram = "SSL.CertificateErrorReportFailure"; |
| + |
| void ClearURLHandlers() { |
| net::URLRequestFilter::GetInstance()->ClearHandlers(); |
| } |
| +// A network delegate used to observe URL request destructions. The tests check |
| +// that no outstanding URL request is present during tear down. |
| +class TestNetworkDelegate : public net::NetworkDelegateImpl { |
| + public: |
| + TestNetworkDelegate( |
| + const base::Callback<void()>& url_request_destroyed_callback) |
| + : url_request_destroyed_callback_(url_request_destroyed_callback) {} |
| + |
| + ~TestNetworkDelegate() override {} |
| + |
| + // net::NetworkDelegate method: |
| + void OnURLRequestDestroyed(net::URLRequest* request) override { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| + url_request_destroyed_callback_); |
| + } |
| + |
| + private: |
| + base::Callback<void()> url_request_destroyed_callback_; |
| +}; |
| + |
| +// Base class for histogram testing. The failed report histogram is checked once |
| +// after teardown to ensure all in flight requests have completed. |
| +class HistogramTestBase { |
| + protected: |
| + virtual ~HistogramTestBase() {} |
| + |
| + // Sets the expected histogram value to be checked during teardown. |
|
estark
2016/12/16 01:57:59
nit: maybe make this SetExpectedHistogramFailedCou
meacer
2016/12/16 20:26:36
Changed it to SetExpectedFailedReportCount, added
|
| + void SetExpectedHistogramCountOnTeardown(int num_expected_failed_report) { |
| + num_expected_failed_report_ = num_expected_failed_report; |
| + } |
| + |
| + void CheckHistogram() { |
| + if (num_expected_failed_report_ != 0) { |
| + histogram_tester_.ExpectUniqueSample(kFailedReportHistogram, |
| + -net::ERR_SSL_PROTOCOL_ERROR, |
| + num_expected_failed_report_); |
| + } else { |
| + histogram_tester_.ExpectTotalCount(kFailedReportHistogram, 0); |
| + } |
| + } |
| + |
| + private: |
| + int num_expected_failed_report_ = 0; |
|
estark
2016/12/16 01:57:59
unsigned int
meacer
2016/12/16 20:26:36
Done.
|
| + base::HistogramTester histogram_tester_; |
| +}; |
| + |
| } // namespace |
| TEST(CertificateReportingServiceReportListTest, BoundedReportList) { |
| @@ -77,7 +132,8 @@ TEST(CertificateReportingServiceReportListTest, BoundedReportList) { |
| } |
| class CertificateReportingServiceReporterOnIOThreadTest |
| - : public ::testing::Test { |
| + : public ::testing::Test, |
| + public HistogramTestBase { |
|
estark
2016/12/16 01:57:59
Instead of the multiple inheritance, could the tes
meacer
2016/12/16 20:26:36
Done.
|
| public: |
| void SetUp() override { |
| message_loop_.reset(new base::MessageLoopForIO()); |
| @@ -89,7 +145,12 @@ class CertificateReportingServiceReporterOnIOThreadTest |
| net::URLRequestMockDataJob::AddUrlHandler(); |
| } |
| - void TearDown() override { ClearURLHandlers(); } |
| + void TearDown() override { |
| + ClearURLHandlers(); |
| + // Check the histogram as the last thing. This makes sure no in-flight |
| + // report is missed. |
| + CheckHistogram(); |
| + } |
| protected: |
| net::URLRequestContextGetter* url_request_context_getter() { |
| @@ -105,6 +166,8 @@ class CertificateReportingServiceReporterOnIOThreadTest |
| TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
| Reporter_RetriesEnabled) { |
| + SetExpectedHistogramCountOnTeardown(6); |
| + |
| std::unique_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock()); |
| base::Time reference_time = base::Time::Now(); |
| clock->SetNow(reference_time); |
| @@ -202,6 +265,8 @@ TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
| // Same as above, but retries are disabled. |
| TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
| Reporter_RetriesDisabled) { |
| + SetExpectedHistogramCountOnTeardown(2); |
| + |
| std::unique_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock()); |
| base::Time reference_time = base::Time::Now(); |
| clock->SetNow(reference_time); |
| @@ -250,7 +315,8 @@ TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
| class CertificateReportingServiceTest |
| : public ::testing::Test, |
| public certificate_reporting_test_utils:: |
| - CertificateReportingServiceTestBase { |
| + CertificateReportingServiceTestBase, |
| + public HistogramTestBase { |
|
estark
2016/12/16 01:57:59
same here
meacer
2016/12/16 20:26:36
Done.
|
| public: |
| CertificateReportingServiceTest() |
| : CertificateReportingServiceTestBase(), |
| @@ -271,24 +337,18 @@ class CertificateReportingServiceTest |
| base::Unretained(this))); |
| WaitForIOThread(); |
| - clock_ = new base::SimpleTestClock(); |
| + safe_browsing::SafeBrowsingService::RegisterFactory(&sb_service_factory); |
| + sb_service_ = sb_service_factory.CreateSafeBrowsingService(); |
| + |
| + clock_.reset(new base::SimpleTestClock()); |
| service_.reset(new CertificateReportingService( |
| - url_request_context_getter(), server_public_key(), |
| - server_public_key_version(), kMaxReportCountInQueue, |
| - base::TimeDelta::FromHours(24), std::unique_ptr<base::Clock>(clock_))); |
| + sb_service_.get(), url_request_context_getter(), &profile_, |
| + server_public_key(), server_public_key_version(), |
| + kMaxReportCountInQueue, base::TimeDelta::FromHours(24), clock_.get())); |
| // Wait for service reset. |
| WaitForIOThread(); |
| } |
| - void SetUpURLRequestContextOnIOThread() { |
| - std::unique_ptr<net::TestURLRequestContext> url_request_context( |
| - new net::TestURLRequestContext(true)); |
| - url_request_context->set_network_delegate(network_delegate()); |
| - url_request_context->Init(); |
| - url_request_context_getter_ = new net::TestURLRequestContextGetter( |
| - io_task_runner_, std::move(url_request_context)); |
| - } |
| - |
| void TearDown() override { |
| WaitForIOThread(); |
| EXPECT_TRUE(interceptor()->successful_reports().empty()); |
| @@ -302,12 +362,27 @@ class CertificateReportingServiceTest |
| WaitForIOThread(); |
| service_.reset(nullptr); |
| + |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, FROM_HERE, |
| + base::Bind(&CertificateReportingServiceTest::TearDownOnIOThread, |
| + base::Unretained(this))); |
|
estark
2016/12/16 01:57:59
This looks a little sketchy to me. I'd think we ne
meacer
2016/12/16 20:26:36
Done.
|
| content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, |
| base::Bind(&ClearURLHandlers)); |
| - TearDownInterceptor(); |
| + |
| + CheckHistogram(); |
| } |
| protected: |
| + void WaitForRequestsDestroyed(const ReportExpectation& expectation) { |
| + wait_helper_.Wait(expectation.num_reports()); |
| + EXPECT_EQ(expectation.successful_reports, |
| + interceptor()->successful_reports()); |
| + EXPECT_EQ(expectation.failed_reports, interceptor()->failed_reports()); |
| + EXPECT_EQ(expectation.delayed_reports, interceptor()->delayed_reports()); |
| + interceptor()->ClearObservedReports(); |
| + } |
| + |
| net::URLRequestContextGetter* url_request_context_getter() { |
| return url_request_context_getter_.get(); |
| } |
| @@ -318,6 +393,8 @@ class CertificateReportingServiceTest |
| ASSERT_TRUE(io_helper->Run()); |
| } |
| + CertificateReportingService* service() { return service_.get(); } |
| + |
| // Sets service enabled state and waits for a reset event. |
| void SetServiceEnabledAndWait(bool enabled) { |
| service()->SetEnabled(enabled); |
| @@ -327,30 +404,61 @@ class CertificateReportingServiceTest |
| void AdvanceClock(base::TimeDelta delta) { |
| content::BrowserThread::PostTask( |
| content::BrowserThread::IO, FROM_HERE, |
| - base::Bind(&base::SimpleTestClock::Advance, base::Unretained(clock_), |
| - delta)); |
| + base::Bind(&base::SimpleTestClock::Advance, |
| + base::Unretained(clock_.get()), delta)); |
| } |
| void SetNow(base::Time now) { |
| - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, |
| - base::Bind(&base::SimpleTestClock::SetNow, |
| - base::Unretained(clock_), now)); |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, FROM_HERE, |
| + base::Bind(&base::SimpleTestClock::SetNow, |
| + base::Unretained(clock_.get()), now)); |
| } |
| - CertificateReportingService* service() { return service_.get(); } |
| - |
| private: |
| + void SetUpURLRequestContextOnIOThread() { |
| + network_delegate_.reset(new TestNetworkDelegate( |
| + base::Bind(&CertificateReportingServiceTest::OnURLRequestDestroyed, |
| + base::Unretained(this)))); |
| + |
| + std::unique_ptr<net::TestURLRequestContext> url_request_context( |
| + new net::TestURLRequestContext(true)); |
| + url_request_context->set_network_delegate(network_delegate_.get()); |
| + url_request_context->Init(); |
| + url_request_context_getter_ = new net::TestURLRequestContextGetter( |
| + io_task_runner_, std::move(url_request_context)); |
| + } |
| + |
| + void TearDownOnIOThread() { |
| + url_request_context_getter_ = nullptr; |
| + network_delegate_.reset(nullptr); |
| + } |
| + |
| + void OnURLRequestDestroyed() { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| + wait_helper_.OnEvent(); |
| + } |
| + |
| // Must be initialized before url_request_context_getter_ |
| content::TestBrowserThreadBundle thread_bundle_; |
| + std::unique_ptr<TestNetworkDelegate> network_delegate_; |
| + certificate_reporting_test_utils::ReportWaitHelper wait_helper_; |
| + |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; |
| std::unique_ptr<CertificateReportingService> service_; |
| - base::SimpleTestClock* clock_; |
| + std::unique_ptr<base::SimpleTestClock> clock_; |
| + |
| + scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_; |
| + safe_browsing::TestSafeBrowsingServiceFactory sb_service_factory; |
| + TestingProfile profile_; |
| }; |
| TEST_F(CertificateReportingServiceTest, Send) { |
| + SetExpectedHistogramCountOnTeardown(4); |
| + |
| WaitForIOThread(); |
| // Let all reports fail. |
| SetFailureMode( |
| @@ -384,6 +492,8 @@ TEST_F(CertificateReportingServiceTest, Send) { |
| } |
| TEST_F(CertificateReportingServiceTest, Disabled_ShouldNotSend) { |
| + SetExpectedHistogramCountOnTeardown(0); |
| + |
| // Let all reports succeed. |
| SetFailureMode(certificate_reporting_test_utils::ReportSendingResult:: |
| REPORTS_SUCCESSFUL); |
| @@ -395,7 +505,7 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldNotSend) { |
| // should be observed. |
| service()->Send("report0"); |
| - // Enable the service and send a report again. |
| + // Enable the service and send a report again. It should be sent successfully. |
| SetServiceEnabledAndWait(true); |
| service()->Send("report1"); |
| @@ -403,6 +513,8 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldNotSend) { |
| } |
| TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { |
| + SetExpectedHistogramCountOnTeardown(1); |
| + |
| // Let all reports fail. |
| SetFailureMode( |
| certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); |
| @@ -413,7 +525,7 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { |
| // Disable the service. |
| SetServiceEnabledAndWait(false); |
| - // Sending has no effect while disabled, wait for a single cancelled event. |
| + // Sending has no effect while disabled. |
| service()->SendPending(); |
| // Re-enable the service and send pending reports. Pending reports should have |
| @@ -425,6 +537,8 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { |
| } |
| TEST_F(CertificateReportingServiceTest, DontSendOldReports) { |
| + SetExpectedHistogramCountOnTeardown(5); |
| + |
| SetNow(base::Time::Now()); |
| // Let all reports fail. |
| SetFailureMode( |
| @@ -469,6 +583,8 @@ TEST_F(CertificateReportingServiceTest, DontSendOldReports) { |
| } |
| TEST_F(CertificateReportingServiceTest, DiscardOldReports) { |
| + SetExpectedHistogramCountOnTeardown(7); |
| + |
| SetNow(base::Time::Now()); |
| // Let all reports fail. |
| SetFailureMode( |
| @@ -523,6 +639,8 @@ TEST_F(CertificateReportingServiceTest, DiscardOldReports) { |
| // A delayed report should successfully upload when it's resumed. |
| TEST_F(CertificateReportingServiceTest, Delayed_Resumed) { |
| + SetExpectedHistogramCountOnTeardown(0); |
| + |
| // Let reports hang. |
| SetFailureMode( |
| certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); |
| @@ -532,12 +650,14 @@ TEST_F(CertificateReportingServiceTest, Delayed_Resumed) { |
| // Resume the report upload and run the callbacks. The report should be |
| // successfully sent. |
| - ResumeDelayedRequest(); |
| + ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
| WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0"})); |
| } |
| // Delayed reports should cleaned when the service is reset. |
| TEST_F(CertificateReportingServiceTest, Delayed_Reset) { |
| + SetExpectedHistogramCountOnTeardown(0); |
| + |
| // Let reports hang. |
| SetFailureMode( |
| certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); |
| @@ -552,7 +672,7 @@ TEST_F(CertificateReportingServiceTest, Delayed_Reset) { |
| // Resume delayed report. No report should be observed since the service |
| // should have reset and all pending reports should be cleared. If any report |
| // is observed, the next WaitForRequestsDestroyed() will fail. |
| - ResumeDelayedRequest(); |
| + ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
| // Enable the service. |
| SetServiceEnabledAndWait(true); |
| @@ -562,7 +682,7 @@ TEST_F(CertificateReportingServiceTest, Delayed_Reset) { |
| // report queue has been cleared above. |
| service()->Send("report1"); |
| - // Resume delayed report. The report should be observed. |
| - ResumeDelayedRequest(); |
| + // Resume delayed report. Two reports are successfully sent. |
| + ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
| WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0", "report1"})); |
| } |