Index: net/http/http_cache_unittest.cc |
=================================================================== |
--- net/http/http_cache_unittest.cc (revision 7627) |
+++ net/http/http_cache_unittest.cc (working copy) |
@@ -532,6 +532,80 @@ |
} |
} |
+// This is a test for http://code.google.com/p/chromium/issues/detail?id=4769. |
+// If cancelling a request is racing with another request for the same resource |
+// finishing, we have to make sure that we remove both transactions from the |
+// entry. |
+TEST(HttpCache, SimpleGET_RacingReaders) { |
+ MockHttpCache cache; |
+ |
+ MockHttpRequest request(kSimpleGET_Transaction); |
+ MockHttpRequest reader_request(kSimpleGET_Transaction); |
+ reader_request.load_flags = net::LOAD_ONLY_FROM_CACHE; |
+ |
+ std::vector<Context*> context_list; |
+ const int kNumTransactions = 5; |
+ |
+ for (int i = 0; i < kNumTransactions; ++i) { |
+ context_list.push_back( |
+ new Context(cache.http_cache()->CreateTransaction())); |
+ |
+ Context* c = context_list[i]; |
+ MockHttpRequest* this_request = &request; |
+ if (i == 1 || i == 2) |
+ this_request = &reader_request; |
+ |
+ int rv = c->trans->Start(this_request, &c->callback); |
+ if (rv != net::ERR_IO_PENDING) |
+ c->result = rv; |
+ } |
+ |
+ // The first request should be a writer at this point, and the subsequent |
+ // requests should be pending. |
+ |
+ EXPECT_EQ(1, cache.network_layer()->transaction_count()); |
+ EXPECT_EQ(0, cache.disk_cache()->open_count()); |
+ EXPECT_EQ(1, cache.disk_cache()->create_count()); |
+ |
+ Context* c = context_list[0]; |
+ ASSERT_EQ(net::ERR_IO_PENDING, c->result); |
+ c->result = c->callback.WaitForResult(); |
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); |
+ |
+ // Now we have 2 active readers and two queued transactions. |
+ |
+ c = context_list[1]; |
+ ASSERT_EQ(net::ERR_IO_PENDING, c->result); |
+ c->result = c->callback.WaitForResult(); |
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); |
+ |
+ // At this point we have one reader, two pending transactions and a task on |
+ // the queue to move to the next transaction. Now we cancel the request that |
+ // is the current reader, and expect the queued task to be able to start the |
+ // next request. |
+ |
+ c = context_list[2]; |
+ c->trans.reset(); |
+ |
+ for (int i = 3; i < kNumTransactions; ++i) { |
+ Context* c = context_list[i]; |
+ if (c->result == net::ERR_IO_PENDING) |
+ c->result = c->callback.WaitForResult(); |
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); |
+ } |
+ |
+ // We should not have had to re-open the disk entry. |
+ |
+ EXPECT_EQ(1, cache.network_layer()->transaction_count()); |
+ EXPECT_EQ(0, cache.disk_cache()->open_count()); |
+ EXPECT_EQ(1, cache.disk_cache()->create_count()); |
+ |
+ for (int i = 0; i < kNumTransactions; ++i) { |
+ Context* c = context_list[i]; |
+ delete c; |
+ } |
+} |
+ |
TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) { |
MockHttpCache cache; |