blob: 2412c10c3de4f9df5fdd061c2bb004fd44da1626 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/certificate_reporting_service.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/test/metrics/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 "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
#include "chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h"
#include "chrome/browser/ssl/cert_report_helper.h"
#include "chrome/browser/ssl/certificate_error_report.h"
#include "chrome/browser/ssl/certificate_reporting_test_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/variations/variations_params_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/url_request/report_sender.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_test_util.h"
#include "url/scheme_host_port.h"
using certificate_reporting_test_utils::CertificateReportingServiceTestHelper;
using certificate_reporting_test_utils::CertificateReportingServiceObserver;
using certificate_reporting_test_utils::EventHistogramTester;
using certificate_reporting_test_utils::ReportExpectation;
using certificate_reporting_test_utils::RetryStatus;
namespace {
const char* kFailedReportHistogram = "SSL.CertificateErrorReportFailure";
void CleanUpOnIOThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::URLRequestFilter::GetInstance()->ClearHandlers();
}
} // namespace
namespace safe_browsing {
// These tests check the whole mechanism to send and queue invalid certificate
// reports. Each test triggers reports by visiting broken SSL pages. The reports
// succeed, fail or hang indefinitely:
// - If a report is expected to fail or succeed, the test waits for the
// corresponding URL request jobs to be destroyed.
// - If a report is expected to hang, the test waits for the corresponding URL
// request job to be created. Only after resuming the hung request job the
// test waits for the request to be destroyed.
class CertificateReportingServiceBrowserTest
: public InProcessBrowserTest,
public testing::WithParamInterface<bool> {
public:
CertificateReportingServiceBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
CertReportHelper::SetFakeOfficialBuildForTesting();
}
void SetUpOnMainThread() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
host_resolver()->AddRule("*", "127.0.0.1");
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
https_server_.ServeFilesFromSourceDirectory("chrome/test/data");
ASSERT_TRUE(https_server_.Start());
test_helper_ =
base::MakeRefCounted<CertificateReportingServiceTestHelper>();
CertificateReportingServiceFactory::GetInstance()
->SetReportEncryptionParamsForTesting(
test_helper()->server_public_key(),
test_helper()->server_public_key_version());
CertificateReportingServiceFactory::GetInstance()
->SetServiceResetCallbackForTesting(
base::Bind(&CertificateReportingServiceObserver::OnServiceReset,
base::Unretained(&service_observer_)));
CertificateReportingServiceFactory::GetInstance()
->SetURLLoaderFactoryForTesting(test_helper_);
event_histogram_tester_.reset(new EventHistogramTester());
InProcessBrowserTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
test_helper()->ExpectNoRequests(service());
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&CleanUpOnIOThread));
EXPECT_GE(num_expected_failed_report_, 0)
<< "Don't forget to set expected failed report count.";
// Check the histogram as the last thing. This makes sure no in-flight
// report is missed.
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);
}
event_histogram_tester_.reset();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// Setting the sending threshold to 1.0 ensures reporting is enabled.
variations::testing::VariationParamsManager::AppendVariationParams(
"ReportCertificateErrors", "ShowAndPossiblySend",
{{"sendingThreshold", "1.0"}}, command_line);
if (GetParam()) {
command_line->AppendSwitch(switches::kCommittedInterstitials);
}
}
CertificateReportingServiceTestHelper* test_helper() {
return test_helper_.get();
}
void WaitForNoReports() {
if (!service()->GetReporterForTesting() ||
!service()
->GetReporterForTesting()
->inflight_report_count_for_testing())
return;
base::RunLoop run_loop;
service()
->GetReporterForTesting()
->SetClosureWhenNoInflightReportsForTesting(run_loop.QuitClosure());
run_loop.Run();
}
protected:
CertificateReportingServiceFactory* factory() {
return CertificateReportingServiceFactory::GetInstance();
}
// Sends a report using the provided hostname. Navigates to an interstitial
// page on this hostname and away from it to trigger a report.
void SendReport(const std::string& hostname) {
// Create an HTTPS URL from the hostname. This will resolve to the HTTPS
// server and cause an SSL error.
const GURL kCertErrorURL(
url::SchemeHostPort("https", hostname, https_server_.port()).GetURL());
// Navigate to the page with SSL error.
TabStripModel* tab_strip_model = browser()->tab_strip_model();
content::WebContents* contents = tab_strip_model->GetActiveWebContents();
ui_test_utils::NavigateToURL(browser(), kCertErrorURL);
// When GetParam() is true, committed interstitials are enabled. In this
// case, no interstitial attaches; once a navigation commits, the error page
// is present.
if (!GetParam())
content::WaitForInterstitialAttach(contents);
// Navigate away from the interstitial to trigger report upload.
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
if (!GetParam())
content::WaitForInterstitialDetach(contents);
}
void SendPendingReports() {
WaitForNoReports();
service()->SendPending();
}
// Changes opt-in status and waits for the cert reporting service to reset.
// Can only be used after the service is initialized. When changing the
// value at the beginning of a test,
// certificate_reporting_test_utils::SetCertReportingOptIn should be used
// instead since the service is only created upon first SSL error.
// Changing the opt-in status synchronously fires
// CertificateReportingService::PreferenceObserver::OnPreferenceChanged which
// will call CertificateReportingService::SetEnabled() which in turn posts
// a task to the IO thread to reset the service. Waiting for the IO thread
// ensures that the service is reset before returning from this method.
void ChangeOptInAndWait(certificate_reporting_test_utils::OptIn opt_in) {
service_observer_.Clear();
certificate_reporting_test_utils::SetCertReportingOptIn(browser(), opt_in);
service_observer_.WaitForReset();
}
// Same as ChangeOptInAndWait, but enables/disables SafeBrowsing instead.
void ToggleSafeBrowsingAndWaitForServiceReset(bool safebrowsing_enabled) {
service_observer_.Clear();
browser()->profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled,
safebrowsing_enabled);
service_observer_.WaitForReset();
}
void SetExpectedHistogramCountOnTeardown(int num_expected_failed_report) {
num_expected_failed_report_ = num_expected_failed_report;
}
CertificateReportingService* service() const {
return CertificateReportingServiceFactory::GetForBrowserContext(
browser()->profile());
}
EventHistogramTester* event_histogram_tester() {
return event_histogram_tester_.get();
}
private:
// Checks that the serialized reports in |received_reports| have the same
// hostnames as |expected_hostnames|.
void CheckReports(const std::set<std::string>& expected_hostnames,
const std::set<std::string>& received_reports,
const std::string type) {
std::set<std::string> received_hostnames;
for (const std::string& serialized_report : received_reports) {
CertificateErrorReport report;
ASSERT_TRUE(report.InitializeFromString(serialized_report));
received_hostnames.insert(report.hostname());
}
EXPECT_EQ(expected_hostnames, received_hostnames) << type
<< " comparison failed";
}
net::EmbeddedTestServer https_server_;
int num_expected_failed_report_ = -1;
scoped_refptr<CertificateReportingServiceTestHelper> test_helper_;
CertificateReportingServiceObserver service_observer_;
base::HistogramTester histogram_tester_;
// Histogram tester for reporting events. This is a member instead of a local
// so that we can check the histogram after the test teardown. At that point
// all in flight reports should be completed or deleted because
// of CleanUpOnIOThread().
std::unique_ptr<EventHistogramTester> event_histogram_tester_;
DISALLOW_COPY_AND_ASSIGN(CertificateReportingServiceBrowserTest);
};
INSTANTIATE_TEST_CASE_P(,
CertificateReportingServiceBrowserTest,
::testing::Values(false, true));
// Tests that report send attempt should be cancelled when extended
// reporting is not opted in.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
NotOptedIn_ShouldNotSendReports) {
SetExpectedHistogramCountOnTeardown(0);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(),
certificate_reporting_test_utils::EXTENDED_REPORTING_DO_NOT_OPT_IN);
// Send a report. Test teardown checks for created and in-flight requests. If
// a report was incorrectly sent, the test will fail.
SendReport("no-report");
event_histogram_tester()->SetExpectedValues(0, 0, 0, 0);
}
// Tests that report send attempts are not cancelled when extended reporting is
// opted in. Goes to an interstitial page and navigates away to force a report
// send event.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
OptedIn_ShouldSendSuccessfulReport) {
SetExpectedHistogramCountOnTeardown(0);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let reports uploads successfully complete.
test_helper()->SetFailureMode(certificate_reporting_test_utils::
ReportSendingResult::REPORTS_SUCCESSFUL);
// Reporting is opted in, so the report should succeed.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Successful({{"report0", RetryStatus::NOT_RETRIED}}));
// report0 was successfully submitted.
event_histogram_tester()->SetExpectedValues(
1 /* submitted */, 0 /* failed */, 1 /* successful */, 0 /* dropped */);
}
// Tests that report send attempts are not cancelled when extended reporting is
// opted in. Goes to an interstitial page and navigate away to force a report
// send event. Repeats this three times and checks expected number of reports.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
OptedIn_ShouldQueueFailedReport) {
SetExpectedHistogramCountOnTeardown(2);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Send a failed report.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Send another failed report.
SendReport("report1");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::NOT_RETRIED}}));
// Let all report uploads complete successfully now.
test_helper()->SetFailureMode(certificate_reporting_test_utils::
ReportSendingResult::REPORTS_SUCCESSFUL);
// Send another report. This time the report should be successfully sent.
SendReport("report2");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Successful({{"report2", RetryStatus::NOT_RETRIED}}));
// Send all pending reports. The two previously failed reports should have
// been queued, and now be sent successfully.
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(ReportExpectation::Successful(
{{"report0", RetryStatus::RETRIED}, {"report1", RetryStatus::RETRIED}}));
// Try sending pending reports again. Since there is no pending report,
// nothing should be sent this time. If any report is sent, test teardown
// will catch it.
SendPendingReports();
// report0 was submitted twice, failed once, succeeded once.
// report1 was submitted twice, failed once, succeeded once.
// report2 was submitted once, succeeded once.
event_histogram_tester()->SetExpectedValues(
5 /* submitted */, 2 /* failed */, 3 /* successful */, 0 /* dropped */);
}
// Opting in then opting out of extended reporting should clear the pending
// report queue.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
OptedIn_ThenOptedOut) {
SetExpectedHistogramCountOnTeardown(1);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Send a failed report.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Disable reporting. This should clear all pending reports.
ChangeOptInAndWait(
certificate_reporting_test_utils::EXTENDED_REPORTING_DO_NOT_OPT_IN);
// Send pending reports. No reports should be observed during test teardown.
SendPendingReports();
// report0 was submitted once and failed once.
event_histogram_tester()->SetExpectedValues(
1 /* submitted */, 1 /* failed */, 0 /* successful */, 0 /* dropped */);
}
// Opting out, then in, then out of extended reporting should work as expected.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
OptedOut_ThenOptedIn_ThenOptedOut) {
SetExpectedHistogramCountOnTeardown(1);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(),
certificate_reporting_test_utils::EXTENDED_REPORTING_DO_NOT_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Send attempt should be cancelled since reporting is opted out.
SendReport("no-report");
test_helper()->ExpectNoRequests(service());
// Enable reporting.
ChangeOptInAndWait(
certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// A failed report should be observed.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Disable reporting. This should reset the reporting service and
// clear all pending reports.
ChangeOptInAndWait(
certificate_reporting_test_utils::EXTENDED_REPORTING_DO_NOT_OPT_IN);
// Report should be cancelled since reporting is opted out.
SendReport("report1");
test_helper()->ExpectNoRequests(service());
// Send pending reports. Nothing should be sent since there aren't any
// pending reports. If any report is sent, test teardown will catch it.
SendPendingReports();
// report0 was submitted once and failed once.
// report1 was never submitted.
event_histogram_tester()->SetExpectedValues(
1 /* submitted */, 1 /* failed */, 0 /* successful */, 0 /* dropped */);
}
// Disabling SafeBrowsing should clear pending reports queue in
// CertificateReportingService.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
DisableSafebrowsing) {
SetExpectedHistogramCountOnTeardown(2);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Send a report.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Disable SafeBrowsing. This should clear all pending reports.
ToggleSafeBrowsingAndWaitForServiceReset(false);
// Send pending reports. No reports should be observed.
SendPendingReports();
test_helper()->ExpectNoRequests(service());
// Re-enable SafeBrowsing and trigger another report which will be queued.
ToggleSafeBrowsingAndWaitForServiceReset(true);
SendReport("report1");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::NOT_RETRIED}}));
// Queued report should now be successfully sent.
test_helper()->SetFailureMode(certificate_reporting_test_utils::
ReportSendingResult::REPORTS_SUCCESSFUL);
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Successful({{"report1", RetryStatus::RETRIED}}));
WaitForNoReports();
// report0 was submitted once, failed once, then cleared.
// report1 was submitted twice, failed once, succeeded once.
event_histogram_tester()->SetExpectedValues(
3 /* submitted */, 2 /* failed */, 1 /* successful */, 0 /* dropped */);
}
// CertificateReportingService should ignore reports older than the report TTL.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
DontSendOldReports) {
SetExpectedHistogramCountOnTeardown(5);
base::SimpleTestClock clock;
base::Time reference_time = base::Time::Now();
clock.SetNow(reference_time);
factory()->SetClockForTesting(&clock);
// The service should ignore reports older than 24 hours.
factory()->SetQueuedReportTTLForTesting(base::TimeDelta::FromHours(24));
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Send a failed report.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Advance the clock a bit and trigger another failed report.
clock.Advance(base::TimeDelta::FromHours(5));
SendReport("report1");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::NOT_RETRIED}}));
// Advance the clock to 20 hours, putting it 25 hours ahead of the reference
// time. This makes report0 older than 24 hours. report1 is now 20 hours.
clock.Advance(base::TimeDelta::FromHours(20));
// Send pending reports. report0 should be discarded since it's too old.
// report1 should be queued again.
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::RETRIED}}));
// Trigger another failed report.
SendReport("report2");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report2", RetryStatus::NOT_RETRIED}}));
// Advance the clock 5 hours. report1 will now be 25 hours old.
clock.Advance(base::TimeDelta::FromHours(5));
// Send pending reports. report1 should be discarded since it's too old.
// report2 should be queued again.
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report2", RetryStatus::RETRIED}}));
// Advance the clock 20 hours again so that report2 is 25 hours old and is
// older than max age (24 hours).
clock.Advance(base::TimeDelta::FromHours(20));
// Send pending reports. report2 should be discarded since it's too old. No
// other reports remain. If any report is sent, test teardown will catch it.
SendPendingReports();
// Let all reports succeed and send a single report. This is to make sure
// that any (incorrectly) pending reports are dropped before the test tear
// down.
test_helper()->SetFailureMode(certificate_reporting_test_utils::
ReportSendingResult::REPORTS_SUCCESSFUL);
SendReport("report3");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Successful({{"report3", RetryStatus::NOT_RETRIED}}));
WaitForNoReports();
// report0 was submitted once, failed once, dropped once.
// report1 was submitted twice, failed twice, dropped once.
// report2 was submitted twice, failed twice, dropped once.
// report3 was submitted once, successful once.
event_histogram_tester()->SetExpectedValues(
6 /* submitted */, 5 /* failed */, 1 /* successful */, 3 /* dropped */);
}
// CertificateReportingService should drop old reports from its pending report
// queue, if the queue is full.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
DropOldReportsFromQueue) {
SetExpectedHistogramCountOnTeardown(7);
base::SimpleTestClock clock;
base::Time reference_time = base::Time::Now();
clock.SetNow(reference_time);
factory()->SetClockForTesting(&clock);
// The service should queue a maximum of 3 reports and ignore reports older
// than 24 hours.
factory()->SetQueuedReportTTLForTesting(base::TimeDelta::FromHours(24));
factory()->SetMaxQueuedReportCountForTesting(3);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports fail.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL);
// Trigger a failed report.
SendReport("report0");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report0", RetryStatus::NOT_RETRIED}}));
// Trigger three more reports within five hours of each other. After this:
// report0 is 0 hours after reference time (15 hours old).
// report1 is 5 hours after reference time (10 hours old).
// report2 is 10 hours after reference time (5 hours old).
// report3 is 15 hours after reference time (0 hours old).
clock.Advance(base::TimeDelta::FromHours(5));
SendReport("report1");
clock.Advance(base::TimeDelta::FromHours(5));
SendReport("report2");
clock.Advance(base::TimeDelta::FromHours(5));
SendReport("report3");
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::NOT_RETRIED},
{"report2", RetryStatus::NOT_RETRIED},
{"report3", RetryStatus::NOT_RETRIED}}));
// Send pending reports. Four reports were generated above, but the service
// only queues three reports, so report0 should be dropped since it's the
// oldest.
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Failed({{"report1", RetryStatus::RETRIED},
{"report2", RetryStatus::RETRIED},
{"report3", RetryStatus::RETRIED}}));
// Let all reports succeed.
test_helper()->SetFailureMode(certificate_reporting_test_utils::
ReportSendingResult::REPORTS_SUCCESSFUL);
// Advance the clock 15 hours. Current time is now 30 hours after reference
// time, and the ages of reports are now as follows:
// report1 is 25 hours old.
// report2 is 20 hours old.
// report3 is 15 hours old.
clock.Advance(base::TimeDelta::FromHours(15));
// Send pending reports. Only reports 2 and 3 should be sent, report 1
// should be ignored because it's too old.
SendPendingReports();
test_helper()->WaitForRequestsDestroyed(ReportExpectation::Successful(
{{"report2", RetryStatus::RETRIED}, {"report3", RetryStatus::RETRIED}}));
WaitForNoReports();
// report0 was submitted once, failed once, dropped once.
// report1 was submitted twice, failed twice, dropped once.
// report2 was submitted thrice, failed twice, succeeded once.
// report3 was submitted thrice, failed twice, succeeded once.
event_histogram_tester()->SetExpectedValues(
9 /* submitted */, 7 /* failed */, 2 /* successful */, 2 /* dropped */);
}
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
Delayed_Resumed) {
SetExpectedHistogramCountOnTeardown(0);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports hang.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY);
// Trigger a report that hangs.
SendReport("report0");
test_helper()->WaitForRequestsCreated(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
// Resume the report upload. The report upload should successfully complete.
// The interceptor only observes request creations and not response
// completions, so there is nothing to observe.
test_helper()->ResumeDelayedRequest();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
WaitForNoReports();
// report0 was submitted once and succeeded once.
event_histogram_tester()->SetExpectedValues(
1 /* submitted */, 0 /* failed */, 1 /* successful */, 0 /* dropped */);
}
// Same as above, but the service is shut down before resuming the delayed
// request. Should not crash.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest,
Delayed_Resumed_ServiceShutdown) {
SetExpectedHistogramCountOnTeardown(0);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports hang.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY);
// Trigger a report that hangs.
SendReport("report0");
test_helper()->WaitForRequestsCreated(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
// Shutdown the service and resume the report upload. Shouldn't crash.
service()->Shutdown();
test_helper()->ResumeDelayedRequest();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
// report0 was submitted once and never completed since the service shut down.
event_histogram_tester()->SetExpectedValues(
1 /* submitted */, 0 /* failed */, 0 /* successful */, 0 /* dropped */);
}
// Trigger a delayed report, then disable Safebrowsing. Certificate reporting
// service should clear its in-flight reports list.
IN_PROC_BROWSER_TEST_P(CertificateReportingServiceBrowserTest, Delayed_Reset) {
SetExpectedHistogramCountOnTeardown(0);
certificate_reporting_test_utils::SetCertReportingOptIn(
browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN);
// Let all reports hang.
test_helper()->SetFailureMode(
certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY);
// Trigger a report that hangs.
SendReport("report0");
test_helper()->WaitForRequestsCreated(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
// Disable SafeBrowsing. This should clear all pending reports.
ToggleSafeBrowsingAndWaitForServiceReset(false);
// In production, the request would have already went out to the network. For
// this test, we manually resume it which will cause it to be cancelled.
test_helper()->ResumeDelayedRequest();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Delayed({{"report0", RetryStatus::NOT_RETRIED}}));
// Resume delayed report. No response should be observed since all pending
// reports should be cleared.
test_helper()->ResumeDelayedRequest();
test_helper()->ExpectNoRequests(service());
// Re-enable SafeBrowsing.
ToggleSafeBrowsingAndWaitForServiceReset(true);
// Trigger a report that hangs.
SendReport("report1");
test_helper()->WaitForRequestsCreated(
ReportExpectation::Delayed({{"report1", RetryStatus::NOT_RETRIED}}));
// Resume the delayed report and wait for it to complete.
test_helper()->ResumeDelayedRequest();
test_helper()->WaitForRequestsDestroyed(
ReportExpectation::Delayed({{"report1", RetryStatus::NOT_RETRIED}}));
WaitForNoReports();
// report0 was submitted once and delayed, then cleared.
// report1 was submitted once and delayed, then succeeded.
event_histogram_tester()->SetExpectedValues(
2 /* submitted */, 0 /* failed */, 1 /* successful */, 0 /* dropped */);
}
} // namespace safe_browsing