1// Copyright (c) 2006-2010 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_util.h"
6
7#include "base/logging.h"
8#include "base/file_util.h"
9#include "base/message_loop_proxy.h"
10#include "base/path_service.h"
11#include "net/base/net_errors.h"
12#include "net/disk_cache/backend_impl.h"
13#include "net/disk_cache/cache_util.h"
14#include "net/disk_cache/file.h"
15
16using base::Time;
17using base::TimeDelta;
18
19namespace {
20
21FilePath BuildCachePath(const std::string& name) {
22  FilePath path;
23  PathService::Get(base::DIR_TEMP, &path);  // Ignore return value;
24  path = path.AppendASCII(name);
25  if (!file_util::PathExists(path))
26    file_util::CreateDirectory(path);
27
28  return path;
29}
30
31}  // namespace.
32
33std::string GenerateKey(bool same_length) {
34  char key[200];
35  CacheTestFillBuffer(key, sizeof(key), same_length);
36
37  key[199] = '\0';
38  return std::string(key);
39}
40
41void CacheTestFillBuffer(char* buffer, size_t len, bool no_nulls) {
42  static bool called = false;
43  if (!called) {
44    called = true;
45    int seed = static_cast<int>(Time::Now().ToInternalValue());
46    srand(seed);
47  }
48
49  for (size_t i = 0; i < len; i++) {
50    buffer[i] = static_cast<char>(rand());
51    if (!buffer[i] && no_nulls)
52      buffer[i] = 'g';
53  }
54  if (len && !buffer[0])
55    buffer[0] = 'g';
56}
57
58FilePath GetCacheFilePath() {
59  return BuildCachePath("cache_test");
60}
61
62bool CreateCacheTestFile(const FilePath& name) {
63  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
64              base::PLATFORM_FILE_READ |
65              base::PLATFORM_FILE_WRITE;
66
67  scoped_refptr<disk_cache::File> file(new disk_cache::File(
68      base::CreatePlatformFile(name, flags, NULL, NULL)));
69  if (!file->IsValid())
70    return false;
71
72  file->SetLength(4 * 1024 * 1024);
73  return true;
74}
75
76bool DeleteCache(const FilePath& path) {
77  disk_cache::DeleteCache(path, false);
78  return true;
79}
80
81bool CopyTestCache(const std::string& name) {
82  FilePath path;
83  PathService::Get(base::DIR_SOURCE_ROOT, &path);
84  path = path.AppendASCII("net");
85  path = path.AppendASCII("data");
86  path = path.AppendASCII("cache_tests");
87  path = path.AppendASCII(name);
88
89  FilePath dest = GetCacheFilePath();
90  if (!DeleteCache(dest))
91    return false;
92  return file_util::CopyDirectory(path, dest, false);
93}
94
95bool CheckCacheIntegrity(const FilePath& path, bool new_eviction) {
96  scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
97      path, base::MessageLoopProxy::CreateForCurrentThread(), NULL));
98  if (!cache.get())
99    return false;
100  if (new_eviction)
101    cache->SetNewEviction();
102  cache->SetFlags(disk_cache::kNoRandom);
103  if (cache->SyncInit() != net::OK)
104    return false;
105  return cache->SelfCheck() >= 0;
106}
107
108ScopedTestCache::ScopedTestCache() : path_(GetCacheFilePath()) {
109  bool result = DeleteCache(path_);
110  DCHECK(result);
111}
112
113ScopedTestCache::ScopedTestCache(const std::string& name)
114    : path_(BuildCachePath(name)) {
115  bool result = DeleteCache(path_);
116  DCHECK(result);
117}
118
119ScopedTestCache::~ScopedTestCache() {
120  file_util::Delete(path(), true);
121}
122
123// -----------------------------------------------------------------------
124
125volatile int g_cache_tests_received = 0;
126volatile bool g_cache_tests_error = 0;
127
128CallbackTest::CallbackTest(bool reuse) : result_(-1), reuse_(reuse ? 0 : 1) {}
129
130CallbackTest::~CallbackTest() {}
131
132// On the actual callback, increase the number of tests received and check for
133// errors (an unexpected test received)
134void CallbackTest::RunWithParams(const Tuple1<int>& params) {
135  if (reuse_) {
136    DCHECK(1 == reuse_);
137    if (2 == reuse_)
138      g_cache_tests_error = true;
139    reuse_++;
140  }
141
142  result_ = params.a;
143  g_cache_tests_received++;
144}
145
146// -----------------------------------------------------------------------
147
148MessageLoopHelper::MessageLoopHelper()
149    : num_callbacks_(0),
150      num_iterations_(0),
151      last_(0),
152      completed_(false) {
153  // Create a recurrent timer of 50 mS.
154  timer_.Start(
155      TimeDelta::FromMilliseconds(50), this, &MessageLoopHelper::TimerExpired);
156}
157
158MessageLoopHelper::~MessageLoopHelper() {
159}
160
161bool MessageLoopHelper::WaitUntilCacheIoFinished(int num_callbacks) {
162  if (num_callbacks == g_cache_tests_received)
163    return true;
164
165  ExpectCallbacks(num_callbacks);
166  MessageLoop::current()->Run();
167  return completed_;
168}
169
170// Quits the message loop when all callbacks are called or we've been waiting
171// too long for them (2 secs without a callback).
172void MessageLoopHelper::TimerExpired() {
173  if (g_cache_tests_received > num_callbacks_) {
174    NOTREACHED();
175  } else if (g_cache_tests_received == num_callbacks_) {
176    completed_ = true;
177    MessageLoop::current()->Quit();
178  } else {
179    // Not finished yet. See if we have to abort.
180    if (last_ == g_cache_tests_received)
181      num_iterations_++;
182    else
183      last_ = g_cache_tests_received;
184    if (40 == num_iterations_)
185      MessageLoop::current()->Quit();
186  }
187}
188