OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h" | 5 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h" |
6 | 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
7 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
8 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
9 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
10 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
11 #include "content/browser/service_worker/service_worker_context_core.h" | 14 #include "content/browser/service_worker/service_worker_context_core.h" |
12 #include "content/browser/service_worker/service_worker_storage.h" | 15 #include "content/browser/service_worker/service_worker_storage.h" |
13 #include "content/public/test/test_browser_thread_bundle.h" | 16 #include "content/public/test/test_browser_thread_bundle.h" |
14 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
15 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
16 #include "net/base/test_completion_callback.h" | 19 #include "net/base/test_completion_callback.h" |
(...skipping 21 matching lines...) Expand all Loading... |
38 body(body), | 41 body(body), |
39 metadata(metadata) {} | 42 metadata(metadata) {} |
40 }; | 43 }; |
41 | 44 |
42 void OnDiskCacheMigrated(const base::Closure& callback, | 45 void OnDiskCacheMigrated(const base::Closure& callback, |
43 ServiceWorkerStatusCode status) { | 46 ServiceWorkerStatusCode status) { |
44 EXPECT_EQ(SERVICE_WORKER_OK, status); | 47 EXPECT_EQ(SERVICE_WORKER_OK, status); |
45 callback.Run(); | 48 callback.Run(); |
46 } | 49 } |
47 | 50 |
| 51 void OnRegistrationFound( |
| 52 const base::Closure& callback, |
| 53 ServiceWorkerStatusCode status, |
| 54 const scoped_refptr<ServiceWorkerRegistration>& registration) { |
| 55 callback.Run(); |
| 56 } |
| 57 |
48 } // namespace | 58 } // namespace |
49 | 59 |
50 class ServiceWorkerDiskCacheMigratorTest : public testing::Test { | 60 class ServiceWorkerDiskCacheMigratorTest : public testing::Test { |
51 public: | 61 public: |
52 ServiceWorkerDiskCacheMigratorTest() | 62 ServiceWorkerDiskCacheMigratorTest() |
53 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} | 63 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} |
54 | 64 |
55 void SetUp() override { | 65 void SetUp() override { |
56 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); | 66 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); |
57 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager( | 67 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager( |
58 new MockServiceWorkerDatabaseTaskManager( | 68 new MockServiceWorkerDatabaseTaskManager( |
59 base::ThreadTaskRunnerHandle::Get())); | 69 base::ThreadTaskRunnerHandle::Get())); |
60 | 70 |
61 context_.reset(new ServiceWorkerContextCore( | 71 context_.reset(new ServiceWorkerContextCore( |
62 user_data_directory_.path(), database_task_manager.Pass(), | 72 user_data_directory_.path(), database_task_manager.Pass(), |
63 base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr, nullptr, | 73 base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr, nullptr, |
64 nullptr)); | 74 nullptr)); |
65 } | 75 } |
66 | 76 |
67 void TearDown() override { | 77 void TearDown() override { |
68 context_.reset(); | 78 context_.reset(); |
69 base::RunLoop().RunUntilIdle(); | 79 base::RunLoop().RunUntilIdle(); |
70 } | 80 } |
71 | 81 |
72 base::FilePath GetOldDiskCachePath() { | |
73 return user_data_directory_.path().AppendASCII("SrcCache"); | |
74 } | |
75 base::FilePath GetDiskCachePath() { | |
76 return user_data_directory_.path().AppendASCII("DestCache"); | |
77 } | |
78 | |
79 scoped_ptr<ServiceWorkerDiskCache> CreateSrcDiskCache() { | 82 scoped_ptr<ServiceWorkerDiskCache> CreateSrcDiskCache() { |
80 #if defined(OS_ANDROID) | 83 #if defined(OS_ANDROID) |
81 // Android has already used the Simple backend. | 84 // Android has already used the Simple backend. |
82 scoped_ptr<ServiceWorkerDiskCache> src( | 85 scoped_ptr<ServiceWorkerDiskCache> src( |
83 ServiceWorkerDiskCache::CreateWithSimpleBackend()); | 86 ServiceWorkerDiskCache::CreateWithSimpleBackend()); |
84 #else | 87 #else |
85 scoped_ptr<ServiceWorkerDiskCache> src( | 88 scoped_ptr<ServiceWorkerDiskCache> src( |
86 ServiceWorkerDiskCache::CreateWithBlockFileBackend()); | 89 ServiceWorkerDiskCache::CreateWithBlockFileBackend()); |
87 #endif // defined(OS_ANDROID) | 90 #endif // defined(OS_ANDROID) |
88 | 91 |
89 net::TestCompletionCallback cb; | 92 net::TestCompletionCallback cb; |
90 src->InitWithDiskBackend( | 93 src->InitWithDiskBackend( |
91 GetOldDiskCachePath(), kMaxDiskCacheSize, false /* force */, | 94 storage()->GetOldDiskCachePath(), kMaxDiskCacheSize, false /* force */, |
92 base::ThreadTaskRunnerHandle::Get(), cb.callback()); | 95 base::ThreadTaskRunnerHandle::Get(), cb.callback()); |
93 EXPECT_EQ(net::OK, cb.WaitForResult()); | 96 EXPECT_EQ(net::OK, cb.WaitForResult()); |
94 return src.Pass(); | 97 return src.Pass(); |
95 } | 98 } |
96 | 99 |
97 scoped_ptr<ServiceWorkerDiskCache> CreateDestDiskCache() { | 100 scoped_ptr<ServiceWorkerDiskCache> CreateDestDiskCache() { |
98 scoped_ptr<ServiceWorkerDiskCache> dest( | 101 scoped_ptr<ServiceWorkerDiskCache> dest( |
99 ServiceWorkerDiskCache::CreateWithSimpleBackend()); | 102 ServiceWorkerDiskCache::CreateWithSimpleBackend()); |
100 net::TestCompletionCallback cb; | 103 net::TestCompletionCallback cb; |
101 dest->InitWithDiskBackend( | 104 dest->InitWithDiskBackend( |
102 GetDiskCachePath(), kMaxDiskCacheSize, false /* force */, | 105 storage()->GetDiskCachePath(), kMaxDiskCacheSize, false /* force */, |
103 base::ThreadTaskRunnerHandle::Get(), cb.callback()); | 106 base::ThreadTaskRunnerHandle::Get(), cb.callback()); |
104 EXPECT_EQ(net::OK, cb.WaitForResult()); | 107 EXPECT_EQ(net::OK, cb.WaitForResult()); |
105 return dest.Pass(); | 108 return dest.Pass(); |
106 } | 109 } |
107 | 110 |
108 scoped_ptr<ServiceWorkerDiskCacheMigrator> CreateMigrator() { | 111 scoped_ptr<ServiceWorkerDiskCacheMigrator> CreateMigrator() { |
109 return make_scoped_ptr(new ServiceWorkerDiskCacheMigrator( | 112 return make_scoped_ptr(new ServiceWorkerDiskCacheMigrator( |
110 GetOldDiskCachePath(), GetDiskCachePath(), kMaxDiskCacheSize, | 113 storage()->GetOldDiskCachePath(), storage()->GetDiskCachePath(), |
111 base::ThreadTaskRunnerHandle::Get())); | 114 kMaxDiskCacheSize, base::ThreadTaskRunnerHandle::Get())); |
112 } | 115 } |
113 | 116 |
114 bool WriteResponse(ServiceWorkerDiskCache* disk_cache, | 117 bool WriteResponse(ServiceWorkerDiskCache* disk_cache, |
115 const ResponseData& response) { | 118 const ResponseData& response) { |
116 scoped_ptr<ServiceWorkerResponseWriter> writer( | 119 scoped_ptr<ServiceWorkerResponseWriter> writer( |
117 new ServiceWorkerResponseWriter(response.resource_id, disk_cache)); | 120 new ServiceWorkerResponseWriter(response.resource_id, disk_cache)); |
118 | 121 |
119 // Write the response info. | 122 // Write the response info. |
120 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); | 123 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); |
121 info->request_time = base::Time() + base::TimeDelta::FromSeconds(10); | 124 info->request_time = base::Time() + base::TimeDelta::FromSeconds(10); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 reader->ReadData(body_buffer.get(), kBigEnough, cb2.callback()); | 194 reader->ReadData(body_buffer.get(), kBigEnough, cb2.callback()); |
192 rv = cb2.WaitForResult(); | 195 rv = cb2.WaitForResult(); |
193 ASSERT_EQ(static_cast<int>(expected.body.length()), rv); | 196 ASSERT_EQ(static_cast<int>(expected.body.length()), rv); |
194 EXPECT_EQ(0, memcmp(expected.body.data(), body_buffer->data(), rv)); | 197 EXPECT_EQ(0, memcmp(expected.body.data(), body_buffer->data(), rv)); |
195 } | 198 } |
196 | 199 |
197 int32 GetEntryCount(ServiceWorkerDiskCache* disk_cache) { | 200 int32 GetEntryCount(ServiceWorkerDiskCache* disk_cache) { |
198 return disk_cache->disk_cache()->GetEntryCount(); | 201 return disk_cache->disk_cache()->GetEntryCount(); |
199 } | 202 } |
200 | 203 |
| 204 ServiceWorkerStorage* storage() { return context_->storage(); } |
| 205 |
201 private: | 206 private: |
202 TestBrowserThreadBundle browser_thread_bundle_; | 207 TestBrowserThreadBundle browser_thread_bundle_; |
203 base::ScopedTempDir user_data_directory_; | 208 base::ScopedTempDir user_data_directory_; |
204 | 209 |
205 scoped_ptr<ServiceWorkerContextCore> context_; | 210 scoped_ptr<ServiceWorkerContextCore> context_; |
206 }; | 211 }; |
207 | 212 |
208 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateDiskCache) { | 213 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateDiskCache) { |
209 std::vector<ResponseData> responses; | 214 std::vector<ResponseData> responses; |
210 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); | 215 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure())); | 327 migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure())); |
323 run_loop.Run(); | 328 run_loop.Run(); |
324 | 329 |
325 // Verify the migrated contents in the dest diskcache. | 330 // Verify the migrated contents in the dest diskcache. |
326 scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache()); | 331 scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache()); |
327 for (const ResponseData& response : responses) | 332 for (const ResponseData& response : responses) |
328 VerifyResponse(dest.get(), response); | 333 VerifyResponse(dest.get(), response); |
329 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest.get())); | 334 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest.get())); |
330 } | 335 } |
331 | 336 |
| 337 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateOnDiskCacheAccess) { |
| 338 std::vector<ResponseData> responses; |
| 339 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
| 340 responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", "")); |
| 341 responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "Worker", "")); |
| 342 responses.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", "meta")); |
| 343 |
| 344 // Populate initial resources in the src diskcache. |
| 345 scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache()); |
| 346 for (const ResponseData& response : responses) { |
| 347 ASSERT_TRUE(WriteResponse(src.get(), response)); |
| 348 VerifyResponse(src.get(), response); |
| 349 } |
| 350 ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get())); |
| 351 ASSERT_TRUE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 352 src.reset(); |
| 353 |
| 354 scoped_ptr<ServiceWorkerDatabase> database( |
| 355 new ServiceWorkerDatabase(storage()->GetDatabasePath())); |
| 356 |
| 357 // This is necessary to make the storage schedule diskcache migration. |
| 358 database->set_skip_writing_diskcache_migration_state_on_init_for_testing(); |
| 359 |
| 360 // Simulate an existing database. |
| 361 std::vector<ServiceWorkerDatabase::ResourceRecord> resources; |
| 362 resources.push_back(ServiceWorkerDatabase::ResourceRecord( |
| 363 1, GURL("https://example.com/foo"), 10)); |
| 364 ServiceWorkerDatabase::RegistrationData deleted_version; |
| 365 std::vector<int64> newly_purgeable_resources; |
| 366 ServiceWorkerDatabase::RegistrationData data; |
| 367 data.registration_id = 100; |
| 368 data.scope = GURL("https://example.com/"); |
| 369 data.script = GURL("https://example.com/script.js"); |
| 370 data.version_id = 200; |
| 371 data.resources_total_size_bytes = 10; |
| 372 ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 373 database->WriteRegistration(data, resources, &deleted_version, |
| 374 &newly_purgeable_resources)); |
| 375 database.reset(); |
| 376 |
| 377 // LazyInitialize() reads initial data and should schedule to migrate. |
| 378 ASSERT_FALSE(storage()->disk_cache_migration_needed_); |
| 379 base::RunLoop run_loop; |
| 380 storage()->LazyInitialize(run_loop.QuitClosure()); |
| 381 run_loop.Run(); |
| 382 EXPECT_TRUE(storage()->disk_cache_migration_needed_); |
| 383 |
| 384 // DiskCache access should start the migration. |
| 385 ServiceWorkerDiskCache* dest = storage()->disk_cache(); |
| 386 |
| 387 // Verify the migrated contents in the dest diskcache. |
| 388 for (const ResponseData& response : responses) |
| 389 VerifyResponse(dest, response); |
| 390 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest)); |
| 391 |
| 392 // After the migration, the src diskcache should be deleted. |
| 393 EXPECT_FALSE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 394 |
| 395 // After the migration, the migration state should be updated. |
| 396 bool migration_needed = false; |
| 397 EXPECT_EQ( |
| 398 ServiceWorkerDatabase::STATUS_OK, |
| 399 storage()->database_->IsDiskCacheMigrationNeeded(&migration_needed)); |
| 400 EXPECT_FALSE(migration_needed); |
| 401 bool deletion_needed = false; |
| 402 EXPECT_EQ( |
| 403 ServiceWorkerDatabase::STATUS_OK, |
| 404 storage()->database_->IsOldDiskCacheDeletionNeeded(&deletion_needed)); |
| 405 EXPECT_FALSE(deletion_needed); |
| 406 } |
| 407 |
| 408 TEST_F(ServiceWorkerDiskCacheMigratorTest, NotMigrateOnDatabaseAccess) { |
| 409 std::vector<ResponseData> responses; |
| 410 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
| 411 responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", "")); |
| 412 responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "Worker", "")); |
| 413 responses.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", "meta")); |
| 414 |
| 415 // Populate initial resources in the src diskcache. |
| 416 scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache()); |
| 417 for (const ResponseData& response : responses) { |
| 418 ASSERT_TRUE(WriteResponse(src.get(), response)); |
| 419 VerifyResponse(src.get(), response); |
| 420 } |
| 421 ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get())); |
| 422 ASSERT_TRUE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 423 |
| 424 scoped_ptr<ServiceWorkerDatabase> database( |
| 425 new ServiceWorkerDatabase(storage()->GetDatabasePath())); |
| 426 |
| 427 // This is necessary to make the storage schedule diskcache migration. |
| 428 database->set_skip_writing_diskcache_migration_state_on_init_for_testing(); |
| 429 |
| 430 // Simulate an existing database. |
| 431 std::vector<ServiceWorkerDatabase::ResourceRecord> resources; |
| 432 resources.push_back(ServiceWorkerDatabase::ResourceRecord( |
| 433 1, GURL("https://example.com/foo"), 10)); |
| 434 ServiceWorkerDatabase::RegistrationData deleted_version; |
| 435 std::vector<int64> newly_purgeable_resources; |
| 436 ServiceWorkerDatabase::RegistrationData data; |
| 437 data.registration_id = 100; |
| 438 data.scope = GURL("https://example.com/"); |
| 439 data.script = GURL("https://example.com/script.js"); |
| 440 data.version_id = 200; |
| 441 data.resources_total_size_bytes = 10; |
| 442 ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 443 database->WriteRegistration(data, resources, &deleted_version, |
| 444 &newly_purgeable_resources)); |
| 445 database.reset(); |
| 446 |
| 447 // LazyInitialize() reads initial data and should schedule to migrate. |
| 448 ASSERT_FALSE(storage()->disk_cache_migration_needed_); |
| 449 base::RunLoop run_loop1; |
| 450 storage()->LazyInitialize(run_loop1.QuitClosure()); |
| 451 run_loop1.Run(); |
| 452 EXPECT_TRUE(storage()->disk_cache_migration_needed_); |
| 453 |
| 454 // Database access should not start the migration. |
| 455 base::RunLoop run_loop2; |
| 456 storage()->FindRegistrationForDocument( |
| 457 GURL("http://example.com/"), |
| 458 base::Bind(&OnRegistrationFound, run_loop2.QuitClosure())); |
| 459 run_loop2.Run(); |
| 460 |
| 461 // Verify that the migration didn't happen. |
| 462 scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache()); |
| 463 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get())); |
| 464 EXPECT_EQ(0, GetEntryCount(dest.get())); |
| 465 EXPECT_TRUE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 466 } |
| 467 |
| 468 TEST_F(ServiceWorkerDiskCacheMigratorTest, NotMigrateForEmptyDatabase) { |
| 469 std::vector<ResponseData> responses; |
| 470 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
| 471 responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", "")); |
| 472 responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "Worker", "")); |
| 473 responses.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", "meta")); |
| 474 |
| 475 // Populate initial resources in the src diskcache. |
| 476 scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache()); |
| 477 for (const ResponseData& response : responses) { |
| 478 ASSERT_TRUE(WriteResponse(src.get(), response)); |
| 479 VerifyResponse(src.get(), response); |
| 480 } |
| 481 ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get())); |
| 482 ASSERT_TRUE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 483 src.reset(); |
| 484 |
| 485 // LazyInitialize() reads initial data and should not schedule to migrate |
| 486 // because the database is empty. |
| 487 ASSERT_FALSE(storage()->disk_cache_migration_needed_); |
| 488 base::RunLoop run_loop; |
| 489 storage()->LazyInitialize(run_loop.QuitClosure()); |
| 490 run_loop.Run(); |
| 491 EXPECT_FALSE(storage()->disk_cache_migration_needed_); |
| 492 |
| 493 // DiskCache access should not start the migration. |
| 494 ServiceWorkerDiskCache* dest = storage()->disk_cache(); |
| 495 |
| 496 // Verify that the migration didn't happen. |
| 497 src = CreateSrcDiskCache(); |
| 498 for (const ResponseData& response : responses) |
| 499 VerifyResponse(src.get(), response); |
| 500 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get())); |
| 501 EXPECT_TRUE(base::DirectoryExists(storage()->GetOldDiskCachePath())); |
| 502 EXPECT_EQ(0, GetEntryCount(dest)); |
| 503 |
| 504 // After the diskcache initialization, the migration state should be updated. |
| 505 bool migration_needed = false; |
| 506 EXPECT_EQ( |
| 507 ServiceWorkerDatabase::STATUS_OK, |
| 508 storage()->database_->IsDiskCacheMigrationNeeded(&migration_needed)); |
| 509 EXPECT_FALSE(migration_needed); |
| 510 bool deletion_needed = false; |
| 511 EXPECT_EQ( |
| 512 ServiceWorkerDatabase::STATUS_OK, |
| 513 storage()->database_->IsOldDiskCacheDeletionNeeded(&deletion_needed)); |
| 514 EXPECT_FALSE(deletion_needed); |
| 515 } |
| 516 |
332 } // namespace content | 517 } // namespace content |
OLD | NEW |