// Copyright (c) 2011 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. // 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 #include #include #include #include #include #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 { public: enum DeferOp { DEFER_NONE, DEFER_CREATE, DEFER_READ, DEFER_WRITE, }; 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; int GetAvailableRange(int64_t offset, int len, int64_t* start, CompletionOnceCallback callback) override; bool CouldBeSparse() const override; void CancelSparseIO() override; int 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 most subsequent requests. void set_fail_requests() { fail_requests_ = true; } 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(); private: friend class base::RefCounted; 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 RunCallback(CompletionOnceCallback callback, int result); // When |store| is true, stores the callback to be delivered later; otherwise // delivers any callback previously stored. static void StoreAndDeliverCallbacks(bool store, MockDiskEntry* entry, CompletionOnceCallback callback, int result); static const int kNumCacheEntryDataIndices = 3; std::string key_; std::vector data_[kNumCacheEntryDataIndices]; uint8_t in_memory_data_; int test_mode_; bool doomed_; bool sparse_; bool fail_requests_; bool fail_sparse_requests_; bool busy_; bool delayed_; bool cancel_; // Used for pause and restart. DeferOp defer_op_; CompletionOnceCallback resume_callback_; int resume_return_code_; static bool ignore_callbacks_; }; class MockDiskCache : public disk_cache::Backend { public: MockDiskCache(); ~MockDiskCache() override; CacheType GetCacheType() const override; int32_t GetEntryCount() const override; int OpenEntry(const std::string& key, net::RequestPriority request_priority, disk_cache::Entry** entry, CompletionOnceCallback callback) override; int CreateEntry(const std::string& key, net::RequestPriority request_priority, disk_cache::Entry** entry, CompletionOnceCallback callback) override; int DoomEntry(const std::string& key, net::RequestPriority request_priority, CompletionOnceCallback callback) override; int DoomAllEntries(CompletionOnceCallback callback) override; int DoomEntriesBetween(base::Time initial_time, base::Time end_time, CompletionOnceCallback callback) override; int DoomEntriesSince(base::Time initial_time, CompletionOnceCallback callback) override; int CalculateSizeOfAllEntries(CompletionOnceCallback callback) override; std::unique_ptr CreateIterator() override; void GetStats(base::StringPairs* stats) override; void OnExternalCacheHit(const std::string& key) override; size_t DumpMemoryStats( base::trace_event::ProcessMemoryDump* pmd, const std::string& parent_absolute_name) const override; uint8_t GetEntryInMemoryData(const std::string& key) override; void SetEntryInMemoryData(const std::string& key, uint8_t data) 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 and OpenEntry. void set_fail_requests() { fail_requests_ = true; } // Return entries that fail some of their requests. void set_soft_failures(bool value) { soft_failures_ = 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; } // Makes all requests for data ranges to fail as not implemented. void set_fail_sparse_requests() { fail_sparse_requests_ = true; } 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 GetDiskEntryRef(const std::string& key); private: using EntryMap = std::map; class NotImplementedIterator; void CallbackLater(CompletionOnceCallback callback, int result); EntryMap entries_; int open_count_; int create_count_; int doomed_count_; bool fail_requests_; bool soft_failures_; bool double_create_check_; bool fail_sparse_requests_; bool support_in_memory_entry_data_; // Used for pause and restart. MockDiskEntry::DeferOp defer_op_; CompletionOnceCallback resume_callback_; int resume_return_code_; }; class MockBackendFactory : public HttpCache::BackendFactory { public: int CreateBackend(NetLog* net_log, std::unique_ptr* backend, CompletionOnceCallback callback) override; }; class MockHttpCache { public: MockHttpCache(); explicit MockHttpCache( std::unique_ptr disk_cache_factory); // |is_main_cache| if set, will set a quic server info factory. explicit MockHttpCache(bool is_main_cache); MockHttpCache(std::unique_ptr disk_cache_factory, bool is_main_cache); HttpCache* http_cache() { return &http_cache_; } MockNetworkLayer* network_layer() { return static_cast(http_cache_.network_layer()); } disk_cache::Backend* backend(); MockDiskCache* disk_cache(); // Wrapper around http_cache()->CreateTransaction(DEFAULT_PRIORITY...) int CreateTransaction(std::unique_ptr* 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 { int CreateEntry(const std::string& key, net::RequestPriority request_priority, disk_cache::Entry** entry, CompletionOnceCallback callback) override; }; class MockBackendNoCbFactory : public HttpCache::BackendFactory { public: int CreateBackend(NetLog* net_log, std::unique_ptr* backend, CompletionOnceCallback callback) override; }; // This backend factory allows us to control the backend instantiation. class MockBlockingBackendFactory : public HttpCache::BackendFactory { public: MockBlockingBackendFactory(); ~MockBlockingBackendFactory() override; int CreateBackend(NetLog* net_log, std::unique_ptr* backend, CompletionOnceCallback callback) override; // Completes the backend creation. Any blocked call will be notified via the // provided callback. void FinishCreation(); std::unique_ptr* backend() { return backend_; } void set_fail(bool fail) { fail_ = fail; } CompletionOnceCallback ReleaseCallback() { return std::move(callback_); } private: int Result() { return fail_ ? ERR_FAILED : OK; } std::unique_ptr* backend_; CompletionOnceCallback callback_; bool block_; bool fail_; }; } // namespace net #endif // NET_HTTP_MOCK_HTTP_CACHE_H_