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