Commit d271f4b2 authored by Sorin Jianu's avatar Sorin Jianu Committed by Commit Bot

Implements Pause/Resume for the URLRequestPostInterceptor.

This allows for temporarily stopping the network so that
update engine tasks can be deterministically cancelled in a unit test.

Bug: 822990
Change-Id: I8d9cf5676c2f1d3211fe392e130eb48052307605
Reviewed-on: https://chromium-review.googlesource.com/998737Reviewed-by: default avatarJoshua Pawlicki <waffles@chromium.org>
Commit-Queue: Sorin Jianu <sorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548592}
parent 80f51807
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/version.h" #include "base/version.h"
...@@ -898,4 +899,36 @@ TEST_F(UpdateCheckerTest, NoUpdateActionRun) { ...@@ -898,4 +899,36 @@ TEST_F(UpdateCheckerTest, NoUpdateActionRun) {
EXPECT_STREQ("this", component->action_run_.c_str()); EXPECT_STREQ("this", component->action_run_.c_str());
} }
TEST_F(UpdateCheckerTest, UpdatePauseResume) {
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
post_interceptor_->url_job_request_ready_callback(base::BindOnce(
[](scoped_refptr<URLRequestPostInterceptor> post_interceptor) {
post_interceptor->Resume();
},
post_interceptor_));
post_interceptor_->Pause();
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
IdToComponentPtrMap components;
components[kUpdateItemId] = MakeComponent();
update_checker_->CheckForUpdates(
update_context_->session_id, std::vector<std::string>{kUpdateItemId},
components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
const auto request = post_interceptor_->GetRequestBody(0);
EXPECT_NE(string::npos,
request.find(std::string("<app appid=\"") + kUpdateItemId +
"\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
"<updatecheck/><ping r=\"-2\" "));
EXPECT_NE(string::npos,
request.find("<packages><package fp=\"fp1\"/></packages></app>"));
}
} // namespace update_client } // namespace update_client
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include "base/bind.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
...@@ -24,16 +25,25 @@ ...@@ -24,16 +25,25 @@
namespace update_client { namespace update_client {
// Returns a canned response. // Returns a canned response.
class URLRequestMockJob : public net::URLRequestSimpleJob { class URLRequestPostInterceptor::URLRequestMockJob
: public net::URLRequestSimpleJob {
public: public:
URLRequestMockJob(net::URLRequest* request, URLRequestMockJob(scoped_refptr<URLRequestPostInterceptor> interceptor,
net::URLRequest* request,
net::NetworkDelegate* network_delegate, net::NetworkDelegate* network_delegate,
int response_code, int response_code,
const std::string& response_body) const std::string& response_body)
: net::URLRequestSimpleJob(request, network_delegate), : net::URLRequestSimpleJob(request, network_delegate),
interceptor_(interceptor),
response_code_(response_code), response_code_(response_code),
response_body_(response_body) {} response_body_(response_body) {}
void Start() override {
if (interceptor_->is_paused_)
return;
net::URLRequestSimpleJob::Start();
}
protected: protected:
void GetResponseInfo(net::HttpResponseInfo* info) override { void GetResponseInfo(net::HttpResponseInfo* info) override {
const std::string headers = const std::string headers =
...@@ -55,6 +65,8 @@ class URLRequestMockJob : public net::URLRequestSimpleJob { ...@@ -55,6 +65,8 @@ class URLRequestMockJob : public net::URLRequestSimpleJob {
private: private:
~URLRequestMockJob() override {} ~URLRequestMockJob() override {}
scoped_refptr<URLRequestPostInterceptor> interceptor_;
int response_code_; int response_code_;
std::string response_body_; std::string response_body_;
DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob); DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob);
...@@ -138,6 +150,25 @@ void URLRequestPostInterceptor::Reset() { ...@@ -138,6 +150,25 @@ void URLRequestPostInterceptor::Reset() {
base::queue<Expectation>().swap(expectations_); base::queue<Expectation>().swap(expectations_);
} }
void URLRequestPostInterceptor::Pause() {
base::AutoLock auto_lock(interceptor_lock_);
is_paused_ = true;
}
void URLRequestPostInterceptor::Resume() {
base::AutoLock auto_lock(interceptor_lock_);
is_paused_ = false;
io_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&URLRequestMockJob::Start,
base::Unretained(request_job_)));
}
void URLRequestPostInterceptor::url_job_request_ready_callback(
UrlJobRequestReadyCallback url_job_request_ready_callback) {
base::AutoLock auto_lock(interceptor_lock_);
url_job_request_ready_callback_ = std::move(url_job_request_ready_callback);
}
class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor {
public: public:
Delegate(const std::string& scheme, Delegate(const std::string& scheme,
...@@ -214,8 +245,15 @@ class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { ...@@ -214,8 +245,15 @@ class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor {
const std::string response_body(expectation.second.response_body); const std::string response_body(expectation.second.response_body);
interceptor->expectations_.pop(); interceptor->expectations_.pop();
++interceptor->hit_count_; ++interceptor->hit_count_;
return new URLRequestMockJob(request, network_delegate, response_code, interceptor->request_job_ =
response_body); new URLRequestMockJob(interceptor, request, network_delegate,
response_code, response_body);
if (interceptor->url_job_request_ready_callback_) {
io_task_runner_->PostTask(
FROM_HERE,
std::move(interceptor->url_job_request_ready_callback_));
}
return interceptor->request_job_;
} }
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/callback.h"
#include "base/containers/queue.h" #include "base/containers/queue.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
...@@ -29,6 +30,8 @@ class HttpRequestHeaders; ...@@ -29,6 +30,8 @@ class HttpRequestHeaders;
namespace update_client { namespace update_client {
class URLRequestMockJob;
// Intercepts requests to a file path, counts them, and captures the body of // Intercepts requests to a file path, counts them, and captures the body of
// the requests. Optionally, for each request, it can return a canned response // the requests. Optionally, for each request, it can return a canned response
// from a given file. The class maintains a queue of expectations, and returns // from a given file. The class maintains a queue of expectations, and returns
...@@ -38,6 +41,11 @@ class URLRequestPostInterceptor ...@@ -38,6 +41,11 @@ class URLRequestPostInterceptor
: public base::RefCountedThreadSafe<URLRequestPostInterceptor> { : public base::RefCountedThreadSafe<URLRequestPostInterceptor> {
public: public:
using InterceptedRequest = std::pair<std::string, net::HttpRequestHeaders>; using InterceptedRequest = std::pair<std::string, net::HttpRequestHeaders>;
// Called when the job associated with the url request which is intercepted
// by this object has been created.
using UrlJobRequestReadyCallback = base::OnceCallback<void()>;
// Allows a generic string maching interface when setting up expectations. // Allows a generic string maching interface when setting up expectations.
class RequestMatcher { class RequestMatcher {
public: public:
...@@ -79,9 +87,26 @@ class URLRequestPostInterceptor ...@@ -79,9 +87,26 @@ class URLRequestPostInterceptor
// Resets the state of the interceptor so that new expectations can be set. // Resets the state of the interceptor so that new expectations can be set.
void Reset(); void Reset();
class Delegate; // Prevents the intercepted request from starting, as a way to simulate
// the effects of a very slow network. Call this function before the actual
// network request occurs.
void Pause();
// Allows a previously paused request to continue.
void Resume();
// Sets a callback to be invoked when the request job associated with
// an intercepted request is created. This allows the test execution to
// synchronize with network tasks running on the IO thread and avoid polling
// using idle run loops. A paused request can be resumed after this callback
// has been invoked.
void url_job_request_ready_callback(
UrlJobRequestReadyCallback url_job_request_ready_callback);
private: private:
class Delegate;
class URLRequestMockJob;
friend class URLRequestPostInterceptorFactory; friend class URLRequestPostInterceptorFactory;
friend class base::RefCountedThreadSafe<URLRequestPostInterceptor>; friend class base::RefCountedThreadSafe<URLRequestPostInterceptor>;
...@@ -118,6 +143,12 @@ class URLRequestPostInterceptor ...@@ -118,6 +143,12 @@ class URLRequestPostInterceptor
// Contains the expectations which this interceptor tries to match. // Contains the expectations which this interceptor tries to match.
base::queue<Expectation> expectations_; base::queue<Expectation> expectations_;
URLRequestMockJob* request_job_ = nullptr;
bool is_paused_ = false;
UrlJobRequestReadyCallback url_job_request_ready_callback_;
DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor); DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor);
}; };
......
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