blob: 9907f499dd1bcd24dd1c64bf1f8bcdc289d2b731 [file] [log] [blame]
// Copyright 2018 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.
#ifndef COMPONENTS_UPDATE_CLIENT_NET_URL_LOADER_POST_INTERCEPTOR_H_
#define COMPONENTS_UPDATE_CLIENT_NET_URL_LOADER_POST_INTERCEPTOR_H_
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_status_code.h"
#include "url/gurl.h"
namespace network {
class TestURLLoaderFactory;
}
namespace net {
namespace test_server {
class EmbeddedTestServer;
class HttpResponse;
struct HttpRequest;
} // namespace test_server
} // namespace net
namespace update_client {
// 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
// one and only one response for each request that matches the expectation.
// Then, the expectation is removed from the queue.
class URLLoaderPostInterceptor {
public:
using InterceptedRequest =
std::tuple<std::string, net::HttpRequestHeaders, GURL>;
// Called when the load associated with the url request is intercepted
// by this object:.
using UrlJobRequestReadyCallback = base::OnceCallback<void()>;
// Allows a generic string maching interface when setting up expectations.
class RequestMatcher {
public:
virtual bool Match(const std::string& actual) const = 0;
virtual ~RequestMatcher() {}
};
explicit URLLoaderPostInterceptor(
network::TestURLLoaderFactory* url_loader_factory);
URLLoaderPostInterceptor(std::vector<GURL> supported_urls,
network::TestURLLoaderFactory* url_loader_factory);
URLLoaderPostInterceptor(std::vector<GURL> supported_urls,
net::test_server::EmbeddedTestServer*);
~URLLoaderPostInterceptor();
// Sets an expection for the body of the POST request and optionally,
// provides a canned response identified by a |file_path| to be returned when
// the expectation is met. If no |file_path| is provided, then an empty
// response body is served. If |response_code| is provided, then an empty
// response body with that response code is returned.
// Returns |true| if the expectation was set.
bool ExpectRequest(std::unique_ptr<RequestMatcher> request_matcher);
bool ExpectRequest(std::unique_ptr<RequestMatcher> request_matcher,
net::HttpStatusCode response_code);
bool ExpectRequest(std::unique_ptr<RequestMatcher> request_matcher,
const base::FilePath& filepath);
// Returns how many requests have been intercepted and matched by
// an expectation. One expectation can only be matched by one request.
int GetHitCount() const;
// Returns how many requests in total have been captured by the interceptor.
int GetCount() const;
// Returns all requests that have been intercepted, matched or not.
std::vector<InterceptedRequest> GetRequests() const;
// Return the body of the n-th request, zero-based.
std::string GetRequestBody(size_t n) const;
// Returns the joined bodies of all requests for debugging purposes.
std::string GetRequestsAsString() const;
// Resets the state of the interceptor so that new expectations can be set.
void Reset();
// 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);
int GetHitCountForURL(const GURL& url);
private:
void InitializeWithInterceptor();
void InitializeWithRequestHandler();
std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
const net::test_server::HttpRequest& request);
struct ExpectationResponse {
ExpectationResponse(net::HttpStatusCode code, const std::string& body)
: response_code(code), response_body(body) {}
const net::HttpStatusCode response_code;
const std::string response_body;
};
using Expectation =
std::pair<std::unique_ptr<RequestMatcher>, ExpectationResponse>;
using PendingExpectation = std::pair<GURL, ExpectationResponse>;
// Contains the count of the request matching expectations.
int hit_count_ = 0;
// Contains the request body and the extra headers of the intercepted
// requests.
std::vector<InterceptedRequest> requests_;
// Contains the expectations which this interceptor tries to match.
base::queue<Expectation> expectations_;
base::queue<PendingExpectation> pending_expectations_;
network::TestURLLoaderFactory* url_loader_factory_ = nullptr;
net::test_server::EmbeddedTestServer* embedded_test_server_ = nullptr;
bool is_paused_ = false;
std::vector<GURL> filtered_urls_;
UrlJobRequestReadyCallback url_job_request_ready_callback_;
DISALLOW_COPY_AND_ASSIGN(URLLoaderPostInterceptor);
};
class PartialMatch : public URLLoaderPostInterceptor::RequestMatcher {
public:
explicit PartialMatch(const std::string& expected) : expected_(expected) {}
bool Match(const std::string& actual) const override;
private:
const std::string expected_;
DISALLOW_COPY_AND_ASSIGN(PartialMatch);
};
class AnyMatch : public URLLoaderPostInterceptor::RequestMatcher {
public:
AnyMatch() = default;
bool Match(const std::string& actual) const override;
private:
DISALLOW_COPY_AND_ASSIGN(AnyMatch);
};
} // namespace update_client
#endif // COMPONENTS_UPDATE_CLIENT_NET_URL_LOADER_POST_INTERCEPTOR_H_