summaryrefslogtreecommitdiff
path: root/chromium/net/http/mock_http_cache.h
blob: 6b2af24e8ff10a909bf2a6bc49c293b0e91b8eee (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
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is a mock of the http cache and related testing classes. To be fair, it
// is not really a mock http cache given that it uses the real implementation of
// the http cache, but it has fake implementations of all required components,
// so it is useful for unit tests at the http layer.

#ifndef NET_HTTP_MOCK_HTTP_CACHE_H_
#define NET_HTTP_MOCK_HTTP_CACHE_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/strings/string_split.h"
#include "net/base/completion_once_callback.h"
#include "net/base/request_priority.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/http/http_transaction_test_util.h"

namespace net {

//-----------------------------------------------------------------------------
// Mock disk cache (a very basic memory cache implementation).

class MockDiskEntry : public disk_cache::Entry,
                      public base::RefCounted<MockDiskEntry> {
 public:
  enum DeferOp {
    DEFER_NONE,
    DEFER_CREATE,
    DEFER_READ,
    DEFER_WRITE,
  };

  // Bit mask used for set_fail_requests().
  enum FailOp {
    FAIL_READ = 0x01,
    FAIL_WRITE = 0x02,
    FAIL_READ_SPARSE = 0x04,
    FAIL_WRITE_SPARSE = 0x08,
    FAIL_GET_AVAILABLE_RANGE = 0x10,
    FAIL_ALL = 0xFF
  };

  explicit MockDiskEntry(const std::string& key);

  bool is_doomed() const { return doomed_; }

  void Doom() override;
  void Close() override;
  std::string GetKey() const override;
  base::Time GetLastUsed() const override;
  base::Time GetLastModified() const override;
  int32_t GetDataSize(int index) const override;
  int ReadData(int index,
               int offset,
               IOBuffer* buf,
               int buf_len,
               CompletionOnceCallback callback) override;
  int WriteData(int index,
                int offset,
                IOBuffer* buf,
                int buf_len,
                CompletionOnceCallback callback,
                bool truncate) override;
  int ReadSparseData(int64_t offset,
                     IOBuffer* buf,
                     int buf_len,
                     CompletionOnceCallback callback) override;
  int WriteSparseData(int64_t offset,
                      IOBuffer* buf,
                      int buf_len,
                      CompletionOnceCallback callback) override;
  RangeResult GetAvailableRange(int64_t offset,
                                int len,
                                RangeResultCallback callback) override;
  bool CouldBeSparse() const override;
  void CancelSparseIO() override;
  net::Error ReadyForSparseIO(
      CompletionOnceCallback completion_callback) override;
  void SetLastUsedTimeForTest(base::Time time) override;

  uint8_t in_memory_data() const { return in_memory_data_; }
  void set_in_memory_data(uint8_t val) { in_memory_data_ = val; }

  // Fail subsequent requests, specified via FailOp bits.
  void set_fail_requests(int mask) { fail_requests_ = mask; }

  void set_fail_sparse_requests() { fail_sparse_requests_ = true; }

  // If |value| is true, don't deliver any completion callbacks until called
  // again with |value| set to false.  Caution: remember to enable callbacks
  // again or all subsequent tests will fail.
  static void IgnoreCallbacks(bool value);

  // Defers invoking the callback for the given operation. Calling code should
  // invoke ResumeDiskEntryOperation to resume.
  void SetDefer(DeferOp defer_op) { defer_op_ = defer_op; }

  // Resumes deferred cache operation by posting |resume_callback_| with
  // |resume_return_code_|.
  void ResumeDiskEntryOperation();

  // Sets the maximum length of a stream. This is only applied to stream 1.
  void set_max_file_size(int val) { max_file_size_ = val; }

 private:
  friend class base::RefCounted<MockDiskEntry>;
  struct CallbackInfo;

  ~MockDiskEntry() override;

  // Unlike the callbacks for MockHttpTransaction, we want this one to run even
  // if the consumer called Close on the MockDiskEntry.  We achieve that by
  // leveraging the fact that this class is reference counted.
  void CallbackLater(CompletionOnceCallback callback, int result);
  void CallbackLater(base::OnceClosure callback);

  void RunCallback(base::OnceClosure callback);

  // When |store| is true, stores the callback to be delivered later; otherwise
  // delivers any callback previously stored.
  static void StoreAndDeliverCallbacks(bool store,
                                       MockDiskEntry* entry,
                                       base::OnceClosure callback);

  static const int kNumCacheEntryDataIndices = 3;

  std::string key_;
  std::vector<char> data_[kNumCacheEntryDataIndices];
  uint8_t in_memory_data_ = 0;
  int test_mode_;
  int max_file_size_;
  bool doomed_ = false;
  bool sparse_ = false;
  int fail_requests_ = 0;
  bool fail_sparse_requests_ = false;
  bool busy_ = false;
  bool delayed_ = false;
  bool cancel_ = false;

  // Used for pause and restart.
  DeferOp defer_op_ = DEFER_NONE;
  CompletionOnceCallback resume_callback_;
  int resume_return_code_ = 0;

  static bool ignore_callbacks_;
};

class MockDiskCache : public disk_cache::Backend {
 public:
  MockDiskCache();
  ~MockDiskCache() override;

  int32_t GetEntryCount() const override;
  EntryResult OpenOrCreateEntry(const std::string& key,
                                net::RequestPriority request_priority,
                                EntryResultCallback callback) override;
  EntryResult OpenEntry(const std::string& key,
                        net::RequestPriority request_priority,
                        EntryResultCallback callback) override;
  EntryResult CreateEntry(const std::string& key,
                          net::RequestPriority request_priority,
                          EntryResultCallback callback) override;
  net::Error DoomEntry(const std::string& key,
                       net::RequestPriority request_priority,
                       CompletionOnceCallback callback) override;
  net::Error DoomAllEntries(CompletionOnceCallback callback) override;
  net::Error DoomEntriesBetween(base::Time initial_time,
                                base::Time end_time,
                                CompletionOnceCallback callback) override;
  net::Error DoomEntriesSince(base::Time initial_time,
                              CompletionOnceCallback callback) override;
  int64_t CalculateSizeOfAllEntries(
      Int64CompletionOnceCallback callback) override;
  std::unique_ptr<Iterator> CreateIterator() override;
  void GetStats(base::StringPairs* stats) override;
  void OnExternalCacheHit(const std::string& key) override;
  uint8_t GetEntryInMemoryData(const std::string& key) override;
  void SetEntryInMemoryData(const std::string& key, uint8_t data) override;
  int64_t MaxFileSize() const override;

  // Returns number of times a cache entry was successfully opened.
  int open_count() const { return open_count_; }

  // Returns number of times a cache entry was successfully created.
  int create_count() const { return create_count_; }

  // Returns number of doomed entries.
  int doomed_count() const { return doomed_count_; }

  // Fail any subsequent CreateEntry, OpenEntry, and DoomEntry
  void set_fail_requests(bool value) { fail_requests_ = value; }

  // Return entries that fail some of their requests.
  // The value is formed as a bitmask of MockDiskEntry::FailOp.
  void set_soft_failures_mask(int value) { soft_failures_ = value; }

  // Returns entries that fail some of their requests, but only until
  // the entry is re-created. The value is formed as a bitmask of
  // MockDiskEntry::FailOp.
  void set_soft_failures_one_instance(int value) {
    soft_failures_one_instance_ = value;
  }

  // Makes sure that CreateEntry is not called twice for a given key.
  void set_double_create_check(bool value) { double_create_check_ = value; }

  // Determines whether to provide the GetEntryInMemoryData/SetEntryInMemoryData
  // interface.  Default is true.
  void set_support_in_memory_entry_data(bool value) {
    support_in_memory_entry_data_ = value;
  }

  // OpenEntry, CreateEntry, and DoomEntry immediately return with
  // ERR_IO_PENDING and will callback some time later with an error.
  void set_force_fail_callback_later(bool value) {
    force_fail_callback_later_ = value;
  }

  // Makes all requests for data ranges to fail as not implemented.
  void set_fail_sparse_requests() { fail_sparse_requests_ = true; }

  // Sets the limit on how big entry streams can get. Only stream 1 enforces
  // this, but MaxFileSize() will still report it.
  void set_max_file_size(int new_size) { max_file_size_ = new_size; }

  void ReleaseAll();

  // Returns true if a doomed entry exists with this key.
  bool IsDiskEntryDoomed(const std::string& key);

  // Defers invoking the callback for the given operation. Calling code should
  // invoke ResumeCacheOperation to resume.
  void SetDefer(MockDiskEntry::DeferOp defer_op) { defer_op_ = defer_op; }

  // Resume deferred cache operation by posting |resume_callback_| with
  // |resume_return_code_|.
  void ResumeCacheOperation();

  // Returns a reference to the disk entry with the given |key|.
  scoped_refptr<MockDiskEntry> GetDiskEntryRef(const std::string& key);

  // Returns a reference to the vector storing all keys for external cache hits.
  const std::vector<std::string>& GetExternalCacheHits() const;

 private:
  using EntryMap = std::map<std::string, MockDiskEntry*>;
  class NotImplementedIterator;

  void CallbackLater(base::OnceClosure callback);

  EntryMap entries_;
  std::vector<std::string> external_cache_hits_;
  int open_count_ = 0;
  int create_count_ = 0;
  int doomed_count_ = 0;
  int max_file_size_;
  bool fail_requests_ = false;
  int soft_failures_ = 0;
  int soft_failures_one_instance_ = 0;
  bool double_create_check_ = true;
  bool fail_sparse_requests_ = false;
  bool support_in_memory_entry_data_ = true;
  bool force_fail_callback_later_ = false;

  // Used for pause and restart.
  MockDiskEntry::DeferOp defer_op_ = MockDiskEntry::DEFER_NONE;
  base::OnceClosure resume_callback_;
};

class MockBackendFactory : public HttpCache::BackendFactory {
 public:
  disk_cache::BackendResult CreateBackend(
      NetLog* net_log,
      disk_cache::BackendResultCallback callback) override;
};

class MockHttpCache {
 public:
  MockHttpCache();
  explicit MockHttpCache(
      std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory);

  HttpCache* http_cache() { return &http_cache_; }

  MockNetworkLayer* network_layer() {
    return static_cast<MockNetworkLayer*>(http_cache_.network_layer());
  }
  disk_cache::Backend* backend();
  MockDiskCache* disk_cache();

  // Wrapper around http_cache()->CreateTransaction(DEFAULT_PRIORITY...)
  int CreateTransaction(std::unique_ptr<HttpTransaction>* trans);

  // Wrapper to simulate cache lock timeout for new transactions.
  void SimulateCacheLockTimeout();

  // Wrapper to simulate cache lock timeout for new transactions.
  void SimulateCacheLockTimeoutAfterHeaders();

  // Wrapper to fail request conditionalization for new transactions.
  void FailConditionalizations();

  // Helper function for reading response info from the disk cache.
  static bool ReadResponseInfo(disk_cache::Entry* disk_entry,
                               HttpResponseInfo* response_info,
                               bool* response_truncated);

  // Helper function for writing response info into the disk cache.
  static bool WriteResponseInfo(disk_cache::Entry* disk_entry,
                                const HttpResponseInfo* response_info,
                                bool skip_transient_headers,
                                bool response_truncated);

  // Helper function to synchronously open a backend entry.
  bool OpenBackendEntry(const std::string& key, disk_cache::Entry** entry);

  // Helper function to synchronously create a backend entry.
  bool CreateBackendEntry(const std::string& key,
                          disk_cache::Entry** entry,
                          NetLog* net_log);

  // Returns the test mode after considering the global override.
  static int GetTestMode(int test_mode);

  // Overrides the test mode for a given operation. Remember to reset it after
  // the test! (by setting test_mode to zero).
  static void SetTestMode(int test_mode);

  // Functions to test the state of ActiveEntry.
  bool IsWriterPresent(const std::string& key);
  bool IsHeadersTransactionPresent(const std::string& key);
  int GetCountReaders(const std::string& key);
  int GetCountAddToEntryQueue(const std::string& key);
  int GetCountDoneHeadersQueue(const std::string& key);
  int GetCountWriterTransactions(const std::string& key);

 private:
  HttpCache http_cache_;
};

// This version of the disk cache doesn't invoke CreateEntry callbacks.
class MockDiskCacheNoCB : public MockDiskCache {
  EntryResult CreateEntry(const std::string& key,
                          net::RequestPriority request_priority,
                          EntryResultCallback callback) override;
};

class MockBackendNoCbFactory : public HttpCache::BackendFactory {
 public:
  disk_cache::BackendResult CreateBackend(
      NetLog* net_log,
      disk_cache::BackendResultCallback callback) override;
};

// This backend factory allows us to control the backend instantiation.
class MockBlockingBackendFactory : public HttpCache::BackendFactory {
 public:
  MockBlockingBackendFactory();
  ~MockBlockingBackendFactory() override;

  disk_cache::BackendResult CreateBackend(
      NetLog* net_log,
      disk_cache::BackendResultCallback callback) override;

  // Completes the backend creation. Any blocked call will be notified via the
  // provided callback.
  void FinishCreation();

  void set_fail(bool fail) { fail_ = fail; }

  disk_cache::BackendResultCallback ReleaseCallback() {
    return std::move(callback_);
  }

 private:
  disk_cache::BackendResult MakeResult();

  disk_cache::BackendResultCallback callback_;
  bool block_ = true;
  bool fail_ = false;
};

}  // namespace net

#endif  // NET_HTTP_MOCK_HTTP_CACHE_H_