1// Copyright 2014 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 "content/browser/service_worker/service_worker_cache_storage_manager.h"
6
7#include "base/files/file_path.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "base/run_loop.h"
11#include "content/browser/fileapi/chrome_blob_storage_context.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/test/test_browser_context.h"
14#include "content/public/test/test_browser_thread_bundle.h"
15#include "net/url_request/url_request_context_getter.h"
16#include "storage/browser/blob/blob_storage_context.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace content {
20
21class ServiceWorkerCacheStorageManagerTest : public testing::Test {
22 protected:
23  ServiceWorkerCacheStorageManagerTest()
24      : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
25        callback_bool_(false),
26        callback_error_(
27            ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR),
28        callback_cache_error_(ServiceWorkerCache::ErrorTypeOK),
29        origin1_("http://example1.com"),
30        origin2_("http://example2.com") {}
31
32  virtual void SetUp() OVERRIDE {
33    ChromeBlobStorageContext* blob_storage_context(
34        ChromeBlobStorageContext::GetFor(&browser_context_));
35    // Wait for ChromeBlobStorageContext to finish initializing.
36    base::RunLoop().RunUntilIdle();
37
38    net::URLRequestContext* url_request_context =
39        browser_context_.GetRequestContext()->GetURLRequestContext();
40    if (MemoryOnly()) {
41      cache_manager_ = ServiceWorkerCacheStorageManager::Create(
42          base::FilePath(), base::MessageLoopProxy::current());
43    } else {
44      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
45      cache_manager_ = ServiceWorkerCacheStorageManager::Create(
46          temp_dir_.path(), base::MessageLoopProxy::current());
47    }
48
49    cache_manager_->SetBlobParametersForCache(
50        url_request_context, blob_storage_context->context()->AsWeakPtr());
51  }
52
53  virtual void TearDown() OVERRIDE {
54    base::RunLoop().RunUntilIdle();
55  }
56
57  virtual bool MemoryOnly() { return false; }
58
59  void BoolAndErrorCallback(
60      base::RunLoop* run_loop,
61      bool value,
62      ServiceWorkerCacheStorage::CacheStorageError error) {
63    callback_bool_ = value;
64    callback_error_ = error;
65    run_loop->Quit();
66  }
67
68  void CacheAndErrorCallback(
69      base::RunLoop* run_loop,
70      const scoped_refptr<ServiceWorkerCache>& cache,
71      ServiceWorkerCacheStorage::CacheStorageError error) {
72    callback_cache_ = cache;
73    callback_error_ = error;
74    run_loop->Quit();
75  }
76
77  void StringsAndErrorCallback(
78      base::RunLoop* run_loop,
79      const std::vector<std::string>& strings,
80      ServiceWorkerCacheStorage::CacheStorageError error) {
81    callback_strings_ = strings;
82    callback_error_ = error;
83    run_loop->Quit();
84  }
85
86  void CachePutCallback(base::RunLoop* run_loop,
87                        ServiceWorkerCache::ErrorType error) {
88    callback_cache_error_ = error;
89    run_loop->Quit();
90  }
91
92  void CacheMatchCallback(
93      base::RunLoop* run_loop,
94      ServiceWorkerCache::ErrorType error,
95      scoped_ptr<ServiceWorkerResponse> response,
96      scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
97    callback_cache_error_ = error;
98    callback_cache_response_ = response.Pass();
99    // Deliberately drop the data handle as only the url is being tested.
100    run_loop->Quit();
101  }
102
103  bool CreateCache(const GURL& origin, const std::string& cache_name) {
104    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
105    cache_manager_->CreateCache(
106        origin,
107        cache_name,
108        base::Bind(&ServiceWorkerCacheStorageManagerTest::CacheAndErrorCallback,
109                   base::Unretained(this),
110                   base::Unretained(loop.get())));
111    loop->Run();
112
113    bool error = callback_error_ !=
114                 ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR;
115    if (error)
116      EXPECT_TRUE(!callback_cache_.get());
117    else
118      EXPECT_TRUE(callback_cache_.get());
119    return !error;
120  }
121
122  bool Get(const GURL& origin, const std::string& cache_name) {
123    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
124    cache_manager_->GetCache(
125        origin,
126        cache_name,
127        base::Bind(&ServiceWorkerCacheStorageManagerTest::CacheAndErrorCallback,
128                   base::Unretained(this),
129                   base::Unretained(loop.get())));
130    loop->Run();
131
132    bool error = callback_error_ !=
133                 ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR;
134    if (error)
135      EXPECT_TRUE(!callback_cache_.get());
136    else
137      EXPECT_TRUE(callback_cache_.get());
138    return !error;
139  }
140
141  bool Has(const GURL& origin, const std::string& cache_name) {
142    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
143    cache_manager_->HasCache(
144        origin,
145        cache_name,
146        base::Bind(&ServiceWorkerCacheStorageManagerTest::BoolAndErrorCallback,
147                   base::Unretained(this),
148                   base::Unretained(loop.get())));
149    loop->Run();
150
151    return callback_bool_;
152  }
153
154  bool Delete(const GURL& origin, const std::string& cache_name) {
155    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
156    cache_manager_->DeleteCache(
157        origin,
158        cache_name,
159        base::Bind(&ServiceWorkerCacheStorageManagerTest::BoolAndErrorCallback,
160                   base::Unretained(this),
161                   base::Unretained(loop.get())));
162    loop->Run();
163
164    return callback_bool_;
165  }
166
167  bool Keys(const GURL& origin) {
168    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
169    cache_manager_->EnumerateCaches(
170        origin,
171        base::Bind(
172            &ServiceWorkerCacheStorageManagerTest::StringsAndErrorCallback,
173            base::Unretained(this),
174            base::Unretained(loop.get())));
175    loop->Run();
176
177    bool error = callback_error_ !=
178                 ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR;
179    return !error;
180  }
181
182  bool CachePut(const scoped_refptr<ServiceWorkerCache>& cache,
183                const std::string& url) {
184    scoped_ptr<ServiceWorkerFetchRequest> request(
185        new ServiceWorkerFetchRequest());
186    scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse());
187    request->url = GURL("http://example.com/foo");
188    response->url = GURL("http://example.com/foo");
189    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
190    cache->Put(
191        request.Pass(),
192        response.Pass(),
193        base::Bind(&ServiceWorkerCacheStorageManagerTest::CachePutCallback,
194                   base::Unretained(this),
195                   base::Unretained(loop.get())));
196    loop->Run();
197
198    bool error = callback_cache_error_ != ServiceWorkerCache::ErrorTypeOK;
199    return !error;
200  }
201
202  bool CacheMatch(const scoped_refptr<ServiceWorkerCache>& cache,
203                  const std::string& url) {
204    scoped_ptr<ServiceWorkerFetchRequest> request(
205        new ServiceWorkerFetchRequest());
206    request->url = GURL("http://example.com/foo");
207    scoped_ptr<base::RunLoop> loop(new base::RunLoop());
208    cache->Match(
209        request.Pass(),
210        base::Bind(&ServiceWorkerCacheStorageManagerTest::CacheMatchCallback,
211                   base::Unretained(this),
212                   base::Unretained(loop.get())));
213    loop->Run();
214
215    bool error = callback_cache_error_ != ServiceWorkerCache::ErrorTypeOK;
216    return !error;
217  }
218
219 protected:
220  TestBrowserContext browser_context_;
221  TestBrowserThreadBundle browser_thread_bundle_;
222
223  base::ScopedTempDir temp_dir_;
224  scoped_ptr<ServiceWorkerCacheStorageManager> cache_manager_;
225
226  scoped_refptr<ServiceWorkerCache> callback_cache_;
227  int callback_bool_;
228  ServiceWorkerCacheStorage::CacheStorageError callback_error_;
229  ServiceWorkerCache::ErrorType callback_cache_error_;
230  scoped_ptr<ServiceWorkerResponse> callback_cache_response_;
231  std::vector<std::string> callback_strings_;
232
233  const GURL origin1_;
234  const GURL origin2_;
235
236 private:
237  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorageManagerTest);
238};
239
240class ServiceWorkerCacheStorageManagerMemoryOnlyTest
241    : public ServiceWorkerCacheStorageManagerTest {
242  virtual bool MemoryOnly() OVERRIDE { return true; }
243};
244
245class ServiceWorkerCacheStorageManagerTestP
246    : public ServiceWorkerCacheStorageManagerTest,
247      public testing::WithParamInterface<bool> {
248  virtual bool MemoryOnly() OVERRIDE { return !GetParam(); }
249};
250
251TEST_F(ServiceWorkerCacheStorageManagerTest, TestsRunOnIOThread) {
252  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
253}
254
255TEST_P(ServiceWorkerCacheStorageManagerTestP, CreateCache) {
256  EXPECT_TRUE(CreateCache(origin1_, "foo"));
257}
258
259TEST_P(ServiceWorkerCacheStorageManagerTestP, CreateDuplicateCache) {
260  EXPECT_TRUE(CreateCache(origin1_, "foo"));
261  EXPECT_FALSE(CreateCache(origin1_, "foo"));
262  EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EXISTS,
263            callback_error_);
264}
265
266TEST_P(ServiceWorkerCacheStorageManagerTestP, CreateTwoCaches) {
267  EXPECT_TRUE(CreateCache(origin1_, "foo"));
268  EXPECT_TRUE(CreateCache(origin1_, "bar"));
269}
270
271TEST_P(ServiceWorkerCacheStorageManagerTestP, CachePointersDiffer) {
272  EXPECT_TRUE(CreateCache(origin1_, "foo"));
273  scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
274  EXPECT_TRUE(CreateCache(origin1_, "bar"));
275  EXPECT_TRUE(cache.get() != callback_cache_.get());
276}
277
278TEST_P(ServiceWorkerCacheStorageManagerTestP, Create2CachesSameNameDiffSWs) {
279  EXPECT_TRUE(CreateCache(origin1_, "foo"));
280  EXPECT_TRUE(CreateCache(origin2_, "foo"));
281}
282
283TEST_P(ServiceWorkerCacheStorageManagerTestP, GetCache) {
284  EXPECT_TRUE(CreateCache(origin1_, "foo"));
285  scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
286  EXPECT_TRUE(Get(origin1_, "foo"));
287  EXPECT_TRUE(cache.get() == callback_cache_.get());
288}
289
290TEST_P(ServiceWorkerCacheStorageManagerTestP, GetNonExistent) {
291  EXPECT_FALSE(Get(origin1_, "foo"));
292  EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND,
293            callback_error_);
294}
295
296TEST_P(ServiceWorkerCacheStorageManagerTestP, HasCache) {
297  EXPECT_TRUE(CreateCache(origin1_, "foo"));
298  EXPECT_TRUE(Has(origin1_, "foo"));
299  EXPECT_TRUE(callback_bool_);
300}
301
302TEST_P(ServiceWorkerCacheStorageManagerTestP, HasNonExistent) {
303  EXPECT_FALSE(Has(origin1_, "foo"));
304}
305
306TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteCache) {
307  EXPECT_TRUE(CreateCache(origin1_, "foo"));
308  EXPECT_TRUE(Delete(origin1_, "foo"));
309  EXPECT_FALSE(Get(origin1_, "foo"));
310  EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND,
311            callback_error_);
312}
313
314TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteTwice) {
315  EXPECT_TRUE(CreateCache(origin1_, "foo"));
316  EXPECT_TRUE(Delete(origin1_, "foo"));
317  EXPECT_FALSE(Delete(origin1_, "foo"));
318  EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND,
319            callback_error_);
320}
321
322TEST_P(ServiceWorkerCacheStorageManagerTestP, EmptyKeys) {
323  EXPECT_TRUE(Keys(origin1_));
324  EXPECT_TRUE(callback_strings_.empty());
325}
326
327TEST_P(ServiceWorkerCacheStorageManagerTestP, SomeKeys) {
328  EXPECT_TRUE(CreateCache(origin1_, "foo"));
329  EXPECT_TRUE(CreateCache(origin1_, "bar"));
330  EXPECT_TRUE(CreateCache(origin2_, "baz"));
331  EXPECT_TRUE(Keys(origin1_));
332  EXPECT_EQ(2u, callback_strings_.size());
333  std::vector<std::string> expected_keys;
334  expected_keys.push_back("foo");
335  expected_keys.push_back("bar");
336  EXPECT_TRUE(expected_keys == callback_strings_);
337  EXPECT_TRUE(Keys(origin2_));
338  EXPECT_EQ(1u, callback_strings_.size());
339  EXPECT_STREQ("baz", callback_strings_[0].c_str());
340}
341
342TEST_P(ServiceWorkerCacheStorageManagerTestP, DeletedKeysGone) {
343  EXPECT_TRUE(CreateCache(origin1_, "foo"));
344  EXPECT_TRUE(CreateCache(origin1_, "bar"));
345  EXPECT_TRUE(CreateCache(origin2_, "baz"));
346  EXPECT_TRUE(Delete(origin1_, "bar"));
347  EXPECT_TRUE(Keys(origin1_));
348  EXPECT_EQ(1u, callback_strings_.size());
349  EXPECT_STREQ("foo", callback_strings_[0].c_str());
350}
351
352TEST_P(ServiceWorkerCacheStorageManagerTestP, Chinese) {
353  EXPECT_TRUE(CreateCache(origin1_, "你好"));
354  scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
355  EXPECT_TRUE(Get(origin1_, "你好"));
356  EXPECT_TRUE(cache.get() == callback_cache_.get());
357  EXPECT_TRUE(Keys(origin1_));
358  EXPECT_EQ(1u, callback_strings_.size());
359  EXPECT_TRUE("你好" == callback_strings_[0]);
360}
361
362TEST_F(ServiceWorkerCacheStorageManagerTest, EmptyKey) {
363  EXPECT_TRUE(CreateCache(origin1_, ""));
364  scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
365  EXPECT_TRUE(Get(origin1_, ""));
366  EXPECT_EQ(cache.get(), callback_cache_.get());
367  EXPECT_TRUE(Keys(origin1_));
368  EXPECT_EQ(1u, callback_strings_.size());
369  EXPECT_TRUE("" == callback_strings_[0]);
370  EXPECT_TRUE(Has(origin1_, ""));
371  EXPECT_TRUE(Delete(origin1_, ""));
372  EXPECT_TRUE(Keys(origin1_));
373  EXPECT_EQ(0u, callback_strings_.size());
374}
375
376TEST_F(ServiceWorkerCacheStorageManagerTest, DataPersists) {
377  EXPECT_TRUE(CreateCache(origin1_, "foo"));
378  EXPECT_TRUE(CreateCache(origin1_, "bar"));
379  EXPECT_TRUE(CreateCache(origin1_, "baz"));
380  EXPECT_TRUE(CreateCache(origin2_, "raz"));
381  EXPECT_TRUE(Delete(origin1_, "bar"));
382  cache_manager_ =
383      ServiceWorkerCacheStorageManager::Create(cache_manager_.get());
384  EXPECT_TRUE(Keys(origin1_));
385  EXPECT_EQ(2u, callback_strings_.size());
386  std::vector<std::string> expected_keys;
387  expected_keys.push_back("foo");
388  expected_keys.push_back("baz");
389  EXPECT_TRUE(expected_keys == callback_strings_);
390}
391
392TEST_F(ServiceWorkerCacheStorageManagerMemoryOnlyTest, DataLostWhenMemoryOnly) {
393  EXPECT_TRUE(CreateCache(origin1_, "foo"));
394  EXPECT_TRUE(CreateCache(origin2_, "baz"));
395  cache_manager_ =
396      ServiceWorkerCacheStorageManager::Create(cache_manager_.get());
397  EXPECT_TRUE(Keys(origin1_));
398  EXPECT_EQ(0u, callback_strings_.size());
399}
400
401TEST_F(ServiceWorkerCacheStorageManagerTest, BadCacheName) {
402  // Since the implementation writes cache names to disk, ensure that we don't
403  // escape the directory.
404  const std::string bad_name = "../../../../../../../../../../../../../../foo";
405  EXPECT_TRUE(CreateCache(origin1_, bad_name));
406  EXPECT_TRUE(Keys(origin1_));
407  EXPECT_EQ(1u, callback_strings_.size());
408  EXPECT_STREQ(bad_name.c_str(), callback_strings_[0].c_str());
409}
410
411TEST_F(ServiceWorkerCacheStorageManagerTest, BadOriginName) {
412  // Since the implementation writes origin names to disk, ensure that we don't
413  // escape the directory.
414  GURL bad_origin("../../../../../../../../../../../../../../foo");
415  EXPECT_TRUE(CreateCache(bad_origin, "foo"));
416  EXPECT_TRUE(Keys(bad_origin));
417  EXPECT_EQ(1u, callback_strings_.size());
418  EXPECT_STREQ("foo", callback_strings_[0].c_str());
419}
420
421// With a persistent cache if the client drops its reference to a
422// ServiceWorkerCache
423// it should be deleted.
424TEST_F(ServiceWorkerCacheStorageManagerTest, DropReference) {
425  EXPECT_TRUE(CreateCache(origin1_, "foo"));
426  base::WeakPtr<ServiceWorkerCache> cache = callback_cache_->AsWeakPtr();
427  callback_cache_ = NULL;
428  EXPECT_TRUE(!cache);
429}
430
431// With a memory cache the cache can't be freed from memory until the client
432// calls delete.
433TEST_F(ServiceWorkerCacheStorageManagerMemoryOnlyTest,
434       MemoryLosesReferenceOnlyAfterDelete) {
435  EXPECT_TRUE(CreateCache(origin1_, "foo"));
436  base::WeakPtr<ServiceWorkerCache> cache = callback_cache_->AsWeakPtr();
437  callback_cache_ = NULL;
438  EXPECT_TRUE(cache);
439  EXPECT_TRUE(Delete(origin1_, "foo"));
440  EXPECT_FALSE(cache);
441}
442
443TEST_P(ServiceWorkerCacheStorageManagerTestP, RecreateCacheOnDemand) {
444  EXPECT_TRUE(CreateCache(origin1_, "foo"));
445  EXPECT_TRUE(CachePut(callback_cache_, "bar"));
446  callback_cache_ = NULL;
447  EXPECT_TRUE(Get(origin1_, "foo"));
448  EXPECT_TRUE(CacheMatch(callback_cache_, "bar"));
449}
450
451TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteBeforeRelease) {
452  EXPECT_TRUE(CreateCache(origin1_, "foo"));
453  EXPECT_TRUE(Delete(origin1_, "foo"));
454  EXPECT_TRUE(callback_cache_->AsWeakPtr());
455}
456
457INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheStorageManagerTests,
458                        ServiceWorkerCacheStorageManagerTestP,
459                        ::testing::Values(false, true));
460
461}  // namespace content
462