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 19 namespace content { 20 21 class 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 240 class ServiceWorkerCacheStorageManagerMemoryOnlyTest 241 : public ServiceWorkerCacheStorageManagerTest { 242 virtual bool MemoryOnly() OVERRIDE { return true; } 243 }; 244 245 class ServiceWorkerCacheStorageManagerTestP 246 : public ServiceWorkerCacheStorageManagerTest, 247 public testing::WithParamInterface<bool> { 248 virtual bool MemoryOnly() OVERRIDE { return !GetParam(); } 249 }; 250 251 TEST_F(ServiceWorkerCacheStorageManagerTest, TestsRunOnIOThread) { 252 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 253 } 254 255 TEST_P(ServiceWorkerCacheStorageManagerTestP, CreateCache) { 256 EXPECT_TRUE(CreateCache(origin1_, "foo")); 257 } 258 259 TEST_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 266 TEST_P(ServiceWorkerCacheStorageManagerTestP, CreateTwoCaches) { 267 EXPECT_TRUE(CreateCache(origin1_, "foo")); 268 EXPECT_TRUE(CreateCache(origin1_, "bar")); 269 } 270 271 TEST_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 278 TEST_P(ServiceWorkerCacheStorageManagerTestP, Create2CachesSameNameDiffSWs) { 279 EXPECT_TRUE(CreateCache(origin1_, "foo")); 280 EXPECT_TRUE(CreateCache(origin2_, "foo")); 281 } 282 283 TEST_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 290 TEST_P(ServiceWorkerCacheStorageManagerTestP, GetNonExistent) { 291 EXPECT_FALSE(Get(origin1_, "foo")); 292 EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND, 293 callback_error_); 294 } 295 296 TEST_P(ServiceWorkerCacheStorageManagerTestP, HasCache) { 297 EXPECT_TRUE(CreateCache(origin1_, "foo")); 298 EXPECT_TRUE(Has(origin1_, "foo")); 299 EXPECT_TRUE(callback_bool_); 300 } 301 302 TEST_P(ServiceWorkerCacheStorageManagerTestP, HasNonExistent) { 303 EXPECT_FALSE(Has(origin1_, "foo")); 304 } 305 306 TEST_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 314 TEST_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 322 TEST_P(ServiceWorkerCacheStorageManagerTestP, EmptyKeys) { 323 EXPECT_TRUE(Keys(origin1_)); 324 EXPECT_TRUE(callback_strings_.empty()); 325 } 326 327 TEST_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 342 TEST_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 352 TEST_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 362 TEST_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 376 TEST_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 392 TEST_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 401 TEST_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 411 TEST_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. 424 TEST_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. 433 TEST_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 443 TEST_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 451 TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteBeforeRelease) { 452 EXPECT_TRUE(CreateCache(origin1_, "foo")); 453 EXPECT_TRUE(Delete(origin1_, "foo")); 454 EXPECT_TRUE(callback_cache_->AsWeakPtr()); 455 } 456 457 INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheStorageManagerTests, 458 ServiceWorkerCacheStorageManagerTestP, 459 ::testing::Values(false, true)); 460 461 } // namespace content 462