| Index: net/http/http_cache_unittest.cc
|
| diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
|
| index 27222a905449abe15cd263149bb25c373a576a89..288b1c7dab731e000ddeacd9a53dca87dfea9a5d 100644
|
| --- a/net/http/http_cache_unittest.cc
|
| +++ b/net/http/http_cache_unittest.cc
|
| @@ -1375,7 +1375,8 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
|
| base::RunLoop().RunUntilIdle();
|
|
|
| // The first request should be a writer at this point, and the subsequent
|
| - // requests should be pending.
|
| + // requests should have passed the validation phase and waiting for the
|
| + // response to be written to the cache before they can read.
|
|
|
| EXPECT_EQ(1, cache.network_layer()->transaction_count());
|
| EXPECT_EQ(0, cache.disk_cache()->open_count());
|
| @@ -1407,6 +1408,175 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
|
| }
|
| }
|
|
|
| +// Tests parallel validation similar to the above test, except here validation
|
| +// request is sent out to the network and results in 304.
|
| +TEST(HttpCache, SimpleGET_ParallelValidation) {
|
| + MockHttpCache cache;
|
| +
|
| + std::vector<MockHttpRequest> request;
|
| + ScopedMockTransaction transaction(kTypicalGET_Transaction);
|
| + transaction.response_headers =
|
| + "Etag: \"foopy\"\n"
|
| + "Cache-Control: max-age=0\n";
|
| + MockHttpRequest request0(transaction);
|
| + request.push_back(request0);
|
| +
|
| + ScopedMockTransaction transaction1(kTypicalGET_Transaction);
|
| + transaction1.status = "HTTP/1.1 304 Not Modified";
|
| + transaction1.load_flags |= LOAD_VALIDATE_CACHE;
|
| + transaction1.response_headers =
|
| + "Etag: \"foopy\"\n"
|
| + "Cache-Control: max-age=3600\n";
|
| + MockHttpRequest request1(transaction1);
|
| + request.push_back(request1);
|
| +
|
| + std::vector<Context*> context_list;
|
| + const int kNumTransactions = 2;
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + context_list.push_back(new Context());
|
| + Context* c = context_list[i];
|
| +
|
| + c->result = cache.CreateTransaction(&c->trans);
|
| + ASSERT_THAT(c->result, IsOk());
|
| + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
|
| +
|
| + c->result = c->trans->Start(&request[i], c->callback.callback(),
|
| + NetLogWithSource());
|
| + }
|
| +
|
| + // All requests are waiting for the active entry.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
|
| + }
|
| +
|
| + // Allow all requests to move from the Create queue to the active entry.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // The first request should be a writer at this point, and the subsequent
|
| + // requests should have passed the validation phase and waiting for the
|
| + // response to be written to the cache before they can read.
|
| +
|
| + EXPECT_EQ(2, cache.network_layer()->transaction_count());
|
| + EXPECT_EQ(0, cache.disk_cache()->open_count());
|
| + EXPECT_EQ(1, cache.disk_cache()->create_count());
|
| +
|
| + // All requests depend on the writer, and the writer is between Start and
|
| + // Read, i.e. idle.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
|
| + }
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + if (c->result == 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(2, 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;
|
| + }
|
| +}
|
| +
|
| +// Tests parallel validation similar to the above test, except here cache write
|
| +// fails and the validated transactions should be restarted.
|
| +TEST(HttpCache, SimpleGET_ParallelValidationFailWrite) {
|
| + MockHttpCache cache;
|
| +
|
| + std::vector<MockHttpRequest> request;
|
| + ScopedMockTransaction transaction(kTypicalGET_Transaction);
|
| + transaction.response_headers =
|
| + "Etag: \"foopy\"\n"
|
| + "Cache-Control: max-age=0\n";
|
| + MockHttpRequest request0(transaction);
|
| + request.push_back(request0);
|
| +
|
| + ScopedMockTransaction transaction1(kTypicalGET_Transaction);
|
| + transaction1.status = "HTTP/1.1 304 Not Modified";
|
| + transaction1.load_flags |= LOAD_VALIDATE_CACHE;
|
| + transaction1.response_headers =
|
| + "Etag: \"foopy\"\n"
|
| + "Cache-Control: max-age=3600\n";
|
| + MockHttpRequest request1(transaction1);
|
| + request.push_back(request1);
|
| +
|
| + std::vector<Context*> context_list;
|
| + const int kNumTransactions = 2;
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + context_list.push_back(new Context());
|
| + Context* c = context_list[i];
|
| +
|
| + c->result = cache.CreateTransaction(&c->trans);
|
| + ASSERT_THAT(c->result, IsOk());
|
| + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
|
| +
|
| + c->result = c->trans->Start(&request[i], c->callback.callback(),
|
| + NetLogWithSource());
|
| + }
|
| +
|
| + // All requests are waiting for the active entry.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
|
| + }
|
| +
|
| + // Allow all requests to move from the Create queue to the active entry.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // The first request should be a writer at this point, and the subsequent
|
| + // requests should have passed the validation phase and waiting for the
|
| + // response to be written to the cache before they can read.
|
| +
|
| + EXPECT_EQ(2, cache.network_layer()->transaction_count());
|
| + EXPECT_EQ(0, cache.disk_cache()->open_count());
|
| + EXPECT_EQ(1, cache.disk_cache()->create_count());
|
| +
|
| + // All requests depend on the writer, and the writer is between Start and
|
| + // Read, i.e. idle.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
|
| + }
|
| +
|
| + // Fail the request.
|
| + cache.disk_cache()->set_soft_failures(true);
|
| + // We have to open the entry again to propagate the failure flag.
|
| + disk_cache::Entry* en;
|
| + cache.OpenBackendEntry(kTypicalGET_Transaction.url, &en);
|
| + en->Close();
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + if (c->result == 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
|
| +
|
| + // Since validated transaction was restarted, there is an additional network
|
| + // transaction created.
|
| + EXPECT_EQ(3, cache.network_layer()->transaction_count());
|
| + EXPECT_EQ(1, cache.disk_cache()->open_count());
|
| + EXPECT_EQ(2, cache.disk_cache()->create_count());
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + delete c;
|
| + }
|
| +}
|
| +
|
| // 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
|
| @@ -1451,11 +1621,12 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
|
| c->result = c->callback.WaitForResult();
|
| ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
|
|
|
| - // Now we have 2 active readers and two queued transactions.
|
| -
|
| + // Now all transactions should be waiting for read to be invoked. Two readers
|
| + // are because of the load flags and remaining two transactions were converted
|
| + // to readers after skipping validation. Note that the remaining two went on
|
| + // to process the headers in parallel with readers presnt on the entry.
|
| EXPECT_EQ(LOAD_STATE_IDLE, context_list[2]->trans->GetLoadState());
|
| - EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE,
|
| - context_list[3]->trans->GetLoadState());
|
| + EXPECT_EQ(LOAD_STATE_IDLE, context_list[3]->trans->GetLoadState());
|
|
|
| c = context_list[1];
|
| ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
|
| @@ -1520,12 +1691,16 @@ TEST(HttpCache, SimpleGET_DoomWithPending) {
|
| NetLogWithSource());
|
| }
|
|
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| // The first request should be a writer at this point, and the two subsequent
|
| // requests should be pending. The last request doomed the first entry.
|
|
|
| EXPECT_EQ(2, cache.network_layer()->transaction_count());
|
|
|
| - // Cancel the first queued transaction.
|
| + // Cancel the second transaction. Note that this and the 3rd transactions
|
| + // would have completed their headers phase and would be waiting in the
|
| + // done_headers_queue when the 2nd transaction is cancelled.
|
| context_list[1].reset();
|
|
|
| for (int i = 0; i < kNumTransactions; ++i) {
|
| @@ -1567,11 +1742,12 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
|
| base::RunLoop().RunUntilIdle();
|
|
|
| // The first request should be a writer at this point, and the subsequent
|
| - // requests should be pending.
|
| + // requests should have completed validation. Since the validation does not
|
| + // result in a match, a new entry would be created.
|
|
|
| - EXPECT_EQ(1, cache.network_layer()->transaction_count());
|
| + EXPECT_EQ(3, cache.network_layer()->transaction_count());
|
| EXPECT_EQ(0, cache.disk_cache()->open_count());
|
| - EXPECT_EQ(1, cache.disk_cache()->create_count());
|
| + EXPECT_EQ(2, cache.disk_cache()->create_count());
|
|
|
| // Now, make sure that the second request asks for the entry not to be stored.
|
| request_handler.set_no_store(true);
|
| @@ -1625,6 +1801,9 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
|
| if (c->result == ERR_IO_PENDING)
|
| c->result = c->callback.WaitForResult();
|
| // Destroy only the first transaction.
|
| + // This should lead to all transactions to restart, even those that have
|
| + // validated themselves and were waiting for the writer transaction to
|
| + // complete writing to the cache.
|
| if (i == 0) {
|
| delete c;
|
| context_list[i] = NULL;
|
| @@ -1649,6 +1828,137 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
|
| }
|
| }
|
|
|
| +// Tests that a transaction which is in validated queue can be destroyed without
|
| +// any impact to other transactions.
|
| +TEST(HttpCache, SimpleGET_ManyWriters_CancelValidated) {
|
| + MockHttpCache cache;
|
| +
|
| + MockHttpRequest request(kSimpleGET_Transaction);
|
| +
|
| + std::vector<Context*> context_list;
|
| + const int kNumTransactions = 2;
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + context_list.push_back(new Context());
|
| + Context* c = context_list[i];
|
| +
|
| + c->result = cache.CreateTransaction(&c->trans);
|
| + ASSERT_THAT(c->result, IsOk());
|
| +
|
| + c->result =
|
| + c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
|
| + }
|
| +
|
| + // Allow all requests to move from the Create queue to the active entry.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // 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());
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + Context* c = context_list[i];
|
| + if (i == 0 && c->result == ERR_IO_PENDING)
|
| + c->result = c->callback.WaitForResult();
|
| + // Destroy one of the transactions waiting after the validated stage.
|
| + if (i == 1) {
|
| + delete c;
|
| + context_list[i] = NULL;
|
| + }
|
| + }
|
| +
|
| + // Complete the rest of the transactions.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + if (i == 1)
|
| + continue;
|
| + Context* c = context_list[i];
|
| + ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
|
| + }
|
| +
|
| + // We should 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) {
|
| + if (i == 1)
|
| + continue;
|
| + Context* c = context_list[i];
|
| + delete c;
|
| + }
|
| +}
|
| +
|
| +// Tests that a transaction which is currently validating can be destroyed
|
| +// without any impact to other transactions.
|
| +TEST(HttpCache, SimpleGET_ManyWriters_CancelValidating) {
|
| + MockHttpCache cache;
|
| +
|
| + MockHttpRequest request(kSimpleGET_Transaction);
|
| +
|
| + std::vector<Context*> context_list;
|
| + const int kNumTransactions = 2;
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + context_list.push_back(new Context());
|
| + Context* c = context_list[i];
|
| +
|
| + c->result = cache.CreateTransaction(&c->trans);
|
| + ASSERT_THAT(c->result, IsOk());
|
| +
|
| + c->result =
|
| + c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
|
| + }
|
| +
|
| + // Delete the currently validating transaction.
|
| + Context* c = context_list[1];
|
| + EXPECT_EQ(ERR_IO_PENDING, c->result);
|
| + delete c;
|
| + context_list[1] = nullptr;
|
| +
|
| + // Allow all requests to move from the Create queue to the active entry.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // 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());
|
| +
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + if (i == 1)
|
| + continue;
|
| + Context* c = context_list[i];
|
| + if (c->result == ERR_IO_PENDING)
|
| + c->result = c->callback.WaitForResult();
|
| + }
|
| +
|
| + // Complete the rest of the transactions.
|
| + for (int i = 0; i < kNumTransactions; ++i) {
|
| + if (i == 1)
|
| + continue;
|
| + Context* c = context_list[i];
|
| + ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
|
| + }
|
| +
|
| + // We should 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) {
|
| + if (i == 1)
|
| + continue;
|
| + Context* c = context_list[i];
|
| + delete c;
|
| + }
|
| +}
|
| +
|
| // Tests that we can cancel requests that are queued waiting to open the disk
|
| // cache entry.
|
| TEST(HttpCache, SimpleGET_ManyWriters_CancelCreate) {
|
| @@ -2540,6 +2850,8 @@ TEST(HttpCache, ETagGET_ConditionalRequest_304_NoStore) {
|
| // be returned.
|
| // (4) loads |kUrl| from cache only -- expects |cached_response_2| to be
|
| // returned.
|
| +// The entry will be created once and will be opened for the 3 subsequent
|
| +// requests.
|
| static void ConditionalizedRequestUpdatesCacheHelper(
|
| const Response& net_response_1,
|
| const Response& net_response_2,
|
| @@ -6115,12 +6427,14 @@ TEST(HttpCache, GET_IncompleteResource_Cancel) {
|
| EXPECT_EQ(5, c->callback.GetResult(rv));
|
|
|
| // Cancel the requests.
|
| + // Since |pending| is currently vaidating the already written headers
|
| + // it will be restarted as well.
|
| delete c;
|
| delete pending;
|
|
|
| EXPECT_EQ(1, cache.network_layer()->transaction_count());
|
| EXPECT_EQ(1, cache.disk_cache()->open_count());
|
| - EXPECT_EQ(2, cache.disk_cache()->create_count());
|
| + EXPECT_EQ(1, cache.disk_cache()->create_count());
|
|
|
| base::RunLoop().RunUntilIdle();
|
| RemoveMockTransaction(&transaction);
|
| @@ -6845,46 +7159,6 @@ TEST(HttpCache, WriteMetadata_Fail) {
|
| EXPECT_EQ(1, cache.disk_cache()->create_count());
|
| }
|
|
|
| -// Tests that if a metadata writer transaction hits cache lock timeout, it will
|
| -// error out.
|
| -TEST(HttpCache, WriteMetadata_CacheLockTimeout) {
|
| - MockHttpCache cache;
|
| -
|
| - // Write to the cache
|
| - HttpResponseInfo response;
|
| - RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
|
| - &response);
|
| - EXPECT_FALSE(response.metadata.get());
|
| -
|
| - MockHttpRequest request(kSimpleGET_Transaction);
|
| - Context c1;
|
| - ASSERT_THAT(cache.CreateTransaction(&c1.trans), IsOk());
|
| - ASSERT_EQ(ERR_IO_PENDING, c1.trans->Start(&request, c1.callback.callback(),
|
| - NetLogWithSource()));
|
| -
|
| - cache.SimulateCacheLockTimeout();
|
| -
|
| - // Write meta data to the same entry.
|
| - scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(50));
|
| - memset(buf->data(), 0, buf->size());
|
| - base::strlcpy(buf->data(), "Hi there", buf->size());
|
| - cache.http_cache()->WriteMetadata(GURL(kSimpleGET_Transaction.url),
|
| - DEFAULT_PRIORITY, response.response_time,
|
| - buf.get(), buf->size());
|
| -
|
| - // Release the buffer before the operation takes place.
|
| - buf = NULL;
|
| -
|
| - // Makes sure we finish pending operations.
|
| - base::RunLoop().RunUntilIdle();
|
| -
|
| - RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
|
| - &response);
|
| -
|
| - // The writer transaction should fail due to cache lock timeout.
|
| - ASSERT_FALSE(response.metadata.get());
|
| -}
|
| -
|
| // Tests that we ignore VARY checks when writing metadata since the request
|
| // headers for the WriteMetadata transaction are made up.
|
| TEST(HttpCache, WriteMetadata_IgnoreVary) {
|
| @@ -7212,10 +7486,6 @@ TEST(HttpCache, StopCachingWithAuthDeletesEntry) {
|
| EXPECT_THAT(callback.GetResult(rv), IsOk());
|
|
|
| trans->StopCaching();
|
| -
|
| - scoped_refptr<IOBuffer> buf(new IOBuffer(256));
|
| - rv = trans->Read(buf.get(), 10, callback.callback());
|
| - EXPECT_EQ(callback.GetResult(rv), 10);
|
| }
|
| RemoveMockTransaction(&mock_transaction);
|
|
|
|
|