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 @@
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
......@@ -898,4 +899,36 @@ TEST_F(UpdateCheckerTest, NoUpdateActionRun) {
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
......@@ -6,6 +6,7 @@
#include <memory>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
......@@ -24,16 +25,25 @@
namespace update_client {
// Returns a canned response.
class URLRequestMockJob : public net::URLRequestSimpleJob {
class URLRequestPostInterceptor::URLRequestMockJob
: public net::URLRequestSimpleJob {
public:
URLRequestMockJob(net::URLRequest* request,
URLRequestMockJob(scoped_refptr<URLRequestPostInterceptor> interceptor,
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
int response_code,
const std::string& response_body)
: net::URLRequestSimpleJob(request, network_delegate),
interceptor_(interceptor),
response_code_(response_code),
response_body_(response_body) {}
void Start() override {
if (interceptor_->is_paused_)
return;
net::URLRequestSimpleJob::Start();
}
protected:
void GetResponseInfo(net::HttpResponseInfo* info) override {
const std::string headers =
......@@ -55,6 +65,8 @@ class URLRequestMockJob : public net::URLRequestSimpleJob {
private:
~URLRequestMockJob() override {}
scoped_refptr<URLRequestPostInterceptor> interceptor_;
int response_code_;
std::string response_body_;
DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob);
......@@ -138,6 +150,25 @@ void URLRequestPostInterceptor::Reset() {
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 {
public:
Delegate(const std::string& scheme,
......@@ -214,8 +245,15 @@ class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor {
const std::string response_body(expectation.second.response_body);
interceptor->expectations_.pop();
++interceptor->hit_count_;
return new URLRequestMockJob(request, network_delegate, response_code,
response_body);
interceptor->request_job_ =
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 @@
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
......@@ -29,6 +30,8 @@ class HttpRequestHeaders;
namespace update_client {
class URLRequestMockJob;
// 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
// from a given file. The class maintains a queue of expectations, and returns
......@@ -38,6 +41,11 @@ class URLRequestPostInterceptor
: public base::RefCountedThreadSafe<URLRequestPostInterceptor> {
public:
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.
class RequestMatcher {
public:
......@@ -79,9 +87,26 @@ class URLRequestPostInterceptor
// Resets the state of the interceptor so that new expectations can be set.
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:
class Delegate;
class URLRequestMockJob;
friend class URLRequestPostInterceptorFactory;
friend class base::RefCountedThreadSafe<URLRequestPostInterceptor>;
......@@ -118,6 +143,12 @@ class URLRequestPostInterceptor
// Contains the expectations which this interceptor tries to match.
base::queue<Expectation> expectations_;
URLRequestMockJob* request_job_ = nullptr;
bool is_paused_ = false;
UrlJobRequestReadyCallback url_job_request_ready_callback_;
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