diff options
Diffstat (limited to 'net/http/http_cache_unittest.cc')
-rw-r--r-- | net/http/http_cache_unittest.cc | 292 |
1 files changed, 262 insertions, 30 deletions
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 32b3343..cf12dfc 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -570,6 +570,13 @@ class MockHttpCache { net::HttpCache http_cache_; }; +// This version of the disk cache doesn't invoke CreateEntry callbacks. +class MockDiskCacheNoCB : public MockDiskCache { + virtual int CreateEntry(const std::string& key, disk_cache::Entry** entry, + net::CompletionCallback* callback) { + return net::ERR_IO_PENDING; + } +}; //----------------------------------------------------------------------------- // helpers @@ -869,6 +876,168 @@ struct Context { //----------------------------------------------------------------------------- // tests +namespace net { + +// This is a friend class of the HttpCache so that we can interact with it to +// perform a few internal tests. We override the backend factory method so that +// we can test the logic of backend instantiation. +class HttpCacheTest : public testing::Test { + public: + // Controls whether to block the backend instantiation or not. If |block| is + // true, any blocked call will be notified via the provided callback. + void BlockCacheCreation(bool block) { + block_ = block; + if (!block_ && callback_) { + *backend_ = new MockDiskCache(); + callback_->Run(OK); + callback_ = NULL; + } + } + + protected: + virtual void SetUp() { + current_test_ = this; + backend_ = NULL; + callback_ = NULL; + block_ = false; + } + + virtual void TearDown() { current_test_ = NULL; } + + // Implements disk_cache::CreateCacheBackend(). + static int MockCreateBackend(CacheType type, const FilePath& path, + int max_bytes, bool force, MessageLoop* thread, + disk_cache::Backend** backend, + CompletionCallback* callback) { + if (current_test_ == NULL) { + EXPECT_TRUE(current_test_); + return ERR_FAILED; + } + if (!current_test_->block_) { + *backend = new MockDiskCache(); + return OK; + } + + current_test_->backend_ = backend; + current_test_->callback_ = callback; + return ERR_IO_PENDING; + } + + private: + static HttpCacheTest* current_test_; + disk_cache::Backend** backend_; + CompletionCallback* callback_; + bool block_; +}; + +// Static. +HttpCacheTest* HttpCacheTest::current_test_ = NULL; + +// Tests that we queue requests when initializing the backend. +TEST_F(HttpCacheTest, SimpleGET_WaitForBackend) { + MockHttpCache cache(NULL); + cache.http_cache()->create_backend_fn_ = MockCreateBackend; + cache.http_cache()->set_type(MEMORY_CACHE); + BlockCacheCreation(true); + + MockHttpRequest request0(kSimpleGET_Transaction); + MockHttpRequest request1(kTypicalGET_Transaction); + MockHttpRequest request2(kETagGET_Transaction); + + std::vector<Context*> context_list; + const int kNumTransactions = 3; + + for (int i = 0; i < kNumTransactions; i++) { + context_list.push_back(new Context()); + Context* c = context_list[i]; + + c->result = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(OK, c->result); + } + + context_list[0]->result = context_list[0]->trans->Start( + &request0, &context_list[0]->callback, BoundNetLog()); + context_list[1]->result = context_list[1]->trans->Start( + &request1, &context_list[1]->callback, BoundNetLog()); + context_list[2]->result = context_list[2]->trans->Start( + &request2, &context_list[2]->callback, BoundNetLog()); + + // Just to make sure that everything is still pending. + MessageLoop::current()->RunAllPending(); + + // The first request should be creating the disk cache. + EXPECT_FALSE(context_list[0]->callback.have_result()); + + BlockCacheCreation(false); + + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(3, cache.network_layer()->transaction_count()); + EXPECT_EQ(3, cache.disk_cache()->create_count()); + + for (int i = 0; i < kNumTransactions; ++i) { + EXPECT_TRUE(context_list[i]->callback.have_result()); + delete context_list[i]; + } +} + +// Tests that we can cancel requests that are queued waiting for the backend +// to be initialized. +TEST_F(HttpCacheTest, SimpleGET_WaitForBackend_CancelCreate) { + MockHttpCache cache(NULL); + cache.http_cache()->create_backend_fn_ = MockCreateBackend; + cache.http_cache()->set_type(MEMORY_CACHE); + BlockCacheCreation(true); + + MockHttpRequest request0(kSimpleGET_Transaction); + MockHttpRequest request1(kTypicalGET_Transaction); + MockHttpRequest request2(kETagGET_Transaction); + + std::vector<Context*> context_list; + const int kNumTransactions = 3; + + for (int i = 0; i < kNumTransactions; i++) { + context_list.push_back(new Context()); + Context* c = context_list[i]; + + c->result = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(OK, c->result); + } + + context_list[0]->result = context_list[0]->trans->Start( + &request0, &context_list[0]->callback, BoundNetLog()); + context_list[1]->result = context_list[1]->trans->Start( + &request1, &context_list[1]->callback, BoundNetLog()); + context_list[2]->result = context_list[2]->trans->Start( + &request2, &context_list[2]->callback, BoundNetLog()); + + // Just to make sure that everything is still pending. + MessageLoop::current()->RunAllPending(); + + // The first request should be creating the disk cache. + EXPECT_FALSE(context_list[0]->callback.have_result()); + + // Cancel a request from the pending queue. + delete context_list[1]; + context_list[1] = NULL; + + // Cancel the request that is creating the entry. + delete context_list[0]; + context_list[0] = NULL; + + // Complete the last transaction. + BlockCacheCreation(false); + + context_list[2]->result = + context_list[2]->callback.GetResult(context_list[2]->result); + ReadAndVerifyTransaction(context_list[2]->trans.get(), kETagGET_Transaction); + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + delete context_list[2]; +} + +} // net namespace. TEST(HttpCache, CreateThenDestroy) { MockHttpCache cache; @@ -912,21 +1081,36 @@ TEST(HttpCache, SimpleGETNoDiskCache) { // Check that the NetLog was filled as expected. // (We attempted to both Open and Create entries, but both failed). - EXPECT_EQ(4u, log.entries().size()); + EXPECT_EQ(6u, log.entries().size()); + EXPECT_TRUE(net::LogContainsBeginEvent( + log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + EXPECT_TRUE(net::LogContainsEndEvent( + log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(0, cache.disk_cache()->create_count()); } +TEST(HttpCache, SimpleGETNoDiskCache2) { + // This will initialize a cache object with NULL backend. + MockHttpCache cache(NULL); + + // Read from the network, and don't use the cache. + RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction); + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_FALSE(cache.http_cache()->GetBackend()); +} + TEST(HttpCache, SimpleGETWithDiskFailures) { MockHttpCache cache; @@ -996,19 +1180,23 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) { log.bound()); // Check that the NetLog was filled as expected. - EXPECT_EQ(6u, log.entries().size()); + EXPECT_EQ(8u, log.entries().size()); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + EXPECT_TRUE(net::LogContainsBeginEvent( + log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + EXPECT_TRUE(net::LogContainsEndEvent( + log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_WAITING)); // force this transaction to read from the cache MockTransaction transaction(kSimpleGET_Transaction); @@ -1019,19 +1207,23 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) { RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound()); // Check that the NetLog was filled as expected. - EXPECT_EQ(6u, log.entries().size()); + EXPECT_EQ(8u, log.entries().size()); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); + log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_READ_INFO)); + log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_READ_INFO)); + log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + EXPECT_TRUE(net::LogContainsBeginEvent( + log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_READ_INFO)); + EXPECT_TRUE(net::LogContainsEndEvent( + log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_READ_INFO)); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); @@ -1111,19 +1303,23 @@ TEST(HttpCache, SimpleGET_LoadBypassCache) { RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound()); // Check that the NetLog was filled as expected. - EXPECT_EQ(6u, log.entries().size()); + EXPECT_EQ(8u, log.entries().size()); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY)); + log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY)); + log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY)); EXPECT_TRUE(net::LogContainsBeginEvent( - log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); EXPECT_TRUE(net::LogContainsEndEvent( - log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY)); + EXPECT_TRUE(net::LogContainsBeginEvent( + log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_WAITING)); + EXPECT_TRUE(net::LogContainsEndEvent( + log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_WAITING)); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); @@ -1668,6 +1864,42 @@ TEST(HttpCache, SimpleGET_AbandonedCacheRead) { MessageLoop::current()->RunAllPending(); } +// Tests that we can delete the HttpCache and deal with queued transactions +// ("waiting for the backend" as opposed to Active or Doomed entries). +TEST(HttpCache, SimpleGET_ManyWriters_DeleteCache) { + scoped_ptr<MockHttpCache> cache(new MockHttpCache(new MockDiskCacheNoCB())); + + MockHttpRequest request(kSimpleGET_Transaction); + + std::vector<Context*> context_list; + const int kNumTransactions = 5; + + for (int i = 0; i < kNumTransactions; i++) { + context_list.push_back(new Context()); + Context* c = context_list[i]; + + c->result = cache->http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, c->result); + + c->result = c->trans->Start(&request, &c->callback, net::BoundNetLog()); + } + + // The first request should be creating the disk cache entry and the others + // should be pending. + + EXPECT_EQ(0, cache->network_layer()->transaction_count()); + EXPECT_EQ(0, cache->disk_cache()->open_count()); + EXPECT_EQ(0, cache->disk_cache()->create_count()); + + cache.reset(); + + // There is not much to do with the transactions at this point... they are + // waiting for a callback that will not fire. + for (int i = 0; i < kNumTransactions; ++i) { + delete context_list[i]; + } +} + TEST(HttpCache, TypicalGET_ConditionalRequest) { MockHttpCache cache; @@ -3885,12 +4117,12 @@ TEST(HttpCache, SyncRead) { TEST_MODE_SYNC_CACHE_WRITE); MockHttpRequest r1(transaction), - r2(transaction), - r3(transaction); + r2(transaction), + r3(transaction); TestTransactionConsumer c1(cache.http_cache()), - c2(cache.http_cache()), - c3(cache.http_cache()); + c2(cache.http_cache()), + c3(cache.http_cache()); c1.Start(&r1, net::BoundNetLog()); |