Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Unified Diff: net/http/http_cache_unittest.cc

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Initial patch Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/http_cache_unittest.cc
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index f6cba7a12b7317c97e97adce75f51707ee05616a..a2f8fe6eaa5740a783fbe87d9cdc1b14d780f1c2 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -148,6 +148,203 @@ void ReadAndVerifyTransaction(HttpTransaction* trans,
EXPECT_EQ(expected, content);
}
+void ReadAndVerifySharedWritersCacheRead(std::vector<Context*>& context_list,
+ const MockTransaction& trans_info) {
+ std::vector<std::string> contents(context_list.size());
+ int rv = ReadSharedWritersCacheRead(context_list, contents);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < contents.size(); i++) {
+ EXPECT_EQ(expected, contents.at(i));
+ }
+}
+
+void ReadAndVerifySharedWritersJoinedRead(const MockTransaction& trans_info,
+ std::vector<Context*>& context_list) {
+ std::vector<std::string> results(context_list.size());
+ int rv = ReadSharedWritersJoinedRead(context_list, results);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < results.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
+void ReadAndVerifySharedWritersJoinedReadDoneReading(
+ const MockTransaction& trans_info,
+ std::vector<Context*>& context_list) {
+ std::vector<std::string> results(context_list.size());
+ int rv = ReadSharedWritersJoinedReadDoneReading(context_list, results);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < results.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
+void ReadAndVerifySharedWritersJoinedReadDoomCurrentWriter(
+ const MockTransaction& trans_info,
+ std::vector<Context*>& context_list) {
+ std::vector<std::string> results(context_list.size() - 1);
+ int rv = ReadSharedWritersJoinedReadDoomCurrentWriter(context_list, results);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < results.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
+void ReadAndVerifySharedWritersDeleteWaitingWriter(
+ const MockTransaction& trans_info,
+ std::vector<Context*>& context_list) {
+ std::vector<std::string> results(context_list.size() - 1);
+ int rv =
+ ReadSharedWritersJoinedReadDeleteWaitingWriter(context_list, results);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < results.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
+void ReadAndVerifySharedWritersDeleteIdleWriter(
+ const MockTransaction& trans_info,
+ std::vector<Context*>& context_list) {
+ std::vector<std::string> results(context_list.size() - 1);
+ int rv = ReadSharedWritersJoinedReadDeleteIdleWriter(context_list, results);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < results.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
+int ReadSharedWritersJoinedReadCacheWriteFailure(
+ std::vector<Context*>& context_list,
+ std::vector<std::string>& results,
+ MockHttpCache& cache) {
+ int rv = 0;
+ MockHttpRequest request(kSimpleGET_Transaction);
+
+ // 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(kSimpleGET_Transaction.url, &en);
+ en->Close();
+
+ // Invoke Read for a few transactions so they become current_writer_ and
+ // waiting_writers_ respectively.
+ std::vector<scoped_refptr<IOBuffer>> buf(2);
+ size_t i = 0, j = 0;
+ do {
+ HttpTransaction* trans = context_list[i]->trans.get();
+ buf[j] = new IOBuffer(30);
+ rv = trans->Read(buf[j].get(), 30, context_list[i]->callback.callback());
+ i = context_list.size() - 1;
+ j++;
+ } while (j < buf.size());
+
+ // current_writer_ which is transaction [0] should continue without writing
+ // to the cache, idle writer ([3]) should fail on its next Read call and
+ // waiting_writers_ ([6]) should return a failure back.
+ if (rv == ERR_IO_PENDING) {
+ Context* ct = *(context_list.begin());
+ rv = ct->callback.WaitForResult();
+ }
+
+ // Only [0] should succeed in the Read.
+ results[0].append(buf[0]->data(), 30);
+
+ // Invoke Start on 4 and 5. 4 will fail to read from the cache, doom the
+ // entry and go on to create a new entry. 5 will also get added to that
+ // entry.
+ for (size_t i = 4; i <= 5; i++) {
+ Context* c = context_list[i];
+ c->result =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ }
+
+ base::RunLoop().RunUntilIdle();
+
+ // 3 and 6 failed, delete them.
+ Context* c = context_list[3];
+ scoped_refptr<IOBuffer> buf1 = new IOBuffer(30);
+ int rv_fail = c->trans->Read(buf1.get(), 30, c->callback.callback());
+ EXPECT_THAT(rv_fail, ERR_CACHE_WRITE_FAILURE);
+
+ Context* c6 = context_list[6];
+ for (auto itr = context_list.begin(); itr != context_list.end();) {
+ if (*itr == c || *itr == c6) {
+ Context* ct = *itr;
+ itr = context_list.erase(itr);
+ delete ct;
+ } else {
+ itr++;
+ }
+ }
+
+ cache.disk_cache()->set_soft_failures(false);
+
+ base::RunLoop().RunUntilIdle();
+
+ // Read for the rest of the transactions.
+ Context* c0 = context_list[0];
+ Context* c3 = context_list[3];
+ for (size_t i = 0; i < context_list.size(); i++) {
+ if (i == 1 || i == 2 || i == 4)
+ continue;
+ std::string res;
+ ReadTransaction(context_list[i]->trans.get(), &res);
+ results[i].append(res);
+ }
+
+ base::RunLoop().RunUntilIdle();
+
+ // Delete the done transactions so that pending queue can be processed.
+ // The reader transactions will error out with ERR_CACHE_MISS because of cache
+ // failures.
+ Context* c1 = context_list[1];
+ Context* c2 = context_list[2];
+ auto itr = context_list.begin();
+ for (; itr != context_list.end();) {
+ Context* c = *itr;
+ if (c == c0 || c == c1 || c == c2 || c == c3) {
+ itr = context_list.erase(itr);
+ delete c;
+ } else {
+ itr++;
+ }
+ }
+
+ std::string res;
+ ReadTransaction(context_list[0]->trans.get(), &res);
+ results[4].append(res);
+
+ return OK;
+}
+
+void ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(
+ const MockTransaction& trans_info,
+ std::vector<Context*>& context_list,
+ MockHttpCache& cache) {
+ std::vector<std::string> results(context_list.size());
+ int rv = ReadSharedWritersJoinedReadCacheWriteFailure(context_list, results,
+ cache);
+
+ EXPECT_THAT(rv, IsOk());
+ std::string expected(trans_info.data);
+ for (size_t i = 0; i < context_list.size(); i++) {
+ EXPECT_EQ(expected, results[i]);
+ }
+}
+
void RunTransactionTestBase(HttpCache* cache,
const MockTransaction& trans_info,
const MockHttpRequest& request,
@@ -157,24 +354,22 @@ void RunTransactionTestBase(HttpCache* cache,
int64_t* sent_bytes,
int64_t* received_bytes,
IPEndPoint* remote_endpoint) {
- TestCompletionCallback callback;
-
// write to the cache
- std::unique_ptr<HttpTransaction> trans;
- int rv = cache->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ Context* c = new Context();
+ int rv = cache->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
- ASSERT_TRUE(trans.get());
+ ASSERT_TRUE(c->trans.get());
- rv = trans->Start(&request, callback.callback(), net_log);
+ rv = c->trans->Start(&request, c->callback.callback(), net_log);
if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
+ rv = c->callback.WaitForResult();
ASSERT_EQ(trans_info.return_code, rv);
if (OK != rv)
return;
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = c->trans->GetResponseInfo();
ASSERT_TRUE(response);
if (response_info)
@@ -185,18 +380,20 @@ void RunTransactionTestBase(HttpCache* cache,
// ID.
EXPECT_TRUE(net_log.net_log());
*load_timing_info = LoadTimingInfo();
- trans->GetLoadTimingInfo(load_timing_info);
+ c->trans->GetLoadTimingInfo(load_timing_info);
}
if (remote_endpoint)
- ASSERT_TRUE(trans->GetRemoteEndpoint(remote_endpoint));
+ ASSERT_TRUE(c->trans->GetRemoteEndpoint(remote_endpoint));
- ReadAndVerifyTransaction(trans.get(), trans_info);
+ ReadAndVerifyTransaction(c->trans.get(), trans_info);
if (sent_bytes)
- *sent_bytes = trans->GetTotalSentBytes();
+ *sent_bytes = c->trans->GetTotalSentBytes();
if (received_bytes)
- *received_bytes = trans->GetTotalReceivedBytes();
+ *received_bytes = c->trans->GetTotalReceivedBytes();
+
+ delete c;
}
void RunTransactionTestWithRequest(HttpCache* cache,
@@ -572,14 +769,6 @@ struct Response {
const char* body;
};
-struct Context {
- Context() : result(ERR_IO_PENDING) {}
-
- int result;
- TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
-};
-
class FakeWebSocketHandshakeStreamCreateHelper
: public WebSocketHandshakeStreamBase::CreateHelper {
public:
@@ -641,9 +830,10 @@ bool LogContainsEventType(const BoundTestNetLog& log,
TEST(HttpCache, CreateThenDestroy) {
MockHttpCache cache;
- std::unique_ptr<HttpTransaction> trans;
- EXPECT_THAT(cache.CreateTransaction(&trans), IsOk());
- ASSERT_TRUE(trans.get());
+ Context* c = new Context();
+ EXPECT_THAT(cache.CreateTransaction(&c->trans), IsOk());
+ ASSERT_TRUE(c->trans.get());
+ delete c;
}
TEST(HttpCache, GetBackend) {
@@ -732,18 +922,20 @@ TEST(HttpCache, ReleaseBuffer) {
RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
MockHttpRequest request(kSimpleGET_Transaction);
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ Context* c = new Context();
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
const int kBufferSize = 10;
scoped_refptr<IOBuffer> buffer(new IOBuffer(kBufferSize));
ReleaseBufferCompletionCallback cb(buffer.get());
- int rv = trans->Start(&request, cb.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, cb.callback(), NetLogWithSource());
EXPECT_THAT(cb.GetResult(rv), IsOk());
- rv = trans->Read(buffer.get(), kBufferSize, cb.callback());
+ rv = c->trans->Read(buffer.get(), kBufferSize, cb.callback());
EXPECT_EQ(kBufferSize, cb.GetResult(rv));
+
+ delete c;
}
TEST(HttpCache, SimpleGETWithDiskFailures) {
@@ -920,18 +1112,16 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) {
transaction.load_flags |= LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
MockHttpRequest request(transaction);
- TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
+ rv = c->callback.WaitForResult();
ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
- trans.reset();
-
EXPECT_EQ(0, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
EXPECT_EQ(0, cache.disk_cache()->create_count());
@@ -1038,20 +1228,21 @@ TEST(HttpCache, SimpleGET_CacheSignal_Failure) {
AddMockTransaction(&transaction);
MockHttpRequest request(transaction);
- TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ Context* c = new Context();
+ int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
- ASSERT_TRUE(trans.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_FAILED));
+ ASSERT_TRUE(c->trans.get());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsError(ERR_FAILED));
- const HttpResponseInfo* response_info = trans->GetResponseInfo();
+ const HttpResponseInfo* response_info = c->trans->GetResponseInfo();
ASSERT_TRUE(response_info);
EXPECT_TRUE(response_info->was_cached);
EXPECT_EQ(2, cache.network_layer()->transaction_count());
RemoveMockTransaction(&transaction);
+
+ delete c;
}
// Confirm if we have an empty cache, a read is marked as network verified.
@@ -1342,8 +1533,9 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
// 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.
+ // At the end of Start: [0] should be in shared_writers->all_writers_,
+ // [3] and [4] should also be in all_writers_ since its a case of validation
+ // match/skip, [1] and [2] should be in pending_queue.
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1419,11 +1611,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.
-
+ // after [0] completes reading and writing, [3] and [4] should be added to
+ // entry->readers from shared writers and pending queue should be
+ // processed to add [1] and [2] to readers as well. They are all waiting for
+ // their consumer to invoke Read.
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));
@@ -1437,7 +1630,9 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
// next request.
c = context_list[2];
- c->trans.reset();
+ if (c->trans) {
+ c->trans->Orphan(std::move(c->trans));
+ }
for (int i = 3; i < kNumTransactions; ++i) {
Context* c = context_list[i];
@@ -1537,9 +1732,9 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
// 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(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);
@@ -1582,7 +1777,8 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
base::RunLoop().RunUntilIdle();
// The first request should be a writer at this point, and the subsequent
- // requests should be pending.
+ // requests should have been added to SharedWriters, skipped validation and
+ // completed the start state machine of HttpCache::Transaction.
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1605,11 +1801,11 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
}
- // We should have had to re-open the disk entry.
-
- EXPECT_EQ(2, cache.network_layer()->transaction_count());
+ // 2nd transaction will reuse the network transaction as they are both part of
+ // SharedWriters. Similarly it will be part of the same entry.
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
- EXPECT_EQ(2, cache.disk_cache()->create_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
for (int i = 1; i < kNumTransactions; ++i) {
Context* c = context_list[i];
@@ -1791,7 +1987,9 @@ TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
// Test that destroying the transaction while it is reading from the cache
// works properly.
- trans.reset();
+ if (trans) {
+ trans->Orphan(std::move(trans));
+ }
// Make sure we pump any pending events, which should include a call to
// HttpCache::Transaction::OnCacheReadCompleted.
@@ -2960,15 +3158,13 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) {
MockHttpRequest request(transaction);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- ASSERT_TRUE(trans.get());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
+ ASSERT_TRUE(c->trans.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
ASSERT_THAT(callback.GetResult(rv), IsError(ERR_CACHE_MISS));
- trans.reset();
-
EXPECT_EQ(0, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
EXPECT_EQ(0, cache.disk_cache()->create_count());
@@ -3215,15 +3411,13 @@ TEST(HttpCache, SimpleHEAD_LoadOnlyFromCache_Miss) {
MockHttpRequest request(transaction);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- ASSERT_TRUE(trans.get());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
+ ASSERT_TRUE(c->trans.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
ASSERT_THAT(callback.GetResult(rv), IsError(ERR_CACHE_MISS));
- trans.reset();
-
EXPECT_EQ(0, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
EXPECT_EQ(0, cache.disk_cache()->create_count());
@@ -5610,17 +5804,17 @@ TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) {
MockHttpRequest request(transaction);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ std::unique_ptr<Context> c(new Context());
+ int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
- ASSERT_TRUE(trans.get());
+ ASSERT_TRUE(c->trans.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
- trans.reset();
+ c.reset();
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
@@ -5831,7 +6025,9 @@ TEST(HttpCache, SetTruncatedFlag) {
MockHttpCache::SetTestMode(TEST_MODE_SYNC_ALL);
// Destroy the transaction.
- c->trans.reset();
+ if (c->trans) {
+ c->trans->Orphan(std::move(c->trans));
+ }
MockHttpCache::SetTestMode(0);
@@ -5841,8 +6037,10 @@ TEST(HttpCache, SetTruncatedFlag) {
// notification from the transaction destructor (see http://crbug.com/31723).
EXPECT_FALSE(c->callback.have_result());
- // Verify that the entry is marked as incomplete.
- VerifyTruncatedFlag(&cache, kSimpleGET_Transaction.url, true, 0);
+ // Verify that the entry is not marked as incomplete since SharedWriters
+ // enables response writing to complete even if transaction is destroyed
+ // mid-way.
+ VerifyTruncatedFlag(&cache, kSimpleGET_Transaction.url, false, 0);
}
// Tests that we don't mark an entry as truncated when we read everything.
@@ -5869,7 +6067,9 @@ TEST(HttpCache, DontSetTruncatedFlag) {
EXPECT_EQ(buf->size(), c->callback.GetResult(rv));
// Destroy the transaction.
- c->trans.reset();
+ if (c->trans) {
+ c->trans->Orphan(std::move(c->trans));
+ }
// Verify that the entry is not marked as truncated.
VerifyTruncatedFlag(&cache, kSimpleGET_Transaction.url, false, 0);
@@ -5883,21 +6083,19 @@ TEST(HttpCache, RangeGET_DontTruncate) {
transaction.request_headers = "Range: bytes = 0-19\r\n" EXTRA_HEADER;
std::unique_ptr<MockHttpRequest> request(new MockHttpRequest(transaction));
- std::unique_ptr<HttpTransaction> trans;
+ std::unique_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
TestCompletionCallback cb;
- rv = trans->Start(request.get(), cb.callback(), NetLogWithSource());
+ rv = c->trans->Start(request.get(), cb.callback(), NetLogWithSource());
EXPECT_EQ(0, cb.GetResult(rv));
scoped_refptr<IOBuffer> buf(new IOBuffer(10));
- rv = trans->Read(buf.get(), 10, cb.callback());
+ rv = c->trans->Read(buf.get(), 10, cb.callback());
EXPECT_EQ(10, cb.GetResult(rv));
- // Should not trigger any DCHECK.
- trans.reset();
VerifyTruncatedFlag(&cache, kRangeGET_TransactionOK.url, false, 0);
}
@@ -5910,21 +6108,20 @@ TEST(HttpCache, RangeGET_DontTruncate2) {
transaction.request_headers = "Range: bytes = 30-49\r\n" EXTRA_HEADER;
std::unique_ptr<MockHttpRequest> request(new MockHttpRequest(transaction));
- std::unique_ptr<HttpTransaction> trans;
+ std::unique_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
- TestCompletionCallback cb;
- rv = trans->Start(request.get(), cb.callback(), NetLogWithSource());
- EXPECT_EQ(0, cb.GetResult(rv));
+ rv = c->trans->Start(request.get(), c->callback.callback(),
+ NetLogWithSource());
+ EXPECT_EQ(0, c->callback.GetResult(rv));
scoped_refptr<IOBuffer> buf(new IOBuffer(10));
- rv = trans->Read(buf.get(), 10, cb.callback());
- EXPECT_EQ(10, cb.GetResult(rv));
+ rv = c->trans->Read(buf.get(), 10, c->callback.callback());
+ EXPECT_EQ(10, c->callback.GetResult(rv));
// Should not trigger any DCHECK.
- trans.reset();
VerifyTruncatedFlag(&cache, kRangeGET_TransactionOK.url, false, 0);
}
@@ -6388,15 +6585,15 @@ TEST(HttpCache, CachedRedirect) {
// Write to the cache.
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_THAT(rv, IsOk());
- const HttpResponseInfo* info = trans->GetResponseInfo();
+ const HttpResponseInfo* info = c->trans->GetResponseInfo();
ASSERT_TRUE(info);
EXPECT_EQ(info->headers->response_code(), 301);
@@ -6406,7 +6603,7 @@ TEST(HttpCache, CachedRedirect) {
EXPECT_EQ(location, "http://www.bar.com/");
// Mark the transaction as completed so it is cached.
- trans->DoneReading();
+ c->trans->DoneReading();
// Destroy transaction when going out of scope. We have not actually
// read the response body -- want to test that it is still getting cached.
@@ -6422,15 +6619,15 @@ TEST(HttpCache, CachedRedirect) {
// Read from the cache.
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_THAT(rv, IsOk());
- const HttpResponseInfo* info = trans->GetResponseInfo();
+ const HttpResponseInfo* info = c->trans->GetResponseInfo();
ASSERT_TRUE(info);
EXPECT_EQ(info->headers->response_code(), 301);
@@ -6440,7 +6637,7 @@ TEST(HttpCache, CachedRedirect) {
EXPECT_EQ(location, "http://www.bar.com/");
// Mark the transaction as completed so it is cached.
- trans->DoneReading();
+ c->trans->DoneReading();
// Destroy transaction when going out of scope. We have not actually
// read the response body -- want to test that it is still getting cached.
@@ -6601,14 +6798,14 @@ TEST(HttpCache, SimpleGET_SSLError) {
transaction.load_flags |= LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
MockHttpRequest request(transaction);
- TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
+ rv = c->callback.WaitForResult();
ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
}
@@ -6616,11 +6813,10 @@ TEST(HttpCache, SimpleGET_SSLError) {
TEST(HttpCache, OutlivedTransactions) {
MockHttpCache* cache = new MockHttpCache;
- std::unique_ptr<HttpTransaction> trans;
- EXPECT_THAT(cache->CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ EXPECT_THAT(cache->CreateTransaction(&c->trans), IsOk());
delete cache;
- trans.reset();
}
// Test that the disabled mode works.
@@ -6899,19 +7095,19 @@ TEST(HttpCache, FilterCompletion) {
TestCompletionCallback callback;
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
MockHttpRequest request(kSimpleGET_Transaction);
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_GT(callback.GetResult(rv), 0);
// Now make sure that the entry is preserved.
- trans->DoneReading();
+ c->trans->DoneReading();
}
// Make sure that the ActiveEntry is gone.
@@ -6935,14 +7131,14 @@ TEST(HttpCache, DoneReading) {
ScopedMockTransaction transaction(kSimpleGET_Transaction);
transaction.data = "";
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
MockHttpRequest request(transaction);
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
- trans->DoneReading();
+ c->trans->DoneReading();
// Leave the transaction around.
// Make sure that the ActiveEntry is gone.
@@ -6959,27 +7155,27 @@ TEST(HttpCache, DoneReading) {
// Tests that we stop caching when told.
TEST(HttpCache, StopCachingDeletesEntry) {
MockHttpCache cache;
- TestCompletionCallback callback;
MockHttpRequest request(kSimpleGET_Transaction);
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
+ int rv =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 10, callback.callback());
- EXPECT_EQ(10, callback.GetResult(rv));
+ rv = c->trans->Read(buf.get(), 10, c->callback.callback());
+ EXPECT_EQ(10, c->callback.GetResult(rv));
- trans->StopCaching();
+ c->trans->StopCaching();
// We should be able to keep reading.
- rv = trans->Read(buf.get(), 256, callback.callback());
- EXPECT_GT(callback.GetResult(rv), 0);
- rv = trans->Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(0, callback.GetResult(rv));
+ rv = c->trans->Read(buf.get(), 256, c->callback.callback());
+ EXPECT_GT(c->callback.GetResult(rv), 0);
+ rv = c->trans->Read(buf.get(), 256, c->callback.callback());
+ EXPECT_EQ(0, c->callback.GetResult(rv));
}
// Make sure that the ActiveEntry is gone.
@@ -7001,26 +7197,26 @@ TEST(HttpCache, StopCachingThenDoneReadingDeletesEntry) {
MockHttpRequest request(kSimpleGET_Transaction);
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 10, callback.callback());
+ rv = c->trans->Read(buf.get(), 10, callback.callback());
EXPECT_EQ(10, callback.GetResult(rv));
- trans->StopCaching();
+ c->trans->StopCaching();
// We should be able to keep reading.
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_GT(callback.GetResult(rv), 0);
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_EQ(0, callback.GetResult(rv));
// We should be able to call DoneReading.
- trans->DoneReading();
+ c->trans->DoneReading();
}
// Make sure that the ActiveEntry is gone.
@@ -7044,16 +7240,16 @@ TEST(HttpCache, StopCachingWithAuthDeletesEntry) {
MockHttpRequest request(mock_transaction);
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
- trans->StopCaching();
+ c->trans->StopCaching();
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 10, callback.callback());
+ rv = c->trans->Read(buf.get(), 10, callback.callback());
EXPECT_EQ(callback.GetResult(rv), 10);
}
RemoveMockTransaction(&mock_transaction);
@@ -7076,8 +7272,8 @@ TEST(HttpCache, StopCachingSavesEntry) {
MockHttpRequest request(kSimpleGET_Transaction);
{
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
// Force a response that can be resumed.
ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
@@ -7086,19 +7282,19 @@ TEST(HttpCache, StopCachingSavesEntry) {
"Content-Length: 42\n"
"Etag: \"foo\"\n";
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 10, callback.callback());
+ rv = c->trans->Read(buf.get(), 10, callback.callback());
EXPECT_EQ(callback.GetResult(rv), 10);
- trans->StopCaching();
+ c->trans->StopCaching();
// We should be able to keep reading.
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_GT(callback.GetResult(rv), 0);
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_EQ(callback.GetResult(rv), 0);
}
@@ -7124,25 +7320,25 @@ TEST(HttpCache, StopCachingTruncatedEntry) {
{
// Now make a regular request.
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ std::unique_ptr<Context> c(new Context());
+ ASSERT_THAT(cache.CreateTransaction(&c->trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ int rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 10, callback.callback());
+ rv = c->trans->Read(buf.get(), 10, callback.callback());
EXPECT_EQ(callback.GetResult(rv), 10);
// This is actually going to do nothing.
- trans->StopCaching();
+ c->trans->StopCaching();
// We should be able to keep reading.
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_GT(callback.GetResult(rv), 0);
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_GT(callback.GetResult(rv), 0);
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = c->trans->Read(buf.get(), 256, callback.callback());
EXPECT_EQ(callback.GetResult(rv), 0);
}
@@ -7369,41 +7565,40 @@ TEST_P(HttpCacheHugeResourceTest,
MockHttpRequest request(transaction);
net::TestCompletionCallback callback;
- std::unique_ptr<net::HttpTransaction> http_transaction;
- int rv = cache.http_cache()->CreateTransaction(net::DEFAULT_PRIORITY,
- &http_transaction);
+ std::unique_ptr<Context> c(new Context());
+ int rv =
+ cache.http_cache()->CreateTransaction(net::DEFAULT_PRIORITY, &c->trans);
ASSERT_EQ(net::OK, rv);
- ASSERT_TRUE(http_transaction.get());
+ ASSERT_TRUE(c->trans.get());
bool network_transaction_started = false;
if (stop_caching_phase == TransactionPhase::AFTER_NETWORK_READ) {
- http_transaction->SetBeforeNetworkStartCallback(
+ c->trans->SetBeforeNetworkStartCallback(
base::Bind(&SetFlagOnBeforeNetworkStart, &network_transaction_started));
}
- rv = http_transaction->Start(&request, callback.callback(),
- NetLogWithSource());
+ rv = c->trans->Start(&request, callback.callback(), NetLogWithSource());
rv = callback.GetResult(rv);
ASSERT_EQ(net::OK, rv);
if (stop_caching_phase == TransactionPhase::BEFORE_FIRST_READ)
- http_transaction->StopCaching();
+ c->trans->StopCaching();
int64_t total_bytes_received = 0;
EXPECT_EQ(kTotalSize,
- http_transaction->GetResponseInfo()->headers->GetContentLength());
+ c->trans->GetResponseInfo()->headers->GetContentLength());
do {
// This test simulates reading gigabytes of data. Buffer size is set to 10MB
// to reduce the number of reads and speed up the test.
const int kBufferSize = 1024 * 1024 * 10;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufferSize));
- rv = http_transaction->Read(buf.get(), kBufferSize, callback.callback());
+ rv = c->trans->Read(buf.get(), kBufferSize, callback.callback());
rv = callback.GetResult(rv);
if (stop_caching_phase == TransactionPhase::AFTER_FIRST_READ &&
total_bytes_received == 0) {
- http_transaction->StopCaching();
+ c->trans->StopCaching();
}
if (rv > 0)
@@ -7411,7 +7606,7 @@ TEST_P(HttpCacheHugeResourceTest,
if (network_transaction_started &&
stop_caching_phase == TransactionPhase::AFTER_NETWORK_READ) {
- http_transaction->StopCaching();
+ c->trans->StopCaching();
network_transaction_started = false;
}
} while (rv > 0);
@@ -7466,11 +7661,11 @@ TEST(HttpCache, TruncatedByContentLength2) {
TEST(HttpCache, SetPriority) {
MockHttpCache cache;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &trans), IsOk());
+ std::unique_ptr<Context> c(new Context);
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &c->trans), IsOk());
// Shouldn't crash, but doesn't do anything either.
- trans->SetPriority(LOW);
+ c->trans->SetPriority(LOW);
EXPECT_FALSE(cache.network_layer()->last_transaction());
EXPECT_EQ(DEFAULT_PRIORITY,
@@ -7480,7 +7675,7 @@ TEST(HttpCache, SetPriority) {
info.url = GURL(kSimpleGET_Transaction.url);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), NetLogWithSource()));
+ c->trans->Start(&info, callback.callback(), NetLogWithSource()));
EXPECT_TRUE(cache.network_layer()->last_transaction());
if (cache.network_layer()->last_transaction()) {
@@ -7488,7 +7683,7 @@ TEST(HttpCache, SetPriority) {
EXPECT_EQ(LOW, cache.network_layer()->last_transaction()->priority());
}
- trans->SetPriority(HIGHEST);
+ c->trans->SetPriority(HIGHEST);
if (cache.network_layer()->last_transaction()) {
EXPECT_EQ(LOW, cache.network_layer()->last_create_transaction_priority());
@@ -7504,8 +7699,8 @@ TEST(HttpCache, SetWebSocketHandshakeStreamCreateHelper) {
MockHttpCache cache;
FakeWebSocketHandshakeStreamCreateHelper create_helper;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &trans), IsOk());
+ std::unique_ptr<Context> c(new Context);
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &c->trans), IsOk());
EXPECT_FALSE(cache.network_layer()->last_transaction());
@@ -7513,12 +7708,12 @@ TEST(HttpCache, SetWebSocketHandshakeStreamCreateHelper) {
info.url = GURL(kSimpleGET_Transaction.url);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), NetLogWithSource()));
+ c->trans->Start(&info, callback.callback(), NetLogWithSource()));
ASSERT_TRUE(cache.network_layer()->last_transaction());
EXPECT_FALSE(cache.network_layer()->last_transaction()->
websocket_handshake_stream_create_helper());
- trans->SetWebSocketHandshakeStreamCreateHelper(&create_helper);
+ c->trans->SetWebSocketHandshakeStreamCreateHelper(&create_helper);
EXPECT_EQ(&create_helper,
cache.network_layer()->last_transaction()->
websocket_handshake_stream_create_helper());
@@ -7544,23 +7739,23 @@ TEST(HttpCache, SetPriorityNewTransaction) {
transaction.request_headers = EXTRA_HEADER;
transaction.data = kFullRangeData;
- std::unique_ptr<HttpTransaction> trans;
- ASSERT_THAT(cache.http_cache()->CreateTransaction(MEDIUM, &trans), IsOk());
+ std::unique_ptr<Context> c(new Context);
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(MEDIUM, &c->trans), IsOk());
EXPECT_EQ(DEFAULT_PRIORITY,
cache.network_layer()->last_create_transaction_priority());
MockHttpRequest info(transaction);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), NetLogWithSource()));
+ c->trans->Start(&info, callback.callback(), NetLogWithSource()));
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(MEDIUM, cache.network_layer()->last_create_transaction_priority());
- trans->SetPriority(HIGHEST);
+ c->trans->SetPriority(HIGHEST);
// Should trigger a new network transaction and pick up the new
// priority.
- ReadAndVerifyTransaction(trans.get(), transaction);
+ ReadAndVerifyTransaction(c->trans.get(), transaction);
EXPECT_EQ(HIGHEST, cache.network_layer()->last_create_transaction_priority());
@@ -7939,13 +8134,13 @@ TEST(HttpCache, RangeGET_MultipleRequests) {
AddMockTransaction(&transaction);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
+ std::unique_ptr<Context> c(new Context);
+ int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &c->trans);
EXPECT_THAT(rv, IsOk());
- ASSERT_TRUE(trans.get());
+ ASSERT_TRUE(c->trans.get());
// Start our transaction.
- trans->Start(&request, callback.callback(), NetLogWithSource());
+ c->trans->Start(&request, callback.callback(), NetLogWithSource());
// A second transaction on a different part of the file (the default
// kRangeGET_TransactionOK requests 40-49) should not be blocked by
@@ -8196,4 +8391,762 @@ TEST(HttpCache, CacheEntryStatusCantConditionalize) {
response_info.cache_entry_status);
}
+TEST(HttpCache, SimpleGET_SharedWritingCacheRead) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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();
+ }
+
+ ReadAndVerifySharedWritersCacheRead(context_list, 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_SharedWritingJoinedRead) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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());
+ }
+
+ std::vector<HttpTransaction*> transactions;
+ for (int i = 0; i < kNumTransactions; ++i) {
+ Context* c = context_list[i];
+ if (c->result == ERR_IO_PENDING)
+ c->result = c->callback.WaitForResult();
+ transactions.push_back(c->trans.get());
+ }
+
+ ReadAndVerifySharedWritersJoinedRead(kSimpleGET_Transaction, context_list);
+
+ // 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_SharedWritingJoinedReadDoneReading) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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());
+ }
+
+ std::vector<HttpTransaction*> transactions;
+ for (int i = 0; i < kNumTransactions; ++i) {
+ Context* c = context_list[i];
+ if (c->result == ERR_IO_PENDING)
+ c->result = c->callback.WaitForResult();
+ transactions.push_back(c->trans.get());
+ }
+
+ ReadAndVerifySharedWritersJoinedReadDoneReading(kSimpleGET_Transaction,
+ context_list);
+
+ // 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;
+ }
+}
+// Tests the following:
+// - A 200 will doom the entry and the transaction will continue to read from
+// the network.
+// - Doomed entry's SharedWriters will continue to read and write to the cache.
+// - Doomed entry's SharedWriters' waiting_for_validation_ will create another
+// entry.
+// - The new entry will also have another SharedWriters for subsequent
+// transactions.
+TEST(HttpCache, SharedWritingValidation200) {
+ MockHttpCache cache;
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+ request.load_flags |= LOAD_VALIDATE_CACHE;
+ MockHttpRequest reader_request(kSimpleGET_Transaction);
+ reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
+ MockHttpRequest request_no_validate(kSimpleGET_Transaction);
+
+ std::vector<Context*> context_list;
+ const int kNumTransactions = 6;
+
+ 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());
+
+ MockHttpRequest* this_request = &request;
+ if (i == 1 || i == 2)
+ this_request = &reader_request;
+
+ if (i == 5)
+ this_request = &request_no_validate;
+
+ c->result = c->trans->Start(this_request, 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 [0] request should be a writer at this point, and should have
+ // created
+ // SharedWriters, [1] and [2] will be in pending_queue and [3] and [4] should
+ // have validated and [5] will have skipped validation and be ready to read.
+
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(2, cache.disk_cache()->create_count());
+
+ Context* c = context_list[0];
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ c->result = c->callback.WaitForResult();
+
+ // First request is done with the headers, now [3] will start validation.
+ Context* c3 = context_list[3];
+ ASSERT_THAT(c3->result, IsError(ERR_IO_PENDING));
+
+ // Let [3] get a 200 , thus leading to dooming the entry, [4] and [5] will
+ // move to entry's pending_queue.
+ c3->result = c3->callback.WaitForResult();
+
+ // [3] will complete reading the response using its own network transaction
+ // and not writing to the cache.
+ ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
+
+ // [0] will complete reading the response using SharedWriter's network
+ // transaction and then the entry should be finalized.
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+
+ // [4] should be added to a new entry and should contiue reading and writing
+ // to the cache (also create SharedWriters)
+ for (int i = 4; i <= 5; i++) {
+ Context* c = context_list[i];
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ c->result = c->callback.WaitForResult();
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+ // [5] will join SharedWriters at this point when [4] completes validation.
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+ }
+ // [1] and [2] will become readers and read from the cache.
+ for (int i = 1; i <= 2; i++) {
+ Context* c = context_list[i];
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ c->result = c->callback.WaitForResult();
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+ }
+
+ // We should not have had to re-open the disk entry
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, 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;
+ }
+}
+
+// Tests a validating transaction deletion while it is waiting for its callback
+// to be invoked.
+TEST(HttpCache, SharedWritingDeleteValidationTrans) {
+ MockHttpCache cache;
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+ request.load_flags |= LOAD_VALIDATE_CACHE;
+ MockHttpRequest reader_request(kSimpleGET_Transaction);
+ reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ MockHttpRequest* this_request = &request;
+ if (i == 1 || i == 2)
+ this_request = &reader_request;
+
+ if (i == 3 || i == 4)
+ continue;
+
+ c->result = c->trans->Start(this_request, c->callback.callback(),
+ NetLogWithSource());
+ }
+
+ // All requests are waiting for the active entry.
+ for (int i = 0; i < kNumTransactions; ++i) {
+ if (i == 3 || i == 4)
+ continue;
+ 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();
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // Start [3], [4].
+ for (size_t i = 3; i <= 4; i++) {
+ Context* c = context_list[i];
+ c->result =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ }
+
+ // Delete [3] as it is the current validating trans.
+ Context* c3 = context_list[3];
+ for (auto it = context_list.begin(); it != context_list.end(); it++) {
+ if (*it == c3) {
+ context_list.erase(it);
+ delete c3;
+ break;
+ }
+ }
+
+ // Complete start state machine for [4].
+ base::RunLoop().RunUntilIdle();
+
+ // [0] will complete reading the response using SharedWriter's network
+ // transaction and then the entry should be finalized.
+ Context* c0 = context_list[0];
+ ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
+
+ // [4] (now [3]) should doom the entry and continue reading with its network
+ // transaction.
+ Context* c4 = context_list[3];
+ ReadAndVerifyTransaction(c4->trans.get(), kSimpleGET_Transaction);
+
+ // 1st entry will get destroyed and [1] and [2] will being readers will get a
+ // ERR_CACHE_MISS.
+ for (int i = 1; i <= 2; i++) {
+ Context* c = context_list[i];
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ c->result = c->callback.WaitForResult();
+ ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
+ }
+
+ // 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 (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
+// Tests a transaction deletion while it is waiting for validation.
+TEST(HttpCache, SharedWritingDeleteWaitingForValidation) {
+ MockHttpCache cache;
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+ request.load_flags |= LOAD_VALIDATE_CACHE;
+ MockHttpRequest reader_request(kSimpleGET_Transaction);
+ reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ MockHttpRequest* this_request = &request;
+ if (i == 1 || i == 2)
+ this_request = &reader_request;
+
+ if (i == 3 || i == 4)
+ continue;
+
+ c->result = c->trans->Start(this_request, c->callback.callback(),
+ NetLogWithSource());
+ }
+
+ // All requests are waiting for the active entry.
+ for (int i = 0; i < kNumTransactions; ++i) {
+ if (i == 3 || i == 4)
+ continue;
+ 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();
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ // Start [3], [4].
+ for (size_t i = 3; i <= 4; i++) {
+ Context* c = context_list[i];
+ c->result =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ }
+
+ // Delete [4] as it is the waiting for validation trans.
+ Context* c4 = context_list[4];
+ for (auto it = context_list.begin(); it != context_list.end(); it++) {
+ if (*it == c4) {
+ context_list.erase(it);
+ delete c4;
+ break;
+ }
+ }
+
+ // Complete start state machine for [3].
+ base::RunLoop().RunUntilIdle();
+
+ // [0] will complete reading the response using SharedWriter's network
+ // transaction and then the entry should be finalized.
+ Context* c0 = context_list[0];
+ ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
+
+ // [3] should doom the entry and continue reading with its network
+ // transaction.
+ Context* c3 = context_list[3];
+ ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
+
+ // 1st entry will get destroyed and [1] and [2] will being readers will get a
+ // ERR_CACHE_MISS.
+ for (int i = 1; i <= 2; i++) {
+ Context* c = context_list[i];
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
+ c->result = c->callback.WaitForResult();
+ ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
+ }
+
+ // 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 (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
+// Tests the impact of cache write failure on Shared Writing.
+TEST(HttpCache, SharedWritingCacheWriteFailure) {
+ MockHttpCache cache;
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+ request.load_flags |= LOAD_VALIDATE_CACHE;
+ MockHttpRequest reader_request(kSimpleGET_Transaction);
+ reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
+ MockHttpRequest request_no_validate(kSimpleGET_Transaction);
+
+ std::vector<Context*> context_list;
+ const int kNumTransactions = 7;
+
+ 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());
+
+ MockHttpRequest* this_request = &request;
+ if (i == 1 || i == 2)
+ this_request = &reader_request;
+
+ if (i == 3 || i == 6)
+ this_request = &request_no_validate;
+
+ if (i == 4 || i == 5)
+ continue;
+
+ c->result = c->trans->Start(this_request, c->callback.callback(),
+ NetLogWithSource());
+ }
+
+ // All requests are waiting for the active entry.
+ for (int i = 0; i < kNumTransactions; ++i) {
+ if (i == 4 || i == 5)
+ continue;
+ 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();
+
+ // At this point, 0,5 and 3 are idle writers, 1 and 2 are pending readers and
+ // 4
+ // will now become the validating_trans_.
+
+ EXPECT_EQ(1, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+ ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(kSimpleGET_Transaction,
+ context_list, cache);
+
+ // We should not have had to re-open the disk entry
+ EXPECT_EQ(3, cache.network_layer()->transaction_count());
+ EXPECT_EQ(1, cache.disk_cache()->open_count());
+ EXPECT_EQ(3, cache.disk_cache()->create_count());
+
+ for (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
+TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDoomCurrentWriter) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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());
+ }
+
+ std::vector<HttpTransaction*> transactions;
+ for (int i = 0; i < kNumTransactions; ++i) {
+ Context* c = context_list[i];
+ if (c->result == ERR_IO_PENDING)
+ c->result = c->callback.WaitForResult();
+ transactions.push_back(c->trans.get());
+ }
+
+ ReadAndVerifySharedWritersJoinedReadDoomCurrentWriter(kSimpleGET_Transaction,
+ context_list);
+
+ // 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 (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
+TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteWaitingWriter) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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());
+ }
+
+ std::vector<HttpTransaction*> transactions;
+ for (int i = 0; i < kNumTransactions; ++i) {
+ Context* c = context_list[i];
+ if (c->result == ERR_IO_PENDING)
+ c->result = c->callback.WaitForResult();
+ transactions.push_back(c->trans.get());
+ }
+
+ ReadAndVerifySharedWritersDeleteWaitingWriter(kSimpleGET_Transaction,
+ context_list);
+
+ // 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 (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
+TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteIdleWriter) {
+ MockHttpCache cache;
+
+ 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.CreateTransaction(&c->trans);
+ ASSERT_THAT(c->result, IsOk());
+ EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+ c->result =
+ c->trans->Start(&request, 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 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());
+
+ // 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());
+ }
+
+ std::vector<HttpTransaction*> transactions;
+ for (int i = 0; i < kNumTransactions; ++i) {
+ Context* c = context_list[i];
+ if (c->result == ERR_IO_PENDING)
+ c->result = c->callback.WaitForResult();
+ transactions.push_back(c->trans.get());
+ }
+
+ ReadAndVerifySharedWritersDeleteIdleWriter(kSimpleGET_Transaction,
+ context_list);
+
+ // 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 (auto i = context_list.begin(); i != context_list.end(); ++i) {
+ Context* c = *i;
+ delete c;
+ }
+}
+
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698