Index: net/http/http_cache_unittest.cc |
=================================================================== |
--- net/http/http_cache_unittest.cc (revision 46487) |
+++ net/http/http_cache_unittest.cc (working copy) |
@@ -570,6 +570,13 @@ |
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,7 +876,169 @@ |
//----------------------------------------------------------------------------- |
// 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 @@ |
// 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_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_CREATE_ENTRY)); |
+ EXPECT_TRUE(net::LogContainsEndEvent( |
+ 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 @@ |
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 @@ |
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 @@ |
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 @@ |
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_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()); |