diff options
Diffstat (limited to 'net/http/http_cache_unittest.cc')
-rw-r--r-- | net/http/http_cache_unittest.cc | 102 |
1 files changed, 101 insertions, 1 deletions
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index f7db18c..f1e636b 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -251,15 +251,34 @@ class MockDiskEntry : public disk_cache::Entry, // Fail most subsequent requests. void set_fail_requests() { fail_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) { + if (ignore_callbacks_ == value) + return; + ignore_callbacks_ = value; + if (!value) + StoreAndDeliverCallbacks(false, NULL, NULL, 0); + } + private: friend class base::RefCounted<MockDiskEntry>; + struct CallbackInfo { + scoped_refptr<MockDiskEntry> entry; + net::CompletionCallback* callback; + int result; + }; + ~MockDiskEntry() {} // 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(net::CompletionCallback* callback, int result) { + if (ignore_callbacks_) + return StoreAndDeliverCallbacks(true, this, callback, result); MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &MockDiskEntry::RunCallback, callback, result)); } @@ -282,6 +301,24 @@ class MockDiskEntry : public disk_cache::Entry, callback->Run(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, + net::CompletionCallback* callback, + int result) { + static std::vector<CallbackInfo> callback_list; + if (store) { + CallbackInfo c = {entry, callback, result}; + callback_list.push_back(c); + } else { + for (size_t i = 0; i < callback_list.size(); i++) { + CallbackInfo& c = callback_list[i]; + c.entry->CallbackLater(c.callback, c.result); + } + callback_list.clear(); + } + } + std::string key_; std::vector<char> data_[2]; int test_mode_; @@ -291,10 +328,12 @@ class MockDiskEntry : public disk_cache::Entry, bool busy_; bool delayed_; static bool cancel_; + static bool ignore_callbacks_; }; -// Static. +// Statics. bool MockDiskEntry::cancel_ = false; +bool MockDiskEntry::ignore_callbacks_ = false; class MockDiskCache : public disk_cache::Backend { public: @@ -2755,6 +2794,67 @@ TEST(HttpCache, RangeGET_Cancel2) { RemoveMockTransaction(&kRangeGET_TransactionOK); } +// A slight variation of the previous test, this time we cancel two requests in +// a row, making sure that the second is waiting for the entry to be ready. +TEST(HttpCache, RangeGET_Cancel3) { + MockHttpCache cache; + cache.http_cache()->set_enable_range_support(true); + AddMockTransaction(&kRangeGET_TransactionOK); + + RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); + MockHttpRequest request(kRangeGET_TransactionOK); + + Context* c = new Context(); + int rv = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, rv); + + rv = c->trans->Start(&request, &c->callback, NULL); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + rv = c->callback.WaitForResult(); + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Make sure that we revalidate the entry and read from the cache (a single + // read will return while waiting for the network). + scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(5); + rv = c->trans->Read(buf, buf->size(), &c->callback); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + rv = c->callback.WaitForResult(); + rv = c->trans->Read(buf, buf->size(), &c->callback); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + + // Destroy the transaction before completing the read. + delete c; + + // We have the read and the delete (OnProcessPendingQueue) waiting on the + // message loop. This means that a new transaction will just reuse the same + // active entry (no open or create). + + c = new Context(); + rv = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, rv); + + rv = c->trans->Start(&request, &c->callback, NULL); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + + MockDiskEntry::IgnoreCallbacks(true); + MessageLoop::current()->RunAllPending(); + MockDiskEntry::IgnoreCallbacks(false); + + // The new transaction is waiting for the query range callback. + delete c; + + // And we should not crash when the callback is delivered. + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + RemoveMockTransaction(&kRangeGET_TransactionOK); +} + // Tests that an invalid range response results in no cached entry. TEST(HttpCache, RangeGET_InvalidResponse1) { MockHttpCache cache; |