summaryrefslogtreecommitdiffstats
path: root/net/http/http_cache_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/http/http_cache_unittest.cc')
-rw-r--r--net/http/http_cache_unittest.cc318
1 files changed, 244 insertions, 74 deletions
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 8a69c65..72231fb 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -27,6 +27,26 @@ using base::Time;
namespace {
+int GetTestModeForEntry(const std::string& key) {
+ // 'key' is prefixed with an identifier if it corresponds to a cached POST.
+ // Skip past that to locate the actual URL.
+ //
+ // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an
+ // URL corresponding to a registered MockTransaction. It would be good to
+ // have another way to access the test_mode.
+ GURL url;
+ if (isdigit(key[0])) {
+ size_t slash = key.find('/');
+ DCHECK(slash != std::string::npos);
+ url = GURL(key.substr(slash + 1));
+ } else {
+ url = GURL(key);
+ }
+ const MockTransaction* t = FindMockTransaction(url);
+ DCHECK(t);
+ return t->test_mode;
+}
+
//-----------------------------------------------------------------------------
// mock disk cache (a very basic memory cache implementation)
@@ -41,25 +61,7 @@ class MockDiskEntry : public disk_cache::Entry,
explicit MockDiskEntry(const std::string& key)
: key_(key), doomed_(false), sparse_(false), fail_requests_(false),
busy_(false), delayed_(false) {
- //
- // 'key' is prefixed with an identifier if it corresponds to a cached POST.
- // Skip past that to locate the actual URL.
- //
- // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an
- // URL corresponding to a registered MockTransaction. It would be good to
- // have another way to access the test_mode.
- //
- GURL url;
- if (isdigit(key[0])) {
- size_t slash = key.find('/');
- DCHECK(slash != std::string::npos);
- url = GURL(key.substr(slash + 1));
- } else {
- url = GURL(key);
- }
- const MockTransaction* t = FindMockTransaction(url);
- DCHECK(t);
- test_mode_ = t->test_mode;
+ test_mode_ = GetTestModeForEntry(key);
}
bool is_doomed() const { return doomed_; }
@@ -353,17 +355,23 @@ class MockDiskCache : public disk_cache::Backend {
}
virtual bool OpenEntry(const std::string& key, disk_cache::Entry** entry) {
+ NOTREACHED();
+ return false;
+ }
+
+ virtual int OpenEntry(const std::string& key, disk_cache::Entry** entry,
+ net::CompletionCallback* callback) {
if (fail_requests_)
- return false;
+ return net::ERR_CACHE_OPEN_FAILURE;
EntryMap::iterator it = entries_.find(key);
if (it == entries_.end())
- return false;
+ return net::ERR_CACHE_OPEN_FAILURE;
if (it->second->is_doomed()) {
it->second->Release();
entries_.erase(it);
- return false;
+ return net::ERR_CACHE_OPEN_FAILURE;
}
open_count_++;
@@ -374,20 +382,29 @@ class MockDiskCache : public disk_cache::Backend {
if (soft_failures_)
it->second->set_fail_requests();
- return true;
- }
+ if (!callback || (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START))
+ return net::OK;
- virtual int OpenEntry(const std::string& key, disk_cache::Entry** entry,
- net::CompletionCallback* callback) {
- return net::ERR_NOT_IMPLEMENTED;
+ CallbackLater(callback, net::OK);
+ return net::ERR_IO_PENDING;
}
virtual bool CreateEntry(const std::string& key, disk_cache::Entry** entry) {
+ NOTREACHED();
+ return false;
+ }
+
+ virtual int CreateEntry(const std::string& key, disk_cache::Entry** entry,
+ net::CompletionCallback* callback) {
if (fail_requests_)
- return false;
+ return net::ERR_CACHE_CREATE_FAILURE;
EntryMap::iterator it = entries_.find(key);
- DCHECK(it == entries_.end());
+ if (it != entries_.end()) {
+ DCHECK(it->second->is_doomed());
+ it->second->Release();
+ entries_.erase(it);
+ }
create_count_++;
@@ -402,21 +419,30 @@ class MockDiskCache : public disk_cache::Backend {
if (soft_failures_)
new_entry->set_fail_requests();
- return true;
- }
+ if (!callback || (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START))
+ return net::OK;
- virtual int CreateEntry(const std::string& key, disk_cache::Entry** entry,
- net::CompletionCallback* callback) {
- return net::ERR_NOT_IMPLEMENTED;
+ CallbackLater(callback, net::OK);
+ return net::ERR_IO_PENDING;
}
virtual bool DoomEntry(const std::string& key) {
+ return false;
+ }
+
+ virtual int DoomEntry(const std::string& key,
+ net::CompletionCallback* callback) {
EntryMap::iterator it = entries_.find(key);
if (it != entries_.end()) {
it->second->Release();
entries_.erase(it);
}
- return true;
+
+ if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START)
+ return net::OK;
+
+ CallbackLater(callback, net::OK);
+ return net::ERR_IO_PENDING;
}
virtual bool DoomAllEntries() {
@@ -429,7 +455,7 @@ class MockDiskCache : public disk_cache::Backend {
virtual bool DoomEntriesBetween(const Time initial_time,
const Time end_time) {
- return true;
+ return false;
}
virtual int DoomEntriesBetween(const base::Time initial_time,
@@ -439,7 +465,7 @@ class MockDiskCache : public disk_cache::Backend {
}
virtual bool DoomEntriesSince(const Time initial_time) {
- return true;
+ return false;
}
virtual int DoomEntriesSince(const base::Time initial_time,
@@ -476,6 +502,26 @@ class MockDiskCache : public disk_cache::Backend {
private:
typedef base::hash_map<std::string, MockDiskEntry*> EntryMap;
+
+ class CallbackRunner : public Task {
+ public:
+ CallbackRunner(net::CompletionCallback* callback, int result)
+ : callback_(callback), result_(result) {}
+ virtual void Run() {
+ callback_->Run(result_);
+ }
+
+ private:
+ net::CompletionCallback* callback_;
+ int result_;
+ DISALLOW_COPY_AND_ASSIGN(CallbackRunner);
+ };
+
+ void CallbackLater(net::CompletionCallback* callback, int result) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new CallbackRunner(callback, result));
+ }
+
EntryMap entries_;
int open_count_;
int create_count_;
@@ -913,7 +959,8 @@ TEST(HttpCache, SimpleGETWithDiskFailures2) {
// We have to open the entry again to propagate the failure flag.
disk_cache::Entry* en;
- ASSERT_TRUE(cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url, &en));
+ ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url,
+ &en, NULL));
en->Close();
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
@@ -1198,7 +1245,10 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
c->result = c->trans->Start(&request, &c->callback, NULL);
}
- // the first request should be a writer at this point, and the subsequent
+ // Allow all requests to move from the Create queue to the active entry.
+ MessageLoop::current()->RunAllPending();
+
+ // 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());
@@ -1212,7 +1262,7 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
}
- // we should not have had to re-open the disk entry
+ // 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());
@@ -1252,6 +1302,9 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
c->result = c->trans->Start(this_request, &c->callback, NULL);
}
+ // Allow all requests to move from the Create queue to the active entry.
+ MessageLoop::current()->RunAllPending();
+
// The first request should be a writer at this point, and the subsequent
// requests should be pending.
@@ -1373,6 +1426,9 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
c->result = c->trans->Start(&request, &c->callback, NULL);
}
+ // Allow all requests to move from the Create queue to the active entry.
+ MessageLoop::current()->RunAllPending();
+
// The first request should be a writer at this point, and the subsequent
// requests should be pending.
@@ -1416,7 +1472,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
c->result = c->trans->Start(&request, &c->callback, NULL);
}
- // the first request should be a writer at this point, and the subsequent
+ // Allow all requests to move from the Create queue to the active entry.
+ MessageLoop::current()->RunAllPending();
+
+ // 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());
@@ -1427,20 +1486,20 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
Context* c = context_list[i];
if (c->result == net::ERR_IO_PENDING)
c->result = c->callback.WaitForResult();
- // destroy only the first transaction
+ // Destroy only the first transaction.
if (i == 0) {
delete c;
context_list[i] = NULL;
}
}
- // complete the rest of the transactions
+ // Complete the rest of the transactions.
for (int i = 1; i < kNumTransactions; ++i) {
Context* c = context_list[i];
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
}
- // we should have had to re-open the disk entry
+ // We should have had to re-open the disk entry.
EXPECT_EQ(2, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1452,6 +1511,107 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
}
}
+// Tests that we can cancel requests that are queued waiting to open the disk
+// cache entry.
+TEST(HttpCache, SimpleGET_ManyWriters_CancelCreate) {
+ 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.http_cache()->CreateTransaction(&c->trans);
+ EXPECT_EQ(net::OK, c->result);
+
+ c->result = c->trans->Start(&request, &c->callback, NULL);
+ }
+
+ // 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(1, cache.disk_cache()->create_count());
+
+ // Cancel a request from the pending queue.
+ delete context_list[3];
+ context_list[3] = NULL;
+
+ // Cancel the request that is creating the entry. This will force the pending
+ // operations to restart.
+ delete context_list[0];
+ context_list[0] = NULL;
+
+ // Complete the rest of the transactions.
+ for (int i = 1; i < kNumTransactions; i++) {
+ Context* c = context_list[i];
+ if (c) {
+ c->result = c->callback.GetResult(c->result);
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+ }
+ }
+
+ // We should have had to re-create the disk 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());
+
+ for (int i = 1; i < kNumTransactions; ++i) {
+ delete context_list[i];
+ }
+}
+
+// Tests that we delete/create entries even if multiple requests are queued.
+TEST(HttpCache, SimpleGET_ManyWriters_BypassCache) {
+ MockHttpCache cache;
+
+ MockHttpRequest request(kSimpleGET_Transaction);
+ request.load_flags = net::LOAD_BYPASS_CACHE;
+
+ 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, NULL);
+ }
+
+ // The first request should be deleting 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());
+
+ // Complete the transactions.
+ for (int i = 0; i < kNumTransactions; i++) {
+ Context* c = context_list[i];
+ c->result = c->callback.GetResult(c->result);
+ ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+ }
+
+ // We should have had to re-create the disk entry multiple times.
+
+ EXPECT_EQ(5, cache.network_layer()->transaction_count());
+ EXPECT_EQ(0, cache.disk_cache()->open_count());
+ EXPECT_EQ(5, cache.disk_cache()->create_count());
+
+ for (int i = 0; i < kNumTransactions; ++i) {
+ delete context_list[i];
+ }
+}
+
TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
MockHttpCache cache;
@@ -2626,8 +2786,8 @@ TEST(HttpCache, GET_Previous206_NotSparse) {
// Create a disk cache entry that stores 206 headers while not being sparse.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kSimpleGET_Transaction.url,
- &entry));
+ ASSERT_EQ(net::OK, cache.disk_cache()->CreateEntry(kSimpleGET_Transaction.url,
+ &entry, NULL));
std::string raw_headers(kRangeGET_TransactionOK.status);
raw_headers.append("\n");
@@ -2669,8 +2829,9 @@ TEST(HttpCache, RangeGET_Previous206_NotSparse_2) {
// Create a disk cache entry that stores 206 headers while not being sparse.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK,
+ cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
+ &entry, NULL));
std::string raw_headers(kRangeGET_TransactionOK.status);
raw_headers.append("\n");
@@ -2858,8 +3019,8 @@ TEST(HttpCache, RangeGET_Cancel) {
// Verify that the entry has not been deleted.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
+ &entry, NULL));
entry->Close();
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
@@ -2992,8 +3153,9 @@ TEST(HttpCache, RangeGET_InvalidResponse1) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
// Verify that we don't have a cached entry.
- disk_cache::Entry* en;
- ASSERT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en));
+ disk_cache::Entry* entry;
+ EXPECT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
+ &entry, NULL));
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
@@ -3021,8 +3183,9 @@ TEST(HttpCache, RangeGET_InvalidResponse2) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
// Verify that we don't have a cached entry.
- disk_cache::Entry* en;
- ASSERT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en));
+ disk_cache::Entry* entry;
+ EXPECT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
+ &entry, NULL));
RemoveMockTransaction(&kRangeGET_TransactionOK);
}
@@ -3063,7 +3226,8 @@ TEST(HttpCache, RangeGET_InvalidResponse3) {
// Verify that we cached the first response but not the second one.
disk_cache::Entry* en;
- ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en));
+ ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
+ &en, NULL));
int64 cached_start = 0;
EXPECT_EQ(10, en->GetAvailableRange(40, 20, &cached_start));
EXPECT_EQ(50, cached_start);
@@ -3211,7 +3375,8 @@ TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) {
TEST(HttpCache, WriteResponseInfo_Truncated) {
MockHttpCache cache;
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry("http://www.google.com", &entry));
+ ASSERT_EQ(net::OK, cache.disk_cache()->CreateEntry("http://www.google.com",
+ &entry, NULL));
std::string headers("HTTP/1.1 200 OK");
headers = net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size());
@@ -3383,8 +3548,8 @@ TEST(HttpCache, Set_Truncated_Flag) {
// Verify that the entry is marked as incomplete.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url,
- &entry));
+ ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url,
+ &entry, NULL));
net::HttpResponseInfo response;
bool truncated = false;
EXPECT_TRUE(net::HttpCache::ReadResponseInfo(entry, &response, &truncated));
@@ -3402,8 +3567,9 @@ TEST(HttpCache, GET_IncompleteResource) {
// Create a disk cache entry that stores an incomplete resource.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK,
+ cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry,
+ NULL));
std::string raw_headers("HTTP/1.1 200 OK\n"
"Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n"
@@ -3462,8 +3628,10 @@ TEST(HttpCache, GET_IncompleteResource2) {
// Create a disk cache entry that stores an incomplete resource.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK,
+ cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry,
+ NULL));
+
// Content-length will be intentionally bad.
std::string raw_headers("HTTP/1.1 200 OK\n"
@@ -3508,8 +3676,8 @@ TEST(HttpCache, GET_IncompleteResource2) {
RemoveMockTransaction(&kRangeGET_TransactionOK);
// Verify that the disk entry was deleted.
- EXPECT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url,
+ &entry, NULL));
}
// Tests that when we cancel a request that was interrupted, we mark it again
@@ -3521,8 +3689,9 @@ TEST(HttpCache, GET_CancelIncompleteResource) {
// Create a disk cache entry that stores an incomplete resource.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK,
+ cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry,
+ NULL));
std::string raw_headers("HTTP/1.1 200 OK\n"
"Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n"
@@ -3586,8 +3755,9 @@ TEST(HttpCache, RangeGET_IncompleteResource) {
// Create a disk cache entry that stores an incomplete resource.
disk_cache::Entry* entry;
- ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url,
- &entry));
+ ASSERT_EQ(net::OK,
+ cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry,
+ NULL));
// Content-length will be intentionally bogus.
std::string raw_headers("HTTP/1.1 200 OK\n"
@@ -3766,8 +3936,8 @@ TEST(HttpCache, CacheControlNoStore) {
EXPECT_EQ(2, cache.disk_cache()->create_count());
disk_cache::Entry* entry;
- bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
- EXPECT_FALSE(exists);
+ EXPECT_NE(net::OK,
+ cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL));
}
TEST(HttpCache, CacheControlNoStore2) {
@@ -3795,8 +3965,8 @@ TEST(HttpCache, CacheControlNoStore2) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
disk_cache::Entry* entry;
- bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
- EXPECT_FALSE(exists);
+ EXPECT_NE(net::OK,
+ cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL));
}
TEST(HttpCache, CacheControlNoStore3) {
@@ -3825,8 +3995,8 @@ TEST(HttpCache, CacheControlNoStore3) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
disk_cache::Entry* entry;
- bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
- EXPECT_FALSE(exists);
+ EXPECT_NE(net::OK,
+ cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL));
}
// Ensure that we don't cache requests served over bad HTTPS.