blob: 2c102840dd7dd100f2d5e063a32081290c959b29 [file] [log] [blame]
// 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