1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/disk_cache/disk_cache_test_base.h"
6
7#include "base/file_util.h"
8#include "base/path_service.h"
9#include "base/run_loop.h"
10#include "base/threading/platform_thread.h"
11#include "net/base/io_buffer.h"
12#include "net/base/net_errors.h"
13#include "net/base/test_completion_callback.h"
14#include "net/disk_cache/backend_impl.h"
15#include "net/disk_cache/cache_util.h"
16#include "net/disk_cache/disk_cache.h"
17#include "net/disk_cache/disk_cache_test_util.h"
18#include "net/disk_cache/mem_backend_impl.h"
19#include "net/disk_cache/simple/simple_backend_impl.h"
20#include "net/disk_cache/simple/simple_index.h"
21
22DiskCacheTest::DiskCacheTest() {
23  CHECK(temp_dir_.CreateUniqueTempDir());
24  cache_path_ = temp_dir_.path();
25  if (!base::MessageLoop::current())
26    message_loop_.reset(new base::MessageLoopForIO());
27}
28
29DiskCacheTest::~DiskCacheTest() {
30}
31
32bool DiskCacheTest::CopyTestCache(const std::string& name) {
33  base::FilePath path;
34  PathService::Get(base::DIR_SOURCE_ROOT, &path);
35  path = path.AppendASCII("net");
36  path = path.AppendASCII("data");
37  path = path.AppendASCII("cache_tests");
38  path = path.AppendASCII(name);
39
40  if (!CleanupCacheDir())
41    return false;
42  return base::CopyDirectory(path, cache_path_, false);
43}
44
45bool DiskCacheTest::CleanupCacheDir() {
46  return DeleteCache(cache_path_);
47}
48
49void DiskCacheTest::TearDown() {
50  base::RunLoop().RunUntilIdle();
51}
52
53DiskCacheTestWithCache::DiskCacheTestWithCache()
54    : cache_impl_(NULL),
55      simple_cache_impl_(NULL),
56      mem_cache_(NULL),
57      mask_(0),
58      size_(0),
59      type_(net::DISK_CACHE),
60      memory_only_(false),
61      simple_cache_mode_(false),
62      simple_cache_wait_for_index_(true),
63      force_creation_(false),
64      new_eviction_(false),
65      first_cleanup_(true),
66      integrity_(true),
67      use_current_thread_(false),
68      cache_thread_("CacheThread") {
69}
70
71DiskCacheTestWithCache::~DiskCacheTestWithCache() {}
72
73void DiskCacheTestWithCache::InitCache() {
74  if (memory_only_)
75    InitMemoryCache();
76  else
77    InitDiskCache();
78
79  ASSERT_TRUE(NULL != cache_);
80  if (first_cleanup_)
81    ASSERT_EQ(0, cache_->GetEntryCount());
82}
83
84// We are expected to leak memory when simulating crashes.
85void DiskCacheTestWithCache::SimulateCrash() {
86  ASSERT_TRUE(!memory_only_);
87  net::TestCompletionCallback cb;
88  int rv = cache_impl_->FlushQueueForTest(cb.callback());
89  ASSERT_EQ(net::OK, cb.GetResult(rv));
90  cache_impl_->ClearRefCountForTest();
91
92  cache_.reset();
93  EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_));
94
95  CreateBackend(disk_cache::kNoRandom, &cache_thread_);
96}
97
98void DiskCacheTestWithCache::SetTestMode() {
99  ASSERT_TRUE(!memory_only_);
100  cache_impl_->SetUnitTestMode();
101}
102
103void DiskCacheTestWithCache::SetMaxSize(int size) {
104  size_ = size;
105  if (simple_cache_impl_)
106    EXPECT_TRUE(simple_cache_impl_->SetMaxSize(size));
107
108  if (cache_impl_)
109    EXPECT_TRUE(cache_impl_->SetMaxSize(size));
110
111  if (mem_cache_)
112    EXPECT_TRUE(mem_cache_->SetMaxSize(size));
113}
114
115int DiskCacheTestWithCache::OpenEntry(const std::string& key,
116                                      disk_cache::Entry** entry) {
117  net::TestCompletionCallback cb;
118  int rv = cache_->OpenEntry(key, entry, cb.callback());
119  return cb.GetResult(rv);
120}
121
122int DiskCacheTestWithCache::CreateEntry(const std::string& key,
123                                        disk_cache::Entry** entry) {
124  net::TestCompletionCallback cb;
125  int rv = cache_->CreateEntry(key, entry, cb.callback());
126  return cb.GetResult(rv);
127}
128
129int DiskCacheTestWithCache::DoomEntry(const std::string& key) {
130  net::TestCompletionCallback cb;
131  int rv = cache_->DoomEntry(key, cb.callback());
132  return cb.GetResult(rv);
133}
134
135int DiskCacheTestWithCache::DoomAllEntries() {
136  net::TestCompletionCallback cb;
137  int rv = cache_->DoomAllEntries(cb.callback());
138  return cb.GetResult(rv);
139}
140
141int DiskCacheTestWithCache::DoomEntriesBetween(const base::Time initial_time,
142                                               const base::Time end_time) {
143  net::TestCompletionCallback cb;
144  int rv = cache_->DoomEntriesBetween(initial_time, end_time, cb.callback());
145  return cb.GetResult(rv);
146}
147
148int DiskCacheTestWithCache::DoomEntriesSince(const base::Time initial_time) {
149  net::TestCompletionCallback cb;
150  int rv = cache_->DoomEntriesSince(initial_time, cb.callback());
151  return cb.GetResult(rv);
152}
153
154int DiskCacheTestWithCache::OpenNextEntry(void** iter,
155                                          disk_cache::Entry** next_entry) {
156  net::TestCompletionCallback cb;
157  int rv = cache_->OpenNextEntry(iter, next_entry, cb.callback());
158  return cb.GetResult(rv);
159}
160
161void DiskCacheTestWithCache::FlushQueueForTest() {
162  if (memory_only_ || !cache_impl_)
163    return;
164
165  net::TestCompletionCallback cb;
166  int rv = cache_impl_->FlushQueueForTest(cb.callback());
167  EXPECT_EQ(net::OK, cb.GetResult(rv));
168}
169
170void DiskCacheTestWithCache::RunTaskForTest(const base::Closure& closure) {
171  if (memory_only_ || !cache_impl_) {
172    closure.Run();
173    return;
174  }
175
176  net::TestCompletionCallback cb;
177  int rv = cache_impl_->RunTaskForTest(closure, cb.callback());
178  EXPECT_EQ(net::OK, cb.GetResult(rv));
179}
180
181int DiskCacheTestWithCache::ReadData(disk_cache::Entry* entry, int index,
182                                     int offset, net::IOBuffer* buf, int len) {
183  net::TestCompletionCallback cb;
184  int rv = entry->ReadData(index, offset, buf, len, cb.callback());
185  return cb.GetResult(rv);
186}
187
188int DiskCacheTestWithCache::WriteData(disk_cache::Entry* entry, int index,
189                                      int offset, net::IOBuffer* buf, int len,
190                                      bool truncate) {
191  net::TestCompletionCallback cb;
192  int rv = entry->WriteData(index, offset, buf, len, cb.callback(), truncate);
193  return cb.GetResult(rv);
194}
195
196int DiskCacheTestWithCache::ReadSparseData(disk_cache::Entry* entry,
197                                           int64 offset, net::IOBuffer* buf,
198                                           int len) {
199  net::TestCompletionCallback cb;
200  int rv = entry->ReadSparseData(offset, buf, len, cb.callback());
201  return cb.GetResult(rv);
202}
203
204int DiskCacheTestWithCache::WriteSparseData(disk_cache::Entry* entry,
205                                            int64 offset,
206                                            net::IOBuffer* buf, int len) {
207  net::TestCompletionCallback cb;
208  int rv = entry->WriteSparseData(offset, buf, len, cb.callback());
209  return cb.GetResult(rv);
210}
211
212void DiskCacheTestWithCache::TrimForTest(bool empty) {
213  RunTaskForTest(base::Bind(&disk_cache::BackendImpl::TrimForTest,
214                            base::Unretained(cache_impl_),
215                            empty));
216}
217
218void DiskCacheTestWithCache::TrimDeletedListForTest(bool empty) {
219  RunTaskForTest(base::Bind(&disk_cache::BackendImpl::TrimDeletedListForTest,
220                            base::Unretained(cache_impl_),
221                            empty));
222}
223
224void DiskCacheTestWithCache::AddDelay() {
225  if (simple_cache_mode_) {
226    // The simple cache uses second resolution for many timeouts, so it's safest
227    // to advance by at least whole seconds before falling back into the normal
228    // disk cache epsilon advance.
229    const base::Time initial_time = base::Time::Now();
230    do {
231      base::PlatformThread::YieldCurrentThread();
232    } while (base::Time::Now() -
233             initial_time < base::TimeDelta::FromSeconds(1));
234  }
235
236  base::Time initial = base::Time::Now();
237  while (base::Time::Now() <= initial) {
238    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
239  };
240}
241
242void DiskCacheTestWithCache::TearDown() {
243  base::RunLoop().RunUntilIdle();
244  disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
245  base::RunLoop().RunUntilIdle();
246  cache_.reset();
247  if (cache_thread_.IsRunning())
248    cache_thread_.Stop();
249
250  if (!memory_only_ && !simple_cache_mode_ && integrity_) {
251    EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_));
252  }
253  base::RunLoop().RunUntilIdle();
254  disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
255  DiskCacheTest::TearDown();
256}
257
258void DiskCacheTestWithCache::InitMemoryCache() {
259  mem_cache_ = new disk_cache::MemBackendImpl(NULL);
260  cache_.reset(mem_cache_);
261  ASSERT_TRUE(cache_);
262
263  if (size_)
264    EXPECT_TRUE(mem_cache_->SetMaxSize(size_));
265
266  ASSERT_TRUE(mem_cache_->Init());
267}
268
269void DiskCacheTestWithCache::InitDiskCache() {
270  if (first_cleanup_)
271    ASSERT_TRUE(CleanupCacheDir());
272
273  if (!cache_thread_.IsRunning()) {
274    ASSERT_TRUE(cache_thread_.StartWithOptions(
275        base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
276  }
277  ASSERT_TRUE(cache_thread_.message_loop() != NULL);
278
279  CreateBackend(disk_cache::kNoRandom, &cache_thread_);
280}
281
282void DiskCacheTestWithCache::CreateBackend(uint32 flags, base::Thread* thread) {
283  base::MessageLoopProxy* runner;
284  if (use_current_thread_)
285    runner = base::MessageLoopProxy::current().get();
286  else
287    runner = thread->message_loop_proxy().get();
288
289  if (simple_cache_mode_) {
290    net::TestCompletionCallback cb;
291    scoped_ptr<disk_cache::SimpleBackendImpl> simple_backend(
292        new disk_cache::SimpleBackendImpl(
293            cache_path_, size_, type_, make_scoped_refptr(runner).get(), NULL));
294    int rv = simple_backend->Init(cb.callback());
295    ASSERT_EQ(net::OK, cb.GetResult(rv));
296    simple_cache_impl_ = simple_backend.get();
297    cache_ = simple_backend.PassAs<disk_cache::Backend>();
298    if (simple_cache_wait_for_index_) {
299      net::TestCompletionCallback wait_for_index_cb;
300      rv = simple_cache_impl_->index()->ExecuteWhenReady(
301          wait_for_index_cb.callback());
302      ASSERT_EQ(net::OK, wait_for_index_cb.GetResult(rv));
303    }
304    return;
305  }
306
307  if (mask_)
308    cache_impl_ = new disk_cache::BackendImpl(cache_path_, mask_, runner, NULL);
309  else
310    cache_impl_ = new disk_cache::BackendImpl(cache_path_, runner, NULL);
311  cache_.reset(cache_impl_);
312  ASSERT_TRUE(cache_);
313  if (size_)
314    EXPECT_TRUE(cache_impl_->SetMaxSize(size_));
315  if (new_eviction_)
316    cache_impl_->SetNewEviction();
317  cache_impl_->SetType(type_);
318  cache_impl_->SetFlags(flags);
319  net::TestCompletionCallback cb;
320  int rv = cache_impl_->Init(cb.callback());
321  ASSERT_EQ(net::OK, cb.GetResult(rv));
322}
323