Index: content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc |
diff --git a/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc b/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d50c2f5fc30d7c7ec918d9300c5c5dea88c8dccc |
--- /dev/null |
+++ b/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc |
@@ -0,0 +1,290 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/service_worker/service_worker_disk_cache_migrator.h" |
+ |
+#include "base/files/scoped_temp_dir.h" |
+#include "base/run_loop.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "content/public/test/test_browser_thread_bundle.h" |
+#include "net/base/io_buffer.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/test_completion_callback.h" |
+#include "net/http/http_response_headers.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+const int kMaxDiskCacheSize = 250 * 1024 * 1024; |
+ |
+struct ResponseData { |
+ int64 resource_id; |
+ std::string headers; |
+ std::string body; |
+ std::string metadata; |
+ |
+ ResponseData(int64 resource_id, |
+ const std::string& headers, |
+ const std::string& body, |
+ const std::string& metadata) |
+ : resource_id(resource_id), |
+ headers(headers), |
+ body(body), |
+ metadata(metadata) {} |
+}; |
+ |
+void OnDiskCacheMigrated(const base::Closure& callback, |
+ ServiceWorkerStatusCode status) { |
+ EXPECT_EQ(SERVICE_WORKER_OK, status); |
+ callback.Run(); |
+} |
+ |
+} // namespace |
+ |
+class ServiceWorkerDiskCacheMigratorTest : public testing::Test { |
+ public: |
+ ServiceWorkerDiskCacheMigratorTest() |
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} |
+ |
+ void SetUp() override { |
+ ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); |
+ const base::FilePath kSrcDiskCachePath = |
+ user_data_directory_.path().AppendASCII("SrcCache"); |
+ const base::FilePath kDestDiskCachePath = |
+ user_data_directory_.path().AppendASCII("DestCache"); |
+ |
+ // Initialize the src BlockFile diskcache. |
+ src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
+ net::TestCompletionCallback cb1; |
+ src_->InitWithDiskBackend( |
+ kSrcDiskCachePath, kMaxDiskCacheSize, false /* force */, |
+ base::ThreadTaskRunnerHandle::Get(), cb1.callback()); |
+ ASSERT_EQ(net::OK, cb1.WaitForResult()); |
+ |
+ // Initialize the dest Simple diskcache. |
+ dest_ = ServiceWorkerDiskCache::CreateWithSimpleBackend(); |
+ net::TestCompletionCallback cb2; |
+ dest_->InitWithDiskBackend( |
+ kDestDiskCachePath, kMaxDiskCacheSize, false /* force */, |
+ base::ThreadTaskRunnerHandle::Get(), cb2.callback()); |
+ ASSERT_EQ(net::OK, cb2.WaitForResult()); |
+ } |
+ |
+ bool WriteResponse(ServiceWorkerDiskCache* disk_cache, |
+ const ResponseData& response) { |
+ scoped_ptr<ServiceWorkerResponseWriter> writer( |
+ new ServiceWorkerResponseWriter(response.resource_id, disk_cache)); |
+ |
+ // Write the response info. |
+ scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); |
+ info->request_time = base::Time::Now(); |
+ info->response_time = base::Time::Now(); |
+ info->was_cached = false; |
+ info->headers = new net::HttpResponseHeaders(response.headers); |
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
+ new HttpResponseInfoIOBuffer(info.release()); |
+ { |
+ net::TestCompletionCallback cb; |
+ writer->WriteInfo(info_buffer.get(), cb.callback()); |
+ int rv = cb.WaitForResult(); |
+ EXPECT_LT(0, rv); |
+ if (rv < 0) |
+ return false; |
+ } |
+ |
+ // Write the response metadata. |
+ scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer( |
+ new ServiceWorkerResponseMetadataWriter(response.resource_id, |
+ disk_cache)); |
+ scoped_refptr<net::IOBuffer> metadata_buffer( |
+ new net::WrappedIOBuffer(response.metadata.data())); |
+ { |
+ const int metadata_length = response.metadata.length(); |
+ net::TestCompletionCallback cb; |
+ metadata_writer->WriteMetadata(metadata_buffer.get(), metadata_length, |
+ cb.callback()); |
+ int rv = cb.WaitForResult(); |
+ EXPECT_EQ(metadata_length, rv); |
+ if (metadata_length != rv) |
+ return false; |
+ } |
+ |
+ // Write the response body. |
+ scoped_refptr<net::IOBuffer> body_buffer( |
+ new net::WrappedIOBuffer(response.body.data())); |
+ { |
+ const int body_length = response.body.length(); |
+ net::TestCompletionCallback cb; |
+ writer->WriteData(body_buffer.get(), body_length, cb.callback()); |
+ int rv = cb.WaitForResult(); |
+ EXPECT_EQ(body_length, rv); |
+ if (body_length != rv) |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+ |
+ void VerifyResponse(ServiceWorkerDiskCache* disk_cache, |
+ const ResponseData& expected) { |
+ scoped_ptr<ServiceWorkerResponseReader> reader( |
+ new ServiceWorkerResponseReader(expected.resource_id, disk_cache)); |
+ |
+ // Verify the response info. |
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
+ new HttpResponseInfoIOBuffer; |
+ { |
+ net::TestCompletionCallback cb; |
+ reader->ReadInfo(info_buffer.get(), cb.callback()); |
+ int rv = cb.WaitForResult(); |
+ EXPECT_LT(0, rv); |
+ EXPECT_EQ("OK", info_buffer->http_info->headers->GetStatusText()); |
+ } |
+ |
+ // Verify the response metadata. |
+ if (!expected.metadata.empty()) { |
+ ASSERT_TRUE(info_buffer->http_info->metadata); |
+ const int data_size = info_buffer->http_info->metadata->size(); |
+ ASSERT_EQ(static_cast<int>(expected.metadata.length()), data_size); |
+ EXPECT_EQ(0, memcmp(expected.metadata.data(), |
+ info_buffer->http_info->metadata->data(), |
+ expected.metadata.length())); |
+ } |
+ |
+ // Verify the response body. |
+ { |
+ const int kBigEnough = 512; |
+ scoped_refptr<net::IOBuffer> body_buffer = new net::IOBuffer(kBigEnough); |
+ net::TestCompletionCallback cb; |
+ reader->ReadData(body_buffer.get(), kBigEnough, cb.callback()); |
+ int rv = cb.WaitForResult(); |
+ ASSERT_EQ(static_cast<int>(expected.body.length()), rv); |
+ EXPECT_EQ(0, memcmp(expected.body.data(), body_buffer->data(), rv)); |
+ } |
+ } |
+ |
+ int32 GetEntryCount(ServiceWorkerDiskCache* disk_cache) { |
+ return disk_cache->disk_cache()->GetEntryCount(); |
+ } |
+ |
+ protected: |
+ TestBrowserThreadBundle browser_thread_bundle_; |
+ base::ScopedTempDir user_data_directory_; |
+ scoped_ptr<ServiceWorkerDiskCache> src_; |
+ scoped_ptr<ServiceWorkerDiskCache> dest_; |
+}; |
+ |
+TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_Basic) { |
+ std::vector<ResponseData> responses; |
+ responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
+ responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", "")); |
+ responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "Worker", "")); |
+ responses.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", "meta")); |
+ responses.push_back(ResponseData(10, "HTTP/1.1 200 OK\0\0", "", "meta")); |
+ responses.push_back(ResponseData(11, "HTTP/1.1 200 OK\0\0", "body", "")); |
+ responses.push_back(ResponseData(12, "HTTP/1.1 200 OK\0\0", "", "")); |
+ |
+ // Populate initial data in the src diskcache. |
+ for (const ResponseData& response : responses) { |
+ ASSERT_TRUE(WriteResponse(src_.get(), response)); |
+ VerifyResponse(src_.get(), response); |
+ } |
+ ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get())); |
+ |
+ // Migrate contents in the src diskcache to the dest diskcache. |
+ base::RunLoop run_loop; |
+ scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
+ new ServiceWorkerDiskCacheMigrator( |
+ src_.get(), dest_.get(), |
+ base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()))); |
+ migrator->Start(); |
+ run_loop.Run(); |
+ |
+ // Verify the migrated contents in the dest diskcache. |
+ for (const ResponseData& response : responses) |
+ VerifyResponse(dest_.get(), response); |
+ EXPECT_EQ(0, GetEntryCount(src_.get())); |
+ EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get())); |
+} |
+ |
+TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_RetryAfterAbort) { |
+ std::vector<ResponseData> incomplete_responses; |
+ incomplete_responses.push_back( |
+ ResponseData(1, "HTTP/1.1 200 OK\0\0", "foo", "bar")); |
+ incomplete_responses.push_back( |
+ ResponseData(2, "HTTP/1.1 200 OK\0\0", "hoge", "")); |
+ incomplete_responses.push_back( |
+ ResponseData(5, "HTTP/1.1 200 OK\0\0", "", "")); |
+ |
+ // To emulate the aborted migration, populate incomplete responses in the |
+ // src diskcache and copy them into the dest diskcache. |
+ for (const ResponseData& response : incomplete_responses) { |
+ ASSERT_TRUE(WriteResponse(src_.get(), response)); |
+ VerifyResponse(src_.get(), response); |
+ } |
+ ASSERT_EQ(static_cast<int>(incomplete_responses.size()), |
+ GetEntryCount(src_.get())); |
+ |
+ base::RunLoop run_loop1; |
+ scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
+ new ServiceWorkerDiskCacheMigrator( |
+ src_.get(), dest_.get(), |
+ base::Bind(&OnDiskCacheMigrated, run_loop1.QuitClosure()))); |
+ migrator->Start(); |
+ run_loop1.Run(); |
+ for (const ResponseData& response : incomplete_responses) |
+ VerifyResponse(dest_.get(), response); |
+ EXPECT_EQ(0, GetEntryCount(src_.get())); |
+ EXPECT_EQ(static_cast<int>(incomplete_responses.size()), |
+ GetEntryCount(dest_.get())); |
+ |
+ // Re-create the src diskcache. |
+ const base::FilePath kSrcDiskCachePath = |
+ user_data_directory_.path().AppendASCII("SrcCache2"); |
+ src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
+ net::TestCompletionCallback cb; |
+ src_->InitWithDiskBackend(kSrcDiskCachePath, kMaxDiskCacheSize, |
+ false /* force */, |
+ base::ThreadTaskRunnerHandle::Get(), cb.callback()); |
+ ASSERT_EQ(net::OK, cb.WaitForResult()); |
+ |
+ // Populate complete responses in the src diskcache. |
+ std::vector<ResponseData> responses; |
+ responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "foo", "bar")); |
+ responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "hoge", "fuga")); |
+ responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "fizz", "buzz")); |
+ for (const ResponseData& response : responses) { |
+ ASSERT_TRUE(WriteResponse(src_.get(), response)); |
+ VerifyResponse(src_.get(), response); |
+ } |
+ ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get())); |
+ |
+ // Retry to migrate responses. |
+ base::RunLoop run_loop2; |
+ migrator.reset(new ServiceWorkerDiskCacheMigrator( |
+ src_.get(), dest_.get(), |
+ base::Bind(&OnDiskCacheMigrated, run_loop2.QuitClosure()))); |
+ migrator->Start(); |
+ run_loop2.Run(); |
+ |
+ // Verify the incomplete responses were successfully overwritten. |
+ for (const ResponseData& response : responses) |
+ VerifyResponse(dest_.get(), response); |
+ EXPECT_EQ(0, GetEntryCount(src_.get())); |
+ EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get())); |
+} |
+ |
+TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_EmptyDiskCache) { |
+ base::RunLoop run_loop; |
+ scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
+ new ServiceWorkerDiskCacheMigrator( |
+ src_.get(), dest_.get(), |
+ base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()))); |
+ migrator->Start(); |
+ run_loop.Run(); |
+} |
+ |
+} // namespace content |