| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/http/infinite_cache.h" |
| |
| #include "base/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/stringprintf.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/http/http_transaction_unittest.h" |
| #include "net/http/http_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::Time; |
| using base::TimeDelta; |
| using net::InfiniteCache; |
| using net::InfiniteCacheTransaction; |
| |
| namespace { |
| |
| void StartRequest(const MockTransaction& http_transaction, |
| InfiniteCacheTransaction* transaction) { |
| std::string standard_headers(http_transaction.status); |
| standard_headers.push_back('\n'); |
| standard_headers.append(http_transaction.response_headers); |
| std::string raw_headers = |
| net::HttpUtil::AssembleRawHeaders(standard_headers.c_str(), |
| standard_headers.size()); |
| |
| scoped_refptr<net::HttpResponseHeaders> headers( |
| new net::HttpResponseHeaders(raw_headers)); |
| net::HttpResponseInfo response; |
| response.headers = headers; |
| response.request_time = http_transaction.request_time.is_null() ? |
| Time::Now() : http_transaction.request_time; |
| response.response_time = http_transaction.response_time.is_null() ? |
| Time::Now() : http_transaction.response_time; |
| |
| MockHttpRequest request(http_transaction); |
| transaction->OnRequestStart(&request); |
| transaction->OnResponseReceived(&response); |
| } |
| |
| void ProcessRequest(const MockTransaction& http_transaction, |
| InfiniteCache* cache) { |
| scoped_ptr<InfiniteCacheTransaction> transaction |
| (cache->CreateInfiniteCacheTransaction()); |
| |
| StartRequest(http_transaction, transaction.get()); |
| transaction->OnDataRead(http_transaction.data, strlen(http_transaction.data)); |
| } |
| |
| void ProcessRequestWithTime(const MockTransaction& http_transaction, |
| InfiniteCache* cache, |
| Time time) { |
| scoped_ptr<InfiniteCacheTransaction> transaction |
| (cache->CreateInfiniteCacheTransaction()); |
| |
| MockTransaction timed_transaction = http_transaction; |
| timed_transaction.request_time = time; |
| timed_transaction.response_time = time; |
| StartRequest(timed_transaction, transaction.get()); |
| transaction->OnDataRead(http_transaction.data, strlen(http_transaction.data)); |
| } |
| |
| } // namespace |
| |
| TEST(InfiniteCache, Basics) { |
| InfiniteCache cache; |
| cache.Init(FilePath()); |
| |
| scoped_ptr<InfiniteCacheTransaction> transaction |
| (cache.CreateInfiniteCacheTransaction()); |
| |
| // Don't even Start() this transaction. |
| transaction.reset(cache.CreateInfiniteCacheTransaction()); |
| |
| net::TestCompletionCallback cb; |
| EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| MockHttpRequest request(kTypicalGET_Transaction); |
| transaction->OnRequestStart(&request); |
| |
| // Don't have a response yet. |
| transaction.reset(cache.CreateInfiniteCacheTransaction()); |
| EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| net::HttpResponseInfo response; |
| scoped_refptr<net::HttpResponseHeaders> headers( |
| new net::HttpResponseHeaders(kTypicalGET_Transaction.response_headers)); |
| response.headers = headers; |
| |
| transaction->OnRequestStart(&request); |
| transaction->OnResponseReceived(&response); |
| transaction.reset(cache.CreateInfiniteCacheTransaction()); |
| EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| // Hit the same URL again. |
| transaction->OnRequestStart(&request); |
| transaction->OnResponseReceived(&response); |
| transaction.reset(cache.CreateInfiniteCacheTransaction()); |
| EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| // Now a different URL. |
| MockHttpRequest request2(kSimpleGET_Transaction); |
| transaction->OnRequestStart(&request2); |
| transaction->OnResponseReceived(&response); |
| transaction.reset(); |
| EXPECT_EQ(2, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| } |
| |
| TEST(InfiniteCache, Save_Restore) { |
| base::ScopedTempDir dir; |
| ASSERT_TRUE(dir.CreateUniqueTempDir()); |
| FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); |
| |
| scoped_ptr<InfiniteCache> cache(new InfiniteCache); |
| cache->Init(path); |
| net::TestCompletionCallback cb; |
| |
| ProcessRequest(kTypicalGET_Transaction, cache.get()); |
| ProcessRequest(kSimpleGET_Transaction, cache.get()); |
| ProcessRequest(kETagGET_Transaction, cache.get()); |
| ProcessRequest(kSimplePOST_Transaction, cache.get()); |
| |
| EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| |
| cache.reset(new InfiniteCache); |
| cache->Init(path); |
| EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| |
| ProcessRequest(kTypicalGET_Transaction, cache.get()); |
| EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| } |
| |
| TEST(InfiniteCache, DoomMethod) { |
| InfiniteCache cache; |
| cache.Init(FilePath()); |
| |
| ProcessRequest(kTypicalGET_Transaction, &cache); |
| ProcessRequest(kSimpleGET_Transaction, &cache); |
| ProcessRequest(kETagGET_Transaction, &cache); |
| net::TestCompletionCallback cb; |
| EXPECT_EQ(3, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| MockTransaction request(kTypicalGET_Transaction); |
| request.method = "PUT"; |
| ProcessRequest(request, &cache); |
| EXPECT_EQ(2, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| request.method = "POST"; |
| request.url = kSimpleGET_Transaction.url; |
| ProcessRequest(request, &cache); |
| EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| |
| request.method = "DELETE"; |
| request.url = kETagGET_Transaction.url; |
| ProcessRequest(request, &cache); |
| EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); |
| } |
| |
| TEST(InfiniteCache, Delete) { |
| base::ScopedTempDir dir; |
| ASSERT_TRUE(dir.CreateUniqueTempDir()); |
| FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); |
| |
| scoped_ptr<InfiniteCache> cache(new InfiniteCache); |
| cache->Init(path); |
| net::TestCompletionCallback cb; |
| |
| ProcessRequest(kTypicalGET_Transaction, cache.get()); |
| ProcessRequest(kSimpleGET_Transaction, cache.get()); |
| EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| EXPECT_TRUE(file_util::PathExists(path)); |
| |
| cache.reset(new InfiniteCache); |
| cache->Init(path); |
| EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, cb.GetResult(cache->DeleteData(cb.callback()))); |
| EXPECT_EQ(0, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_FALSE(file_util::PathExists(path)); |
| |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| } |
| |
| TEST(InfiniteCache, DeleteBetween) { |
| #if !defined(OS_ANDROID) |
| base::ScopedTempDir dir; |
| ASSERT_TRUE(dir.CreateUniqueTempDir()); |
| FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); |
| |
| scoped_ptr<InfiniteCache> cache(new InfiniteCache); |
| cache->Init(path); |
| net::TestCompletionCallback cb; |
| |
| Time::Exploded baseline = {}; |
| baseline.year = 2012; |
| baseline.month = 1; |
| baseline.day_of_month = 1; |
| Time base_time = Time::FromUTCExploded(baseline); |
| |
| ProcessRequestWithTime(kTypicalGET_Transaction, cache.get(), base_time); |
| |
| Time start = base_time + TimeDelta::FromSeconds(2); |
| ProcessRequestWithTime(kSimpleGET_Transaction, cache.get(), start); |
| Time end = start + TimeDelta::FromSeconds(2); |
| |
| ProcessRequestWithTime(kETagGET_Transaction, cache.get(), |
| end + TimeDelta::FromSeconds(2)); |
| |
| EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, |
| cb.GetResult(cache->DeleteDataBetween(start, end, |
| cb.callback()))); |
| EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| |
| // Make sure the data is deleted from disk. |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| cache.reset(new InfiniteCache); |
| cache->Init(path); |
| |
| EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| ProcessRequestWithTime(kETagGET_Transaction, cache.get(), |
| end + TimeDelta::FromMinutes(5)); |
| EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| |
| EXPECT_EQ(net::OK, |
| cb.GetResult(cache->DeleteDataBetween(start, Time::Now(), |
| cb.callback()))); |
| EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| |
| // Make sure the data is deleted from disk. |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| cache.reset(new InfiniteCache); |
| cache->Init(path); |
| |
| EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| ProcessRequest(kTypicalGET_Transaction, cache.get()); |
| EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| #endif // OS_ANDROID |
| } |
| |
| #if 0 |
| // This test is too slow for the bots. |
| TEST(InfiniteCache, FillUp) { |
| base::ScopedTempDir dir; |
| ASSERT_TRUE(dir.CreateUniqueTempDir()); |
| FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); |
| |
| scoped_ptr<InfiniteCache> cache(new InfiniteCache); |
| cache->Init(path); |
| net::TestCompletionCallback cb; |
| |
| const int kNumEntries = 25000; |
| for (int i = 0; i < kNumEntries; i++) { |
| std::string url = StringPrintf("http://foo.com/%d/foo.html", i); |
| MockTransaction transaction = kTypicalGET_Transaction; |
| transaction.url = url.c_str(); |
| ProcessRequest(transaction, cache.get()); |
| } |
| |
| EXPECT_EQ(kNumEntries, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); |
| |
| cache.reset(new InfiniteCache); |
| cache->Init(path); |
| EXPECT_EQ(kNumEntries, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); |
| } |
| #endif |