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
|
// 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 <array>
#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"
#include "net/http/no_vary_search_cache_storage_file_operations.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;
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;
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::array<std::vector<uint8_t>, kNumCacheEntryDataIndices> data_;
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(
net::Int32CompletionOnceCallback callback) const override;
EntryResult OpenOrCreateEntry(const std::string& key,
RequestPriority request_priority,
EntryResultCallback callback) override;
EntryResult OpenEntry(const std::string& key,
RequestPriority request_priority,
EntryResultCallback callback) override;
EntryResult CreateEntry(const std::string& key,
RequestPriority request_priority,
EntryResultCallback callback) override;
Error DoomEntry(const std::string& key,
RequestPriority request_priority,
CompletionOnceCallback callback) override;
Error DoomAllEntries(CompletionOnceCallback callback) override;
Error DoomEntriesBetween(base::Time initial_time,
base::Time end_time,
CompletionOnceCallback callback) override;
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, raw_ptr<MockDiskEntry, CtnExperimental>>;
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,
std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations =
nullptr);
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)
std::unique_ptr<HttpTransaction> CreateTransaction();
// 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);
base::WeakPtr<HttpCache> GetWeakPtr();
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,
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;
};
struct GetBackendResultIsPendingHelper {
bool operator()(const HttpCache::GetBackendResult& result) const {
return result.first == net::ERR_IO_PENDING;
}
};
using TestGetBackendCompletionCallbackBase =
net::internal::TestCompletionCallbackTemplate<
HttpCache::GetBackendResult,
GetBackendResultIsPendingHelper>;
class TestGetBackendCompletionCallback
: public TestGetBackendCompletionCallbackBase {
public:
TestGetBackendCompletionCallback() = default;
HttpCache::GetBackendCallback callback() {
return base::BindOnce(&TestGetBackendCompletionCallback::SetResult,
base::Unretained(this));
}
};
} // namespace net
#endif // NET_HTTP_MOCK_HTTP_CACHE_H_
|