Commit ba3bd9c5 authored by meacer's avatar meacer Committed by Commit bot

Fix flaky CertificateReportingService browser tests.

CertificateReportingService browser tests wait for the IO thread
after sending a report or resetting the service. This doesn't seem
reliable and the tests occasionally fail. A better approach is to:
- For reports, wait for requests to be destroyed
(CertificateReportingService unit test already does this).
- For service resets, wait for a callback to be called.

This CL does these: It removes WaitForIOThread calls from the browser
test and replaces them with the above. It also refactors the following:
- RequestObserver is shared between browser and unit tests.
- NetworkDelegate is no longer used in the unit tests. RequestObserver is
used instead.
- All tests now expect no URL requests to remain during tear down.
- The code to check expected reports is now shared.

BUG=677560

Review-Url: https://codereview.chromium.org/2605403002
Cr-Commit-Position: refs/heads/master@{#442008}
parent e6f55074
...@@ -167,12 +167,14 @@ CertificateReportingService::CertificateReportingService( ...@@ -167,12 +167,14 @@ CertificateReportingService::CertificateReportingService(
uint32_t server_public_key_version, uint32_t server_public_key_version,
size_t max_queued_report_count, size_t max_queued_report_count,
base::TimeDelta max_report_age, base::TimeDelta max_report_age,
base::Clock* clock) base::Clock* clock,
const base::Callback<void()>& reset_callback)
: pref_service_(*profile->GetPrefs()), : pref_service_(*profile->GetPrefs()),
url_request_context_(nullptr), url_request_context_(nullptr),
max_queued_report_count_(max_queued_report_count), max_queued_report_count_(max_queued_report_count),
max_report_age_(max_report_age), max_report_age_(max_report_age),
clock_(clock), clock_(clock),
reset_callback_(reset_callback),
server_public_key_(server_public_key), server_public_key_(server_public_key),
server_public_key_version_(server_public_key_version) { server_public_key_version_(server_public_key_version) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -188,12 +190,13 @@ CertificateReportingService::CertificateReportingService( ...@@ -188,12 +190,13 @@ CertificateReportingService::CertificateReportingService(
base::Bind(&CertificateReportingService::OnPreferenceChanged, base::Bind(&CertificateReportingService::OnPreferenceChanged,
base::Unretained(this))); base::Unretained(this)));
content::BrowserThread::PostTask( content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::Bind(&CertificateReportingService::InitializeOnIOThread, base::Bind(&CertificateReportingService::InitializeOnIOThread,
base::Unretained(this), true, url_request_context_getter, base::Unretained(this), true, url_request_context_getter,
max_queued_report_count_, max_report_age_, clock_, max_queued_report_count_, max_report_age_, clock_,
server_public_key_, server_public_key_version_)); server_public_key_, server_public_key_version_),
reset_callback_);
} }
CertificateReportingService::~CertificateReportingService() { CertificateReportingService::~CertificateReportingService() {
...@@ -253,12 +256,13 @@ void CertificateReportingService::SetEnabled(bool enabled) { ...@@ -253,12 +256,13 @@ void CertificateReportingService::SetEnabled(bool enabled) {
if (!url_request_context_) if (!url_request_context_)
return; return;
content::BrowserThread::PostTask( content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::Bind(&CertificateReportingService::ResetOnIOThread, base::Bind(&CertificateReportingService::ResetOnIOThread,
base::Unretained(this), enabled, url_request_context_, base::Unretained(this), enabled, url_request_context_,
max_queued_report_count_, max_report_age_, clock_, max_queued_report_count_, max_report_age_, clock_,
server_public_key_, server_public_key_version_)); server_public_key_, server_public_key_version_),
reset_callback_);
} }
CertificateReportingService::Reporter* CertificateReportingService::Reporter*
......
...@@ -152,7 +152,8 @@ class CertificateReportingService : public KeyedService { ...@@ -152,7 +152,8 @@ class CertificateReportingService : public KeyedService {
uint32_t server_public_key_version, uint32_t server_public_key_version,
size_t max_queued_report_count, size_t max_queued_report_count,
base::TimeDelta max_report_age, base::TimeDelta max_report_age,
base::Clock* clock); base::Clock* clock,
const base::Callback<void()>& reset_callback);
~CertificateReportingService() override; ~CertificateReportingService() override;
...@@ -226,6 +227,9 @@ class CertificateReportingService : public KeyedService { ...@@ -226,6 +227,9 @@ class CertificateReportingService : public KeyedService {
base::Clock* const clock_; base::Clock* const clock_;
// Called when the service is reset. Used for testing.
base::Callback<void()> reset_callback_;
// Encryption parameters. // Encryption parameters.
uint8_t* server_public_key_; uint8_t* server_public_key_;
uint32_t server_public_key_version_; uint32_t server_public_key_version_;
......
...@@ -60,6 +60,11 @@ void CertificateReportingServiceFactory::SetMaxQueuedReportCountForTesting( ...@@ -60,6 +60,11 @@ void CertificateReportingServiceFactory::SetMaxQueuedReportCountForTesting(
max_queued_report_count_ = max_queued_report_count; max_queued_report_count_ = max_queued_report_count;
} }
void CertificateReportingServiceFactory::SetServiceResetCallbackForTesting(
const base::Callback<void()>& service_reset_callback) {
service_reset_callback_ = service_reset_callback;
}
CertificateReportingServiceFactory::CertificateReportingServiceFactory() CertificateReportingServiceFactory::CertificateReportingServiceFactory()
: BrowserContextKeyedServiceFactory( : BrowserContextKeyedServiceFactory(
"cert_reporting::Factory", "cert_reporting::Factory",
...@@ -68,7 +73,8 @@ CertificateReportingServiceFactory::CertificateReportingServiceFactory() ...@@ -68,7 +73,8 @@ CertificateReportingServiceFactory::CertificateReportingServiceFactory()
server_public_key_version_(0), server_public_key_version_(0),
clock_(new base::DefaultClock()), clock_(new base::DefaultClock()),
queued_report_ttl_(base::TimeDelta::FromSeconds(kMaxReportAgeInSeconds)), queued_report_ttl_(base::TimeDelta::FromSeconds(kMaxReportAgeInSeconds)),
max_queued_report_count_(kMaxReportCountInQueue) {} max_queued_report_count_(kMaxReportCountInQueue),
service_reset_callback_(base::Bind(&base::DoNothing)) {}
CertificateReportingServiceFactory::~CertificateReportingServiceFactory() {} CertificateReportingServiceFactory::~CertificateReportingServiceFactory() {}
...@@ -80,7 +86,7 @@ KeyedService* CertificateReportingServiceFactory::BuildServiceInstanceFor( ...@@ -80,7 +86,7 @@ KeyedService* CertificateReportingServiceFactory::BuildServiceInstanceFor(
safe_browsing_service, safe_browsing_service->url_request_context(), safe_browsing_service, safe_browsing_service->url_request_context(),
static_cast<Profile*>(profile), server_public_key_, static_cast<Profile*>(profile), server_public_key_,
server_public_key_version_, max_queued_report_count_, queued_report_ttl_, server_public_key_version_, max_queued_report_count_, queued_report_ttl_,
clock_.get()); clock_.get(), service_reset_callback_);
} }
content::BrowserContext* content::BrowserContext*
......
...@@ -30,6 +30,8 @@ class CertificateReportingServiceFactory ...@@ -30,6 +30,8 @@ class CertificateReportingServiceFactory
void SetClockForTesting(std::unique_ptr<base::Clock> clock); void SetClockForTesting(std::unique_ptr<base::Clock> clock);
void SetQueuedReportTTLForTesting(base::TimeDelta queued_report_ttl); void SetQueuedReportTTLForTesting(base::TimeDelta queued_report_ttl);
void SetMaxQueuedReportCountForTesting(size_t max_report_count); void SetMaxQueuedReportCountForTesting(size_t max_report_count);
void SetServiceResetCallbackForTesting(
const base::Callback<void()>& service_reset_callback);
private: private:
friend struct base::DefaultSingletonTraits< friend struct base::DefaultSingletonTraits<
...@@ -51,6 +53,7 @@ class CertificateReportingServiceFactory ...@@ -51,6 +53,7 @@ class CertificateReportingServiceFactory
std::unique_ptr<base::Clock> clock_; std::unique_ptr<base::Clock> clock_;
base::TimeDelta queued_report_ttl_; base::TimeDelta queued_report_ttl_;
size_t max_queued_report_count_; size_t max_queued_report_count_;
base::Callback<void()> service_reset_callback_;
DISALLOW_COPY_AND_ASSIGN(CertificateReportingServiceFactory); DISALLOW_COPY_AND_ASSIGN(CertificateReportingServiceFactory);
}; };
......
...@@ -28,7 +28,7 @@ namespace certificate_reporting_test_utils { ...@@ -28,7 +28,7 @@ namespace certificate_reporting_test_utils {
// Example: // Example:
// The following expects report0 and report1 to be successfully sent and their // The following expects report0 and report1 to be successfully sent and their
// URL requests to be deleted: // URL requests to be deleted:
// WaitForRequestDeletions( // WaitForRequestsDestroyed(
// ReportExpectation::Successful("report0, report1")); // ReportExpectation::Successful("report0, report1"));
struct ReportExpectation { struct ReportExpectation {
ReportExpectation(); ReportExpectation();
...@@ -47,23 +47,6 @@ struct ReportExpectation { ...@@ -47,23 +47,6 @@ struct ReportExpectation {
std::set<std::string> delayed_reports; std::set<std::string> delayed_reports;
}; };
// Helper class to wait for a number of events (e.g. request destroyed, report
// observed).
class ReportWaitHelper {
public:
ReportWaitHelper();
~ReportWaitHelper();
// Waits for |num_events_to_wait_for|.
void Wait(int num_events_to_wait_for);
// Must be called when an event is observed.
void OnEvent();
private:
int num_events_to_wait_for_;
int num_received_events_;
std::unique_ptr<base::RunLoop> run_loop_;
};
// Failure mode of the report sending attempts. // Failure mode of the report sending attempts.
enum ReportSendingResult { enum ReportSendingResult {
// Report send attempts should be successful. // Report send attempts should be successful.
...@@ -74,14 +57,51 @@ enum ReportSendingResult { ...@@ -74,14 +57,51 @@ enum ReportSendingResult {
REPORTS_DELAY, REPORTS_DELAY,
}; };
// Helper class to wait for a number of events (e.g. request destroyed, report
// observed).
class RequestObserver {
public:
RequestObserver();
~RequestObserver();
// Waits for |num_request| requests to be created or destroyed, depending on
// whichever one this class observes.
void Wait(unsigned int num_events_to_wait_for);
// Called when a request created or destroyed, depending on whichever one this
// class observes.
void OnRequest(const std::string& serialized_report,
ReportSendingResult report_type);
// These must be called on the UI thread.
const std::set<std::string>& successful_reports() const;
const std::set<std::string>& failed_reports() const;
const std::set<std::string>& delayed_reports() const;
void ClearObservedReports();
private:
unsigned int num_events_to_wait_for_;
unsigned int num_received_events_;
std::unique_ptr<base::RunLoop> run_loop_;
std::set<std::string> successful_reports_;
std::set<std::string> failed_reports_;
std::set<std::string> delayed_reports_;
};
// A URLRequestJob that can be delayed until Resume() is called. Returns an // A URLRequestJob that can be delayed until Resume() is called. Returns an
// empty response. If Resume() is called before a request is made, then the // empty response. If Resume() is called before a request is made, then the
// request will not be delayed. // request will not be delayed. If not delayed, it can return a failed or a
// successful URL request job.
class DelayableCertReportURLRequestJob : public net::URLRequestJob, class DelayableCertReportURLRequestJob : public net::URLRequestJob,
public base::NonThreadSafe { public base::NonThreadSafe {
public: public:
DelayableCertReportURLRequestJob(net::URLRequest* request, DelayableCertReportURLRequestJob(
net::NetworkDelegate* network_delegate); bool delayed,
bool should_fail,
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const base::Callback<void()>& destruction_callback);
~DelayableCertReportURLRequestJob() override; ~DelayableCertReportURLRequestJob() override;
base::WeakPtr<DelayableCertReportURLRequestJob> GetWeakPtr(); base::WeakPtr<DelayableCertReportURLRequestJob> GetWeakPtr();
...@@ -98,8 +118,10 @@ class DelayableCertReportURLRequestJob : public net::URLRequestJob, ...@@ -98,8 +118,10 @@ class DelayableCertReportURLRequestJob : public net::URLRequestJob,
void Resume(); void Resume();
private: private:
bool delayed_ = true; bool delayed_;
bool started_ = false; bool should_fail_;
bool started_;
base::Callback<void()> destruction_callback_;
base::WeakPtrFactory<DelayableCertReportURLRequestJob> weak_factory_; base::WeakPtrFactory<DelayableCertReportURLRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DelayableCertReportURLRequestJob); DISALLOW_COPY_AND_ASSIGN(DelayableCertReportURLRequestJob);
...@@ -122,35 +144,30 @@ class CertReportJobInterceptor : public net::URLRequestInterceptor { ...@@ -122,35 +144,30 @@ class CertReportJobInterceptor : public net::URLRequestInterceptor {
void SetFailureMode(ReportSendingResult expected_report_result); void SetFailureMode(ReportSendingResult expected_report_result);
// Resumes any hanging URL request and runs callback when the request // Resumes any hanging URL request and runs callback when the request
// is resumed (i.e. response starts). Must be called on the UI thread. // is resumed (i.e. response starts). Must be called on the UI thread.
void Resume(const base::Closure& callback); void Resume();
// These must be called on the UI thread.
const std::set<std::string>& successful_reports() const;
const std::set<std::string>& failed_reports() const;
const std::set<std::string>& delayed_reports() const;
void ClearObservedReports();
// Waits for requests for |num_reports| reports to be created. Only used in RequestObserver* request_created_observer() const;
// browser tests. Unit tests wait for requests to be destroyed instead. RequestObserver* request_destroyed_observer() const;
// Must be called on the UI thread.
void WaitForReports(int num_reports);
private: private:
void SetFailureModeOnIOThread(ReportSendingResult expected_report_result); void SetFailureModeOnIOThread(ReportSendingResult expected_report_result);
void ResumeOnIOThread(); void ResumeOnIOThread();
void RequestCreated(const std::string& uploaded_report, void RequestCreated(const std::string& uploaded_report,
ReportSendingResult expected_report_result); ReportSendingResult expected_report_result) const;
void RequestDestructed(const std::string& uploaded_report,
ReportSendingResult expected_report_result) const;
std::set<std::string> successful_reports_; mutable std::set<std::string> successful_reports_;
std::set<std::string> failed_reports_; mutable std::set<std::string> failed_reports_;
std::set<std::string> delayed_reports_; mutable std::set<std::string> delayed_reports_;
ReportSendingResult expected_report_result_; ReportSendingResult expected_report_result_;
// Private key to decrypt certificate reports. // Private key to decrypt certificate reports.
const uint8_t* server_private_key_; const uint8_t* server_private_key_;
ReportWaitHelper wait_helper_; mutable RequestObserver request_created_observer_;
mutable RequestObserver request_destroyed_observer_;
mutable base::WeakPtr<DelayableCertReportURLRequestJob> delayed_request_ = mutable base::WeakPtr<DelayableCertReportURLRequestJob> delayed_request_ =
nullptr; nullptr;
...@@ -159,20 +176,24 @@ class CertReportJobInterceptor : public net::URLRequestInterceptor { ...@@ -159,20 +176,24 @@ class CertReportJobInterceptor : public net::URLRequestInterceptor {
DISALLOW_COPY_AND_ASSIGN(CertReportJobInterceptor); DISALLOW_COPY_AND_ASSIGN(CertReportJobInterceptor);
}; };
// A network delegate used to observe URL request destructions. The tests check // Class to wait for the CertificateReportingService to reset.
// that no outstanding URL request is present during tear down. class CertificateReportingServiceObserver {
class CertificateReportingServiceTestNetworkDelegate
: public net::NetworkDelegateImpl {
public: public:
CertificateReportingServiceTestNetworkDelegate( CertificateReportingServiceObserver();
const base::Callback<void()>& url_request_destroyed_callback); ~CertificateReportingServiceObserver();
~CertificateReportingServiceTestNetworkDelegate() override;
// net::NetworkDelegate method: // Clears the state of the observer. Must be called before waiting each time.
void OnURLRequestDestroyed(net::URLRequest* request) override; void Clear();
// Waits for the service to reset.
void WaitForReset();
// Must be called when the service is reset.
void OnServiceReset();
private: private:
base::Callback<void()> url_request_destroyed_callback_; bool did_reset_ = false;
std::unique_ptr<base::RunLoop> run_loop_;
}; };
// Base class for CertificateReportingService tests. Sets up an interceptor to // Base class for CertificateReportingService tests. Sets up an interceptor to
...@@ -189,14 +210,20 @@ class CertificateReportingServiceTestHelper { ...@@ -189,14 +210,20 @@ class CertificateReportingServiceTestHelper {
// Resumes delayed report request. Failure mode should be REPORTS_DELAY when // Resumes delayed report request. Failure mode should be REPORTS_DELAY when
// calling this method. // calling this method.
void ResumeDelayedRequest(const base::Callback<void()>& callback); void ResumeDelayedRequest();
void WaitForRequestsCreated(const ReportExpectation& expectation);
void WaitForRequestsDestroyed(const ReportExpectation& expectation);
// Checks that all requests are destroyed and that there are no in-flight
// reports in |service|.
void ExpectNoRequests(CertificateReportingService* service);
uint8_t* server_public_key(); uint8_t* server_public_key();
uint32_t server_public_key_version() const; uint32_t server_public_key_version() const;
CertReportJobInterceptor* interceptor() { return url_request_interceptor_; }
private: private:
CertReportJobInterceptor* interceptor() { return url_request_interceptor_; }
void SetUpInterceptorOnIOThread(); void SetUpInterceptorOnIOThread();
CertReportJobInterceptor* url_request_interceptor_; CertReportJobInterceptor* url_request_interceptor_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment