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..8ef06293dfdb0372268a7cf9763e1cc964ee36f4 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,66 @@ |
#include "net/url_request/url_request_test_util.h" |
#include "testing/gtest/include/gtest/gtest.h" |
+using certificate_reporting_test_utils::CertificateReportingServiceTestHelper; |
+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 ReportHistogramTestHelper { |
+ public: |
+ // Sets the expected histogram value to be checked during teardown. |
+ void SetExpectedFailedReportCount(unsigned 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: |
+ unsigned int num_expected_failed_report_ = 0; |
+ base::HistogramTester histogram_tester_; |
+}; |
+ |
} // namespace |
TEST(CertificateReportingServiceReportListTest, BoundedReportList) { |
@@ -89,22 +143,34 @@ 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. |
+ histogram_test_helper_.CheckHistogram(); |
+ } |
protected: |
net::URLRequestContextGetter* url_request_context_getter() { |
return url_request_context_getter_.get(); |
} |
+ void SetExpectedFailedReportCountOnTearDown(unsigned int count) { |
+ histogram_test_helper_.SetExpectedFailedReportCount(count); |
+ } |
+ |
private: |
std::unique_ptr<base::MessageLoopForIO> message_loop_; |
std::unique_ptr<content::TestBrowserThread> io_thread_; |
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; |
+ ReportHistogramTestHelper histogram_test_helper_; |
}; |
TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
Reporter_RetriesEnabled) { |
+ SetExpectedFailedReportCountOnTearDown(6); |
+ |
std::unique_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock()); |
base::Time reference_time = base::Time::Now(); |
clock->SetNow(reference_time); |
@@ -202,6 +268,8 @@ TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
// Same as above, but retries are disabled. |
TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
Reporter_RetriesDisabled) { |
+ SetExpectedFailedReportCountOnTearDown(2); |
+ |
std::unique_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock()); |
base::Time reference_time = base::Time::Now(); |
clock->SetNow(reference_time); |
@@ -247,21 +315,17 @@ TEST_F(CertificateReportingServiceReporterOnIOThreadTest, |
ASSERT_EQ(0u, list->items().size()); |
} |
-class CertificateReportingServiceTest |
- : public ::testing::Test, |
- public certificate_reporting_test_utils:: |
- CertificateReportingServiceTestBase { |
+class CertificateReportingServiceTest : public ::testing::Test { |
public: |
CertificateReportingServiceTest() |
- : CertificateReportingServiceTestBase(), |
- thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), |
+ : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), |
io_task_runner_(content::BrowserThread::GetTaskRunnerForThread( |
content::BrowserThread::IO)) {} |
~CertificateReportingServiceTest() override {} |
void SetUp() override { |
- SetUpInterceptor(); |
+ test_helper_.SetUpInterceptor(); |
WaitForIOThread(); |
content::BrowserThread::PostTask( |
@@ -271,43 +335,55 @@ 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_, |
+ test_helper_.server_public_key(), |
+ test_helper_.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()); |
- EXPECT_TRUE(interceptor()->failed_reports().empty()); |
- EXPECT_TRUE(interceptor()->delayed_reports().empty()); |
+ EXPECT_TRUE(test_helper_.interceptor()->successful_reports().empty()); |
+ EXPECT_TRUE(test_helper_.interceptor()->failed_reports().empty()); |
+ EXPECT_TRUE(test_helper_.interceptor()->delayed_reports().empty()); |
EXPECT_EQ(0u, service() |
->GetReporterForTesting() |
->inflight_report_count_for_testing()); |
service_->Shutdown(); |
WaitForIOThread(); |
- |
service_.reset(nullptr); |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&CertificateReportingServiceTest::TearDownOnIOThread, |
+ base::Unretained(this))); |
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, |
base::Bind(&ClearURLHandlers)); |
- TearDownInterceptor(); |
+ WaitForIOThread(); |
+ |
+ histogram_test_helper_.CheckHistogram(); |
} |
protected: |
+ void WaitForRequestsDestroyed(const ReportExpectation& expectation) { |
+ wait_helper_.Wait(expectation.num_reports()); |
+ EXPECT_EQ(expectation.successful_reports, |
+ test_helper_.interceptor()->successful_reports()); |
+ EXPECT_EQ(expectation.failed_reports, |
+ test_helper_.interceptor()->failed_reports()); |
+ EXPECT_EQ(expectation.delayed_reports, |
+ test_helper_.interceptor()->delayed_reports()); |
+ test_helper_.interceptor()->ClearObservedReports(); |
+ } |
+ |
net::URLRequestContextGetter* url_request_context_getter() { |
return url_request_context_getter_.get(); |
} |
@@ -318,6 +394,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,33 +405,72 @@ 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(); } |
+ void SetExpectedFailedReportCountOnTearDown(unsigned int count) { |
+ histogram_test_helper_.SetExpectedFailedReportCount(count); |
+ } |
+ |
+ CertificateReportingServiceTestHelper* test_helper() { return &test_helper_; } |
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_; |
+ |
+ CertificateReportingServiceTestHelper test_helper_; |
+ ReportHistogramTestHelper histogram_test_helper_; |
}; |
TEST_F(CertificateReportingServiceTest, Send) { |
- WaitForIOThread(); |
+ SetExpectedFailedReportCountOnTearDown(4); |
+ |
// Let all reports fail. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); |
// Send two reports. Both should fail and get queued. |
@@ -369,8 +486,8 @@ TEST_F(CertificateReportingServiceTest, Send) { |
WaitForRequestsDestroyed(ReportExpectation::Failed({"report0", "report1"})); |
// Let all reports succeed. |
- SetFailureMode(certificate_reporting_test_utils::ReportSendingResult:: |
- REPORTS_SUCCESSFUL); |
+ test_helper()->SetFailureMode(certificate_reporting_test_utils:: |
+ ReportSendingResult::REPORTS_SUCCESSFUL); |
// Send a third report. This should not be queued. |
service()->Send("report2"); |
@@ -384,9 +501,11 @@ TEST_F(CertificateReportingServiceTest, Send) { |
} |
TEST_F(CertificateReportingServiceTest, Disabled_ShouldNotSend) { |
+ SetExpectedFailedReportCountOnTearDown(0); |
+ |
// Let all reports succeed. |
- SetFailureMode(certificate_reporting_test_utils::ReportSendingResult:: |
- REPORTS_SUCCESSFUL); |
+ test_helper()->SetFailureMode(certificate_reporting_test_utils:: |
+ ReportSendingResult::REPORTS_SUCCESSFUL); |
// Disable the service. |
SetServiceEnabledAndWait(false); |
@@ -395,7 +514,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,8 +522,10 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldNotSend) { |
} |
TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { |
+ SetExpectedFailedReportCountOnTearDown(1); |
+ |
// Let all reports fail. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); |
service()->Send("report0"); |
@@ -413,7 +534,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,9 +546,11 @@ TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { |
} |
TEST_F(CertificateReportingServiceTest, DontSendOldReports) { |
+ SetExpectedFailedReportCountOnTearDown(5); |
+ |
SetNow(base::Time::Now()); |
// Let all reports fail. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); |
// Send a report. |
@@ -469,9 +592,11 @@ TEST_F(CertificateReportingServiceTest, DontSendOldReports) { |
} |
TEST_F(CertificateReportingServiceTest, DiscardOldReports) { |
+ SetExpectedFailedReportCountOnTearDown(7); |
+ |
SetNow(base::Time::Now()); |
// Let all reports fail. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); |
// Send a failed report. |
@@ -502,8 +627,8 @@ TEST_F(CertificateReportingServiceTest, DiscardOldReports) { |
ReportExpectation::Failed({"report1", "report2", "report3"})); |
// Let all reports succeed. |
- SetFailureMode(certificate_reporting_test_utils::ReportSendingResult:: |
- REPORTS_SUCCESSFUL); |
+ test_helper()->SetFailureMode(certificate_reporting_test_utils:: |
+ ReportSendingResult::REPORTS_SUCCESSFUL); |
// Advance the clock by 15 hours. Current time is now 30 hours after reference |
// time. The ages of reports are now as follows: |
@@ -523,8 +648,10 @@ TEST_F(CertificateReportingServiceTest, DiscardOldReports) { |
// A delayed report should successfully upload when it's resumed. |
TEST_F(CertificateReportingServiceTest, Delayed_Resumed) { |
+ SetExpectedFailedReportCountOnTearDown(0); |
+ |
// Let reports hang. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); |
// Send a report. The report upload hangs, so no error or success callbacks |
// should be called. |
@@ -532,14 +659,16 @@ TEST_F(CertificateReportingServiceTest, Delayed_Resumed) { |
// Resume the report upload and run the callbacks. The report should be |
// successfully sent. |
- ResumeDelayedRequest(); |
+ test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0"})); |
} |
// Delayed reports should cleaned when the service is reset. |
TEST_F(CertificateReportingServiceTest, Delayed_Reset) { |
+ SetExpectedFailedReportCountOnTearDown(0); |
+ |
// Let reports hang. |
- SetFailureMode( |
+ test_helper()->SetFailureMode( |
certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); |
// Send a report. The report is triggered but hangs, so no error or success |
// callbacks should be called. |
@@ -552,7 +681,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(); |
+ test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
// Enable the service. |
SetServiceEnabledAndWait(true); |
@@ -562,7 +691,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. |
+ test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); |
WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0", "report1"})); |
} |