summaryrefslogtreecommitdiff
path: root/chromium/net/url_request/test_url_fetcher_factory.h
blob: 18360bda6711a8befa6af21d1646a28e310a6fc9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
// Copyright (c) 2012 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 NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_
#define NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_

#include <stdint.h>

#include <list>
#include <map>
#include <string>
#include <utility>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"

namespace net {

// Changes URLFetcher's Factory for the lifetime of the object.
// Note that this scoper cannot be nested (to make it even harder to misuse).
class ScopedURLFetcherFactory : public base::NonThreadSafe {
 public:
  explicit ScopedURLFetcherFactory(URLFetcherFactory* factory);
  virtual ~ScopedURLFetcherFactory();

 private:
  DISALLOW_COPY_AND_ASSIGN(ScopedURLFetcherFactory);
};

// TestURLFetcher and TestURLFetcherFactory are used for testing consumers of
// URLFetcher. TestURLFetcherFactory is a URLFetcherFactory that creates
// TestURLFetchers. TestURLFetcher::Start is overriden to do nothing. It is
// expected that you'll grab the delegate from the TestURLFetcher and invoke
// the callback method when appropriate. In this way it's easy to mock a
// URLFetcher.
// Typical usage:
//   // TestURLFetcher requires a MessageLoop.
//   MessageLoop message_loop;
//   // And an IO thread to release URLRequestContextGetter in URLFetcher::Core.
//   BrowserThreadImpl io_thread(BrowserThread::IO, &message_loop);
//   // Create factory (it automatically sets itself as URLFetcher's factory).
//   TestURLFetcherFactory factory;
//   // Do something that triggers creation of a URLFetcher.
//   ...
//   TestURLFetcher* fetcher = factory.GetFetcherByID(expected_id);
//   DCHECK(fetcher);
//   // Notify delegate with whatever data you want.
//   fetcher->delegate()->OnURLFetchComplete(...);
//   // Make sure consumer of URLFetcher does the right thing.
//   ...
//
// Note: if you don't know when your request objects will be created you
// might want to use the FakeURLFetcher and FakeURLFetcherFactory classes
// below.

class TestURLFetcherFactory;
class TestURLFetcher : public URLFetcher {
 public:
  // Interface for tests to intercept production code classes using URLFetcher.
  // Allows even-driven mock server classes to analyze the correctness of
  // requests / uploads events and forge responses back at the right moment.
  class DelegateForTests {
   public:
    // Callback issued correspondingly to the call to the |Start()| method.
    virtual void OnRequestStart(int fetcher_id) = 0;

    // Callback issued correspondingly to the call to |AppendChunkToUpload|.
    // Uploaded chunks can be retrieved with the |upload_chunks()| getter.
    virtual void OnChunkUpload(int fetcher_id) = 0;

    // Callback issued correspondingly to the destructor.
    virtual void OnRequestEnd(int fetcher_id) = 0;
  };

  TestURLFetcher(int id,
                 const GURL& url,
                 URLFetcherDelegate* d);
  ~TestURLFetcher() override;

  // URLFetcher implementation
  void SetUploadData(const std::string& upload_content_type,
                     const std::string& upload_content) override;
  void SetUploadFilePath(
      const std::string& upload_content_type,
      const base::FilePath& file_path,
      uint64 range_offset,
      uint64 range_length,
      scoped_refptr<base::TaskRunner> file_task_runner) override;
  void SetUploadStreamFactory(
      const std::string& upload_content_type,
      const CreateUploadStreamCallback& callback) override;
  void SetChunkedUpload(const std::string& upload_content_type) override;
  // Overriden to cache the chunks uploaded. Caller can read back the uploaded
  // chunks with the upload_chunks() accessor.
  void AppendChunkToUpload(const std::string& data,
                           bool is_last_chunk) override;
  void SetLoadFlags(int load_flags) override;
  int GetLoadFlags() const override;
  void SetReferrer(const std::string& referrer) override;
  void SetReferrerPolicy(URLRequest::ReferrerPolicy referrer_policy) override;
  void SetExtraRequestHeaders(
      const std::string& extra_request_headers) override;
  void AddExtraRequestHeader(const std::string& header_line) override;
  void SetRequestContext(
      URLRequestContextGetter* request_context_getter) override;
  void SetFirstPartyForCookies(const GURL& first_party_for_cookies) override;
  void SetURLRequestUserData(
      const void* key,
      const CreateDataCallback& create_data_callback) override;
  void SetStopOnRedirect(bool stop_on_redirect) override;
  void SetAutomaticallyRetryOn5xx(bool retry) override;
  void SetMaxRetriesOn5xx(int max_retries) override;
  int GetMaxRetriesOn5xx() const override;
  base::TimeDelta GetBackoffDelay() const override;
  void SetAutomaticallyRetryOnNetworkChanges(int max_retries) override;
  void SaveResponseToFileAtPath(
      const base::FilePath& file_path,
      scoped_refptr<base::SequencedTaskRunner> file_task_runner) override;
  void SaveResponseToTemporaryFile(
      scoped_refptr<base::SequencedTaskRunner> file_task_runner) override;
  void SaveResponseWithWriter(
      scoped_ptr<URLFetcherResponseWriter> response_writer) override;
  HttpResponseHeaders* GetResponseHeaders() const override;
  HostPortPair GetSocketAddress() const override;
  bool WasFetchedViaProxy() const override;
  bool WasCached() const override;
  // Only valid when the response was set via SetResponseString().
  int64_t GetReceivedResponseContentLength() const override;
  // Only valid when the response was set via SetResponseString(), or
  // set_was_cached(true) was called.
  int64_t GetTotalReceivedBytes() const override;
  void Start() override;

  // URL we were created with. Because of how we're using URLFetcher GetURL()
  // always returns an empty URL. Chances are you'll want to use
  // GetOriginalURL() in your tests.
  const GURL& GetOriginalURL() const override;
  const GURL& GetURL() const override;
  const URLRequestStatus& GetStatus() const override;
  int GetResponseCode() const override;
  const ResponseCookies& GetCookies() const override;
  void ReceivedContentWasMalformed() override;
  // Override response access functions to return fake data.
  bool GetResponseAsString(std::string* out_response_string) const override;
  bool GetResponseAsFilePath(bool take_ownership,
                             base::FilePath* out_response_path) const override;

  void GetExtraRequestHeaders(HttpRequestHeaders* headers) const;

  // Sets owner of this class.  Set it to a non-NULL value if you want
  // to automatically unregister this fetcher from the owning factory
  // upon destruction.
  void set_owner(TestURLFetcherFactory* owner) { owner_ = owner; }

  // Unique ID in our factory.
  int id() const { return id_; }

  // Returns the data uploaded on this URLFetcher.
  const std::string& upload_content_type() const {
    return upload_content_type_;
  }
  const std::string& upload_data() const { return upload_data_; }
  const base::FilePath& upload_file_path() const { return upload_file_path_; }

  // Returns the chunks of data uploaded on this URLFetcher.
  const std::list<std::string>& upload_chunks() const { return chunks_; }

  // Checks whether the last call to |AppendChunkToUpload(...)| was final.
  bool did_receive_last_chunk() const { return did_receive_last_chunk_; }

  // Returns the delegate installed on the URLFetcher.
  URLFetcherDelegate* delegate() const { return delegate_; }

  void set_url(const GURL& url) { fake_url_ = url; }
  void set_status(const URLRequestStatus& status);
  void set_response_code(int response_code) {
    fake_response_code_ = response_code;
  }
  void set_cookies(const ResponseCookies& c) { fake_cookies_ = c; }
  void set_was_fetched_via_proxy(bool flag);
  void set_was_cached(bool flag);
  void set_response_headers(scoped_refptr<HttpResponseHeaders> headers);
  void set_backoff_delay(base::TimeDelta backoff_delay);
  void SetDelegateForTests(DelegateForTests* delegate_for_tests);

  // Set string data.
  void SetResponseString(const std::string& response);

  // Set File data.
  void SetResponseFilePath(const base::FilePath& path);

 private:
  enum ResponseDestinationType {
    STRING,  // Default: In a std::string
    TEMP_FILE  // Write to a temp file
  };

  TestURLFetcherFactory* owner_;
  const int id_;
  const GURL original_url_;
  URLFetcherDelegate* delegate_;
  DelegateForTests* delegate_for_tests_;
  std::string upload_content_type_;
  std::string upload_data_;
  base::FilePath upload_file_path_;
  std::list<std::string> chunks_;
  bool did_receive_last_chunk_;

  // User can use set_* methods to provide values returned by getters.
  // Setting the real values is not possible, because the real class
  // has no setters. The data is a private member of a class defined
  // in a .cc file, so we can't get at it with friendship.
  int fake_load_flags_;
  GURL fake_url_;
  URLRequestStatus fake_status_;
  int fake_response_code_;
  ResponseCookies fake_cookies_;
  ResponseDestinationType fake_response_destination_;
  std::string fake_response_string_;
  base::FilePath fake_response_file_path_;
  bool fake_was_fetched_via_proxy_;
  bool fake_was_cached_;
  int64 fake_response_bytes_;
  scoped_refptr<HttpResponseHeaders> fake_response_headers_;
  HttpRequestHeaders fake_extra_request_headers_;
  int fake_max_retries_;
  base::TimeDelta fake_backoff_delay_;
  scoped_ptr<URLFetcherResponseWriter> response_writer_;

  DISALLOW_COPY_AND_ASSIGN(TestURLFetcher);
};

typedef TestURLFetcher::DelegateForTests TestURLFetcherDelegateForTests;

// Simple URLFetcherFactory method that creates TestURLFetchers. All fetchers
// are registered in a map by the id passed to the create method.
// Optionally, a fetcher may be automatically unregistered from the map upon
// its destruction.
class TestURLFetcherFactory : public URLFetcherFactory,
                              public ScopedURLFetcherFactory {
 public:
  TestURLFetcherFactory();
  ~TestURLFetcherFactory() override;

  scoped_ptr<URLFetcher> CreateURLFetcher(int id,
                                          const GURL& url,
                                          URLFetcher::RequestType request_type,
                                          URLFetcherDelegate* d) override;
  TestURLFetcher* GetFetcherByID(int id) const;
  void RemoveFetcherFromMap(int id);
  void SetDelegateForTests(TestURLFetcherDelegateForTests* delegate_for_tests);
  void set_remove_fetcher_on_delete(bool remove_fetcher_on_delete) {
    remove_fetcher_on_delete_ = remove_fetcher_on_delete;
  }

 private:
  // Maps from id passed to create to the returned URLFetcher.
  typedef std::map<int, TestURLFetcher*> Fetchers;
  Fetchers fetchers_;
  TestURLFetcherDelegateForTests* delegate_for_tests_;
  // Whether to automatically unregister a fetcher from this factory upon its
  // destruction, false by default.
  bool remove_fetcher_on_delete_;

  DISALLOW_COPY_AND_ASSIGN(TestURLFetcherFactory);
};

// The FakeURLFetcher and FakeURLFetcherFactory classes are similar to the
// ones above but don't require you to know when exactly the URLFetcher objects
// will be created.
//
// These classes let you set pre-baked HTTP responses for particular URLs.
// E.g., if the user requests http://a.com/ then respond with an HTTP/500.
//
// We assume that the thread that is calling Start() on the URLFetcher object
// has a message loop running.

// FakeURLFetcher can be used to create a URLFetcher that will emit a fake
// response when started. This class can be used in place of an actual
// URLFetcher.
//
// Example usage:
//  FakeURLFetcher fake_fetcher("http://a.com", some_delegate,
//                              "<html><body>hello world</body></html>",
//                              HTTP_OK);
//
// // Will schedule a call to some_delegate->OnURLFetchComplete(&fake_fetcher).
// fake_fetcher.Start();
class FakeURLFetcher : public TestURLFetcher {
 public:
  // Normal URL fetcher constructor but also takes in a pre-baked response.
  FakeURLFetcher(const GURL& url,
                 URLFetcherDelegate* d,
                 const std::string& response_data,
                 HttpStatusCode response_code,
                 URLRequestStatus::Status status);

  // Start the request.  This will call the given delegate asynchronously
  // with the pre-baked response as parameter.
  void Start() override;

  const GURL& GetURL() const override;

  ~FakeURLFetcher() override;

 private:
  // This is the method which actually calls the delegate that is passed in the
  // constructor.
  void RunDelegate();

  int64_t response_bytes_;
  base::WeakPtrFactory<FakeURLFetcher> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(FakeURLFetcher);
};


// FakeURLFetcherFactory is a factory for FakeURLFetcher objects. When
// instantiated, it sets itself up as the default URLFetcherFactory. Fake
// responses for given URLs can be set using SetFakeResponse.
//
// This class is not thread-safe.  You should not call SetFakeResponse or
// ClearFakeResponse at the same time you call CreateURLFetcher.  However, it is
// OK to start URLFetcher objects while setting or clearing fake responses
// since already created URLFetcher objects will not be affected by any changes
// made to the fake responses (once a URLFetcher object is created you cannot
// change its fake response).
//
// Example usage:
//  FakeURLFetcherFactory factory;
//
//  // You know that class SomeService will request http://a.com/success and you
//  // want to respond with a simple html page and an HTTP/200 code.
//  factory.SetFakeResponse("http://a.com/success",
//                          "<html><body>hello world</body></html>",
//                          HTTP_OK,
//                          URLRequestStatus::SUCCESS);
//  // You know that class SomeService will request url http://a.com/servererror
//  // and you want to test the service class by returning a server error.
//  factory.SetFakeResponse("http://a.com/servererror",
//                          "",
//                          HTTP_INTERNAL_SERVER_ERROR,
//                          URLRequestStatus::SUCCESS);
//  // You know that class SomeService will request url http://a.com/autherror
//  // and you want to test the service class by returning a specific error
//  // code, say, a HTTP/401 error.
//  factory.SetFakeResponse("http://a.com/autherror",
//                          "some_response",
//                          HTTP_UNAUTHORIZED,
//                          URLRequestStatus::SUCCESS);
//
//  // You know that class SomeService will request url http://a.com/failure
//  // and you want to test the service class by returning a failure in the
//  // network layer.
//  factory.SetFakeResponse("http://a.com/failure",
//                          "",
//                          HTTP_INTERNAL_SERVER_ERROR,
//                          URLRequestStatus::FAILURE);
//
//  SomeService service;
//  service.Run();  // Will eventually request these three URLs.
class FakeURLFetcherFactory : public URLFetcherFactory,
                              public ScopedURLFetcherFactory {
 public:
  // Parameters to FakeURLFetcherCreator: url, delegate, response_data,
  //                                      response_code
  // |url| URL for instantiated FakeURLFetcher
  // |delegate| Delegate for FakeURLFetcher
  // |response_data| response data for FakeURLFetcher
  // |response_code| response code for FakeURLFetcher
  // |status| URL fetch status for FakeURLFetcher
  // These arguments should by default be used in instantiating FakeURLFetcher
  // like so:
  // new FakeURLFetcher(url, delegate, response_data, response_code, status)
  typedef base::Callback<scoped_ptr<FakeURLFetcher>(
      const GURL&,
      URLFetcherDelegate*,
      const std::string&,
      HttpStatusCode,
      URLRequestStatus::Status)> FakeURLFetcherCreator;

  // |default_factory|, which can be NULL, is a URLFetcherFactory that
  // will be used to construct a URLFetcher in case the URL being created
  // has no pre-baked response. If it is NULL, a URLFetcherImpl will be
  // created in this case.
  explicit FakeURLFetcherFactory(URLFetcherFactory* default_factory);

  // |default_factory|, which can be NULL, is a URLFetcherFactory that
  // will be used to construct a URLFetcher in case the URL being created
  // has no pre-baked response. If it is NULL, a URLFetcherImpl will be
  // created in this case.
  // |creator| is a callback that returns will be called to create a
  // FakeURLFetcher if a response is found to a given URL. It can be
  // set to MakeFakeURLFetcher.
  FakeURLFetcherFactory(URLFetcherFactory* default_factory,
                        const FakeURLFetcherCreator& creator);

  ~FakeURLFetcherFactory() override;

  // If no fake response is set for the given URL this method will delegate the
  // call to |default_factory_| if it is not NULL, or return NULL if it is
  // NULL.
  // Otherwise, it will return a URLFetcher object which will respond with the
  // pre-baked response that the client has set by calling SetFakeResponse().
  scoped_ptr<URLFetcher> CreateURLFetcher(int id,
                                          const GURL& url,
                                          URLFetcher::RequestType request_type,
                                          URLFetcherDelegate* d) override;

  // Sets the fake response for a given URL. The |response_data| may be empty.
  // The |response_code| may be any HttpStatusCode. For instance, HTTP_OK will
  // return an HTTP/200 and HTTP_INTERNAL_SERVER_ERROR will return an HTTP/500.
  // The |status| argument may be any URLRequestStatus::Status value. Typically,
  // requests that return a valid HttpStatusCode have the SUCCESS status, while
  // requests that indicate a failure to connect to the server have the FAILED
  // status.
  void SetFakeResponse(const GURL& url,
                       const std::string& response_data,
                       HttpStatusCode response_code,
                       URLRequestStatus::Status status);

  // Clear all the fake responses that were previously set via
  // SetFakeResponse().
  void ClearFakeResponses();

 private:
  struct FakeURLResponse {
    std::string response_data;
    HttpStatusCode response_code;
    URLRequestStatus::Status status;
  };
  typedef std::map<GURL, FakeURLResponse> FakeResponseMap;

  const FakeURLFetcherCreator creator_;
  FakeResponseMap fake_responses_;
  URLFetcherFactory* const default_factory_;

  static scoped_ptr<FakeURLFetcher> DefaultFakeURLFetcherCreator(
      const GURL& url,
      URLFetcherDelegate* delegate,
      const std::string& response_data,
      HttpStatusCode response_code,
      URLRequestStatus::Status status);
  DISALLOW_COPY_AND_ASSIGN(FakeURLFetcherFactory);
};

// This is an implementation of URLFetcherFactory that will create a
// URLFetcherImpl. It can be use in conjunction with a FakeURLFetcherFactory in
// integration tests to control the behavior of some requests but execute
// all the other ones.
class URLFetcherImplFactory : public URLFetcherFactory {
 public:
  URLFetcherImplFactory();
  ~URLFetcherImplFactory() override;

  // This method will create a real URLFetcher.
  scoped_ptr<URLFetcher> CreateURLFetcher(int id,
                                          const GURL& url,
                                          URLFetcher::RequestType request_type,
                                          URLFetcherDelegate* d) override;
};

}  // namespace net

#endif  // NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_