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