• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This is a mock of the http cache and related testing classes. To be fair, it
6 // is not really a mock http cache given that it uses the real implementation of
7 // the http cache, but it has fake implementations of all required components,
8 // so it is useful for unit tests at the http layer.
9 
10 #ifndef NET_HTTP_MOCK_HTTP_CACHE_H_
11 #define NET_HTTP_MOCK_HTTP_CACHE_H_
12 
13 #include <stdint.h>
14 
15 #include <map>
16 #include <memory>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "base/memory/raw_ptr.h"
22 #include "base/strings/string_split.h"
23 #include "net/base/completion_once_callback.h"
24 #include "net/base/request_priority.h"
25 #include "net/disk_cache/disk_cache.h"
26 #include "net/http/http_cache.h"
27 #include "net/http/http_transaction_test_util.h"
28 
29 namespace net {
30 
31 //-----------------------------------------------------------------------------
32 // Mock disk cache (a very basic memory cache implementation).
33 
34 class MockDiskEntry : public disk_cache::Entry,
35                       public base::RefCounted<MockDiskEntry> {
36  public:
37   enum DeferOp {
38     DEFER_NONE,
39     DEFER_CREATE,
40     DEFER_READ,
41     DEFER_WRITE,
42   };
43 
44   // Bit mask used for set_fail_requests().
45   enum FailOp {
46     FAIL_READ = 0x01,
47     FAIL_WRITE = 0x02,
48     FAIL_READ_SPARSE = 0x04,
49     FAIL_WRITE_SPARSE = 0x08,
50     FAIL_GET_AVAILABLE_RANGE = 0x10,
51     FAIL_ALL = 0xFF
52   };
53 
54   explicit MockDiskEntry(const std::string& key);
55 
is_doomed()56   bool is_doomed() const { return doomed_; }
57 
58   void Doom() override;
59   void Close() override;
60   std::string GetKey() const override;
61   base::Time GetLastUsed() const override;
62   base::Time GetLastModified() const override;
63   int32_t GetDataSize(int index) const override;
64   int ReadData(int index,
65                int offset,
66                IOBuffer* buf,
67                int buf_len,
68                CompletionOnceCallback callback) override;
69   int WriteData(int index,
70                 int offset,
71                 IOBuffer* buf,
72                 int buf_len,
73                 CompletionOnceCallback callback,
74                 bool truncate) override;
75   int ReadSparseData(int64_t offset,
76                      IOBuffer* buf,
77                      int buf_len,
78                      CompletionOnceCallback callback) override;
79   int WriteSparseData(int64_t offset,
80                       IOBuffer* buf,
81                       int buf_len,
82                       CompletionOnceCallback callback) override;
83   RangeResult GetAvailableRange(int64_t offset,
84                                 int len,
85                                 RangeResultCallback callback) override;
86   bool CouldBeSparse() const override;
87   void CancelSparseIO() override;
88   Error ReadyForSparseIO(CompletionOnceCallback completion_callback) override;
89   void SetLastUsedTimeForTest(base::Time time) override;
90 
in_memory_data()91   uint8_t in_memory_data() const { return in_memory_data_; }
set_in_memory_data(uint8_t val)92   void set_in_memory_data(uint8_t val) { in_memory_data_ = val; }
93 
94   // Fail subsequent requests, specified via FailOp bits.
set_fail_requests(int mask)95   void set_fail_requests(int mask) { fail_requests_ = mask; }
96 
set_fail_sparse_requests()97   void set_fail_sparse_requests() { fail_sparse_requests_ = true; }
98 
99   // If |value| is true, don't deliver any completion callbacks until called
100   // again with |value| set to false.  Caution: remember to enable callbacks
101   // again or all subsequent tests will fail.
102   static void IgnoreCallbacks(bool value);
103 
104   // Defers invoking the callback for the given operation. Calling code should
105   // invoke ResumeDiskEntryOperation to resume.
SetDefer(DeferOp defer_op)106   void SetDefer(DeferOp defer_op) { defer_op_ = defer_op; }
107 
108   // Resumes deferred cache operation by posting |resume_callback_| with
109   // |resume_return_code_|.
110   void ResumeDiskEntryOperation();
111 
112   // Sets the maximum length of a stream. This is only applied to stream 1.
set_max_file_size(int val)113   void set_max_file_size(int val) { max_file_size_ = val; }
114 
115  private:
116   friend class base::RefCounted<MockDiskEntry>;
117   struct CallbackInfo;
118 
119   ~MockDiskEntry() override;
120 
121   // Unlike the callbacks for MockHttpTransaction, we want this one to run even
122   // if the consumer called Close on the MockDiskEntry.  We achieve that by
123   // leveraging the fact that this class is reference counted.
124   void CallbackLater(CompletionOnceCallback callback, int result);
125   void CallbackLater(base::OnceClosure callback);
126 
127   void RunCallback(base::OnceClosure callback);
128 
129   // When |store| is true, stores the callback to be delivered later; otherwise
130   // delivers any callback previously stored.
131   static void StoreAndDeliverCallbacks(bool store,
132                                        MockDiskEntry* entry,
133                                        base::OnceClosure callback);
134 
135   static const int kNumCacheEntryDataIndices = 3;
136 
137   std::string key_;
138   std::vector<char> data_[kNumCacheEntryDataIndices];
139   uint8_t in_memory_data_ = 0;
140   int test_mode_;
141   int max_file_size_;
142   bool doomed_ = false;
143   bool sparse_ = false;
144   int fail_requests_ = 0;
145   bool fail_sparse_requests_ = false;
146   bool busy_ = false;
147   bool delayed_ = false;
148   bool cancel_ = false;
149 
150   // Used for pause and restart.
151   DeferOp defer_op_ = DEFER_NONE;
152   CompletionOnceCallback resume_callback_;
153   int resume_return_code_ = 0;
154 
155   static bool ignore_callbacks_;
156 };
157 
158 class MockDiskCache : public disk_cache::Backend {
159  public:
160   MockDiskCache();
161   ~MockDiskCache() override;
162 
163   int32_t GetEntryCount() const override;
164   EntryResult OpenOrCreateEntry(const std::string& key,
165                                 RequestPriority request_priority,
166                                 EntryResultCallback callback) override;
167   EntryResult OpenEntry(const std::string& key,
168                         RequestPriority request_priority,
169                         EntryResultCallback callback) override;
170   EntryResult CreateEntry(const std::string& key,
171                           RequestPriority request_priority,
172                           EntryResultCallback callback) override;
173   Error DoomEntry(const std::string& key,
174                   RequestPriority request_priority,
175                   CompletionOnceCallback callback) override;
176   Error DoomAllEntries(CompletionOnceCallback callback) override;
177   Error DoomEntriesBetween(base::Time initial_time,
178                            base::Time end_time,
179                            CompletionOnceCallback callback) override;
180   Error DoomEntriesSince(base::Time initial_time,
181                          CompletionOnceCallback callback) override;
182   int64_t CalculateSizeOfAllEntries(
183       Int64CompletionOnceCallback callback) override;
184   std::unique_ptr<Iterator> CreateIterator() override;
185   void GetStats(base::StringPairs* stats) override;
186   void OnExternalCacheHit(const std::string& key) override;
187   uint8_t GetEntryInMemoryData(const std::string& key) override;
188   void SetEntryInMemoryData(const std::string& key, uint8_t data) override;
189   int64_t MaxFileSize() const override;
190 
191   // Returns number of times a cache entry was successfully opened.
open_count()192   int open_count() const { return open_count_; }
193 
194   // Returns number of times a cache entry was successfully created.
create_count()195   int create_count() const { return create_count_; }
196 
197   // Returns number of doomed entries.
doomed_count()198   int doomed_count() const { return doomed_count_; }
199 
200   // Fail any subsequent CreateEntry, OpenEntry, and DoomEntry
set_fail_requests(bool value)201   void set_fail_requests(bool value) { fail_requests_ = value; }
202 
203   // Return entries that fail some of their requests.
204   // The value is formed as a bitmask of MockDiskEntry::FailOp.
set_soft_failures_mask(int value)205   void set_soft_failures_mask(int value) { soft_failures_ = value; }
206 
207   // Returns entries that fail some of their requests, but only until
208   // the entry is re-created. The value is formed as a bitmask of
209   // MockDiskEntry::FailOp.
set_soft_failures_one_instance(int value)210   void set_soft_failures_one_instance(int value) {
211     soft_failures_one_instance_ = value;
212   }
213 
214   // Makes sure that CreateEntry is not called twice for a given key.
set_double_create_check(bool value)215   void set_double_create_check(bool value) { double_create_check_ = value; }
216 
217   // Determines whether to provide the GetEntryInMemoryData/SetEntryInMemoryData
218   // interface.  Default is true.
set_support_in_memory_entry_data(bool value)219   void set_support_in_memory_entry_data(bool value) {
220     support_in_memory_entry_data_ = value;
221   }
222 
223   // OpenEntry, CreateEntry, and DoomEntry immediately return with
224   // ERR_IO_PENDING and will callback some time later with an error.
set_force_fail_callback_later(bool value)225   void set_force_fail_callback_later(bool value) {
226     force_fail_callback_later_ = value;
227   }
228 
229   // Makes all requests for data ranges to fail as not implemented.
set_fail_sparse_requests()230   void set_fail_sparse_requests() { fail_sparse_requests_ = true; }
231 
232   // Sets the limit on how big entry streams can get. Only stream 1 enforces
233   // this, but MaxFileSize() will still report it.
set_max_file_size(int new_size)234   void set_max_file_size(int new_size) { max_file_size_ = new_size; }
235 
236   void ReleaseAll();
237 
238   // Returns true if a doomed entry exists with this key.
239   bool IsDiskEntryDoomed(const std::string& key);
240 
241   // Defers invoking the callback for the given operation. Calling code should
242   // invoke ResumeCacheOperation to resume.
SetDefer(MockDiskEntry::DeferOp defer_op)243   void SetDefer(MockDiskEntry::DeferOp defer_op) { defer_op_ = defer_op; }
244 
245   // Resume deferred cache operation by posting |resume_callback_| with
246   // |resume_return_code_|.
247   void ResumeCacheOperation();
248 
249   // Returns a reference to the disk entry with the given |key|.
250   scoped_refptr<MockDiskEntry> GetDiskEntryRef(const std::string& key);
251 
252   // Returns a reference to the vector storing all keys for external cache hits.
253   const std::vector<std::string>& GetExternalCacheHits() const;
254 
255  private:
256   using EntryMap =
257       std::map<std::string, raw_ptr<MockDiskEntry, CtnExperimental>>;
258   class NotImplementedIterator;
259 
260   void CallbackLater(base::OnceClosure callback);
261 
262   EntryMap entries_;
263   std::vector<std::string> external_cache_hits_;
264   int open_count_ = 0;
265   int create_count_ = 0;
266   int doomed_count_ = 0;
267   int max_file_size_;
268   bool fail_requests_ = false;
269   int soft_failures_ = 0;
270   int soft_failures_one_instance_ = 0;
271   bool double_create_check_ = true;
272   bool fail_sparse_requests_ = false;
273   bool support_in_memory_entry_data_ = true;
274   bool force_fail_callback_later_ = false;
275 
276   // Used for pause and restart.
277   MockDiskEntry::DeferOp defer_op_ = MockDiskEntry::DEFER_NONE;
278   base::OnceClosure resume_callback_;
279 };
280 
281 class MockBackendFactory : public HttpCache::BackendFactory {
282  public:
283   disk_cache::BackendResult CreateBackend(
284       NetLog* net_log,
285       disk_cache::BackendResultCallback callback) override;
286 };
287 
288 class MockHttpCache {
289  public:
290   MockHttpCache();
291   explicit MockHttpCache(
292       std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory);
293 
http_cache()294   HttpCache* http_cache() { return &http_cache_; }
295 
network_layer()296   MockNetworkLayer* network_layer() {
297     return static_cast<MockNetworkLayer*>(http_cache_.network_layer());
298   }
299   disk_cache::Backend* backend();
300   MockDiskCache* disk_cache();
301 
302   // Wrapper around http_cache()->CreateTransaction(DEFAULT_PRIORITY...)
303   int CreateTransaction(std::unique_ptr<HttpTransaction>* trans);
304 
305   // Wrapper to simulate cache lock timeout for new transactions.
306   void SimulateCacheLockTimeout();
307 
308   // Wrapper to simulate cache lock timeout for new transactions.
309   void SimulateCacheLockTimeoutAfterHeaders();
310 
311   // Wrapper to fail request conditionalization for new transactions.
312   void FailConditionalizations();
313 
314   // Helper function for reading response info from the disk cache.
315   static bool ReadResponseInfo(disk_cache::Entry* disk_entry,
316                                HttpResponseInfo* response_info,
317                                bool* response_truncated);
318 
319   // Helper function for writing response info into the disk cache.
320   static bool WriteResponseInfo(disk_cache::Entry* disk_entry,
321                                 const HttpResponseInfo* response_info,
322                                 bool skip_transient_headers,
323                                 bool response_truncated);
324 
325   // Helper function to synchronously open a backend entry.
326   bool OpenBackendEntry(const std::string& key, disk_cache::Entry** entry);
327 
328   // Helper function to synchronously create a backend entry.
329   bool CreateBackendEntry(const std::string& key,
330                           disk_cache::Entry** entry,
331                           NetLog* net_log);
332 
333   // Returns the test mode after considering the global override.
334   static int GetTestMode(int test_mode);
335 
336   // Overrides the test mode for a given operation. Remember to reset it after
337   // the test! (by setting test_mode to zero).
338   static void SetTestMode(int test_mode);
339 
340   // Functions to test the state of ActiveEntry.
341   bool IsWriterPresent(const std::string& key);
342   bool IsHeadersTransactionPresent(const std::string& key);
343   int GetCountReaders(const std::string& key);
344   int GetCountAddToEntryQueue(const std::string& key);
345   int GetCountDoneHeadersQueue(const std::string& key);
346   int GetCountWriterTransactions(const std::string& key);
347 
348   base::WeakPtr<HttpCache> GetWeakPtr();
349 
350  private:
351   HttpCache http_cache_;
352 };
353 
354 // This version of the disk cache doesn't invoke CreateEntry callbacks.
355 class MockDiskCacheNoCB : public MockDiskCache {
356   EntryResult CreateEntry(const std::string& key,
357                           RequestPriority request_priority,
358                           EntryResultCallback callback) override;
359 };
360 
361 class MockBackendNoCbFactory : public HttpCache::BackendFactory {
362  public:
363   disk_cache::BackendResult CreateBackend(
364       NetLog* net_log,
365       disk_cache::BackendResultCallback callback) override;
366 };
367 
368 // This backend factory allows us to control the backend instantiation.
369 class MockBlockingBackendFactory : public HttpCache::BackendFactory {
370  public:
371   MockBlockingBackendFactory();
372   ~MockBlockingBackendFactory() override;
373 
374   disk_cache::BackendResult CreateBackend(
375       NetLog* net_log,
376       disk_cache::BackendResultCallback callback) override;
377 
378   // Completes the backend creation. Any blocked call will be notified via the
379   // provided callback.
380   void FinishCreation();
381 
set_fail(bool fail)382   void set_fail(bool fail) { fail_ = fail; }
383 
ReleaseCallback()384   disk_cache::BackendResultCallback ReleaseCallback() {
385     return std::move(callback_);
386   }
387 
388  private:
389   disk_cache::BackendResult MakeResult();
390 
391   disk_cache::BackendResultCallback callback_;
392   bool block_ = true;
393   bool fail_ = false;
394 };
395 
396 struct GetBackendResultIsPendingHelper {
operatorGetBackendResultIsPendingHelper397   bool operator()(const HttpCache::GetBackendResult& result) const {
398     return result.first == net::ERR_IO_PENDING;
399   }
400 };
401 using TestGetBackendCompletionCallbackBase =
402     net::internal::TestCompletionCallbackTemplate<
403         HttpCache::GetBackendResult,
404         GetBackendResultIsPendingHelper>;
405 
406 class TestGetBackendCompletionCallback
407     : public TestGetBackendCompletionCallbackBase {
408  public:
409   TestGetBackendCompletionCallback() = default;
410 
callback()411   HttpCache::GetBackendCallback callback() {
412     return base::BindOnce(&TestGetBackendCompletionCallback::SetResult,
413                           base::Unretained(this));
414   }
415 };
416 
417 }  // namespace net
418 
419 #endif  // NET_HTTP_MOCK_HTTP_CACHE_H_
420