| // 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 SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ |
| #define SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include "base/macros.h" |
| #include "mojo/public/cpp/bindings/binding_set.h" |
| #include "net/http/http_status_code.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| |
| namespace network { |
| |
| // A helper class to ease testing code that uses URLLoader interface. A test |
| // would pass this factory instead of the production factory to code, and |
| // would prime it with response data for arbitrary URLs. |
| class TestURLLoaderFactory : public mojom::URLLoaderFactory { |
| public: |
| struct PendingRequest { |
| PendingRequest(); |
| ~PendingRequest(); |
| PendingRequest(PendingRequest&& other); |
| PendingRequest& operator=(PendingRequest&& other); |
| |
| mojom::URLLoaderClientPtr client; |
| ResourceRequest request; |
| }; |
| |
| // Bitfield that is used with |SimulateResponseForPendingRequest()|. |
| enum SimulateResponseFlags : uint32_t { |
| kDefault = 0x0, |
| kUrlMatchPrefix = 0x1, // Whether URLs are a match if they start with the |
| // URL passed in to |
| // SimulateResponseForPendingRequest |
| kMostRecentMatch = 0x2, // Start with the most recent requests. |
| }; |
| |
| TestURLLoaderFactory(); |
| ~TestURLLoaderFactory() override; |
| |
| using Redirects = |
| std::vector<std::pair<net::RedirectInfo, ResourceResponseHead>>; |
| |
| // Adds a response to be served. There is one unique response per URL, and if |
| // this method is called multiple times for the same URL the last response |
| // data is used. |
| // This can be called before or after a request is made. If it's called after, |
| // then pending requests will be "woken up". |
| void AddResponse(const GURL& url, |
| const ResourceResponseHead& head, |
| const std::string& content, |
| const URLLoaderCompletionStatus& status, |
| const Redirects& redirects = Redirects()); |
| |
| // Simpler version of above for the common case of success or error page. |
| void AddResponse(const std::string& url, |
| const std::string& content, |
| net::HttpStatusCode status = net::HTTP_OK); |
| |
| // Returns true if there is a request for a given URL with a living client |
| // that did not produce a response yet. If |load_flags_out| is non-null, |
| // it will reports load flags used for the request |
| // WARNING: This does RunUntilIdle() first. |
| bool IsPending(const std::string& url, int* load_flags_out = nullptr); |
| |
| // Returns the total # of pending requests. |
| // WARNING: This does RunUntilIdle() first. |
| int NumPending(); |
| |
| // Clear all the responses that were previously set. |
| void ClearResponses(); |
| |
| using Interceptor = base::RepeatingCallback<void(const ResourceRequest&)>; |
| void SetInterceptor(const Interceptor& interceptor); |
| |
| // Returns a mutable list of pending requests, for consumers that need direct |
| // access. It's recommended that consumers use AddResponse() rather than |
| // servicing requests themselves, whenever possible. |
| std::vector<PendingRequest>* pending_requests() { return &pending_requests_; } |
| |
| // Sends a response for the first (oldest) pending request with URL |url|. |
| // Returns false if no such pending request exists. |
| // |flags| can be used to change the default behavior: |
| // - if kUrlMatchPrefix is set, the pending request is a match if its URL |
| // starts with |url| (instead of being equal to |url|). |
| // - if kMostRecentMatch is set, the most recent (instead of oldest) pending |
| // request matching is used. |
| bool SimulateResponseForPendingRequest( |
| const GURL& url, |
| const network::URLLoaderCompletionStatus& completion_status, |
| const ResourceResponseHead& response_head, |
| const std::string& content, |
| SimulateResponseFlags flags = kDefault); |
| |
| // Sends a response for the given request |request|. |
| // |
| // Differently from its variant above, this method does not remove |request| |
| // from |pending_requests_|. |
| // |
| // This method is useful to process requests at a given pre-defined order. |
| void SimulateResponseWithoutRemovingFromPendingList( |
| PendingRequest* request, |
| const ResourceResponseHead& head, |
| std::string content, |
| const URLLoaderCompletionStatus& status); |
| |
| // Simpler version of the method above. |
| void SimulateResponseWithoutRemovingFromPendingList(PendingRequest* request, |
| std::string content); |
| |
| // mojom::URLLoaderFactory implementation. |
| void CreateLoaderAndStart(mojom::URLLoaderRequest request, |
| int32_t routing_id, |
| int32_t request_id, |
| uint32_t options, |
| const ResourceRequest& url_request, |
| mojom::URLLoaderClientPtr client, |
| const net::MutableNetworkTrafficAnnotationTag& |
| traffic_annotation) override; |
| void Clone(mojom::URLLoaderFactoryRequest request) override; |
| |
| private: |
| bool CreateLoaderAndStartInternal(const GURL& url, |
| mojom::URLLoaderClient* client); |
| |
| static void SimulateResponse(mojom::URLLoaderClient* client, |
| Redirects redirects, |
| ResourceResponseHead head, |
| std::string content, |
| URLLoaderCompletionStatus status); |
| |
| struct Response { |
| Response(); |
| ~Response(); |
| Response(const Response&); |
| GURL url; |
| Redirects redirects; |
| ResourceResponseHead head; |
| std::string content; |
| URLLoaderCompletionStatus status; |
| }; |
| std::map<GURL, Response> responses_; |
| |
| std::vector<PendingRequest> pending_requests_; |
| |
| Interceptor interceptor_; |
| mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory); |
| }; |
| |
| } // namespace network |
| |
| #endif // SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ |