OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h" |
| 6 |
| 7 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/run_loop.h" |
| 9 #include "base/thread_task_runner_handle.h" |
| 10 #include "content/public/test/test_browser_thread_bundle.h" |
| 11 #include "net/base/io_buffer.h" |
| 12 #include "net/base/net_errors.h" |
| 13 #include "net/base/test_completion_callback.h" |
| 14 #include "net/http/http_response_headers.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 namespace content { |
| 18 |
| 19 namespace { |
| 20 |
| 21 const int kMaxDiskCacheSize = 250 * 1024 * 1024; |
| 22 |
| 23 struct ResponseData { |
| 24 int64 resource_id; |
| 25 std::string headers; |
| 26 std::string body; |
| 27 std::string metadata; |
| 28 |
| 29 ResponseData(int64 resource_id, |
| 30 const std::string& headers, |
| 31 const std::string& body, |
| 32 const std::string& metadata) |
| 33 : resource_id(resource_id), |
| 34 headers(headers), |
| 35 body(body), |
| 36 metadata(metadata) {} |
| 37 }; |
| 38 |
| 39 void OnDiskCacheMigrated(const base::Closure& callback, |
| 40 ServiceWorkerStatusCode status) { |
| 41 EXPECT_EQ(SERVICE_WORKER_OK, status); |
| 42 callback.Run(); |
| 43 } |
| 44 |
| 45 } // namespace |
| 46 |
| 47 class ServiceWorkerDiskCacheMigratorTest : public testing::Test { |
| 48 public: |
| 49 ServiceWorkerDiskCacheMigratorTest() |
| 50 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} |
| 51 |
| 52 void SetUp() override { |
| 53 ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); |
| 54 const base::FilePath kSrcDiskCachePath = |
| 55 user_data_directory_.path().AppendASCII("SrcCache"); |
| 56 const base::FilePath kDestDiskCachePath = |
| 57 user_data_directory_.path().AppendASCII("DestCache"); |
| 58 |
| 59 // Initialize the src BlockFile diskcache. |
| 60 src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
| 61 net::TestCompletionCallback cb1; |
| 62 src_->InitWithDiskBackend( |
| 63 kSrcDiskCachePath, kMaxDiskCacheSize, false /* force */, |
| 64 base::ThreadTaskRunnerHandle::Get(), cb1.callback()); |
| 65 ASSERT_EQ(net::OK, cb1.WaitForResult()); |
| 66 |
| 67 // Initialize the dest Simple diskcache. |
| 68 dest_ = ServiceWorkerDiskCache::CreateWithSimpleBackend(); |
| 69 net::TestCompletionCallback cb2; |
| 70 dest_->InitWithDiskBackend( |
| 71 kDestDiskCachePath, kMaxDiskCacheSize, false /* force */, |
| 72 base::ThreadTaskRunnerHandle::Get(), cb2.callback()); |
| 73 ASSERT_EQ(net::OK, cb2.WaitForResult()); |
| 74 } |
| 75 |
| 76 bool WriteResponse(ServiceWorkerDiskCache* disk_cache, |
| 77 const ResponseData& response) { |
| 78 scoped_ptr<ServiceWorkerResponseWriter> writer( |
| 79 new ServiceWorkerResponseWriter(response.resource_id, disk_cache)); |
| 80 |
| 81 // Write the response info. |
| 82 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); |
| 83 info->request_time = base::Time::Now(); |
| 84 info->response_time = base::Time::Now(); |
| 85 info->was_cached = false; |
| 86 info->headers = new net::HttpResponseHeaders(response.headers); |
| 87 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
| 88 new HttpResponseInfoIOBuffer(info.release()); |
| 89 { |
| 90 net::TestCompletionCallback cb; |
| 91 writer->WriteInfo(info_buffer.get(), cb.callback()); |
| 92 int rv = cb.WaitForResult(); |
| 93 EXPECT_LT(0, rv); |
| 94 if (rv < 0) |
| 95 return false; |
| 96 } |
| 97 |
| 98 // Write the response metadata. |
| 99 scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer( |
| 100 new ServiceWorkerResponseMetadataWriter(response.resource_id, |
| 101 disk_cache)); |
| 102 scoped_refptr<net::IOBuffer> metadata_buffer( |
| 103 new net::WrappedIOBuffer(response.metadata.data())); |
| 104 { |
| 105 const int metadata_length = response.metadata.length(); |
| 106 net::TestCompletionCallback cb; |
| 107 metadata_writer->WriteMetadata(metadata_buffer.get(), metadata_length, |
| 108 cb.callback()); |
| 109 int rv = cb.WaitForResult(); |
| 110 EXPECT_EQ(metadata_length, rv); |
| 111 if (metadata_length != rv) |
| 112 return false; |
| 113 } |
| 114 |
| 115 // Write the response body. |
| 116 scoped_refptr<net::IOBuffer> body_buffer( |
| 117 new net::WrappedIOBuffer(response.body.data())); |
| 118 { |
| 119 const int body_length = response.body.length(); |
| 120 net::TestCompletionCallback cb; |
| 121 writer->WriteData(body_buffer.get(), body_length, cb.callback()); |
| 122 int rv = cb.WaitForResult(); |
| 123 EXPECT_EQ(body_length, rv); |
| 124 if (body_length != rv) |
| 125 return false; |
| 126 } |
| 127 |
| 128 return true; |
| 129 } |
| 130 |
| 131 void VerifyResponse(ServiceWorkerDiskCache* disk_cache, |
| 132 const ResponseData& expected) { |
| 133 scoped_ptr<ServiceWorkerResponseReader> reader( |
| 134 new ServiceWorkerResponseReader(expected.resource_id, disk_cache)); |
| 135 |
| 136 // Verify the response info. |
| 137 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
| 138 new HttpResponseInfoIOBuffer; |
| 139 { |
| 140 net::TestCompletionCallback cb; |
| 141 reader->ReadInfo(info_buffer.get(), cb.callback()); |
| 142 int rv = cb.WaitForResult(); |
| 143 EXPECT_LT(0, rv); |
| 144 EXPECT_EQ("OK", info_buffer->http_info->headers->GetStatusText()); |
| 145 } |
| 146 |
| 147 // Verify the response metadata. |
| 148 if (!expected.metadata.empty()) { |
| 149 ASSERT_TRUE(info_buffer->http_info->metadata); |
| 150 const int data_size = info_buffer->http_info->metadata->size(); |
| 151 ASSERT_EQ(static_cast<int>(expected.metadata.length()), data_size); |
| 152 EXPECT_EQ(0, memcmp(expected.metadata.data(), |
| 153 info_buffer->http_info->metadata->data(), |
| 154 expected.metadata.length())); |
| 155 } |
| 156 |
| 157 // Verify the response body. |
| 158 { |
| 159 const int kBigEnough = 512; |
| 160 scoped_refptr<net::IOBuffer> body_buffer = new net::IOBuffer(kBigEnough); |
| 161 net::TestCompletionCallback cb; |
| 162 reader->ReadData(body_buffer.get(), kBigEnough, cb.callback()); |
| 163 int rv = cb.WaitForResult(); |
| 164 ASSERT_EQ(static_cast<int>(expected.body.length()), rv); |
| 165 EXPECT_EQ(0, memcmp(expected.body.data(), body_buffer->data(), rv)); |
| 166 } |
| 167 } |
| 168 |
| 169 int32 GetEntryCount(ServiceWorkerDiskCache* disk_cache) { |
| 170 return disk_cache->disk_cache()->GetEntryCount(); |
| 171 } |
| 172 |
| 173 protected: |
| 174 TestBrowserThreadBundle browser_thread_bundle_; |
| 175 base::ScopedTempDir user_data_directory_; |
| 176 scoped_ptr<ServiceWorkerDiskCache> src_; |
| 177 scoped_ptr<ServiceWorkerDiskCache> dest_; |
| 178 }; |
| 179 |
| 180 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_Basic) { |
| 181 std::vector<ResponseData> responses; |
| 182 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", "")); |
| 183 responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", "")); |
| 184 responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "Worker", "")); |
| 185 responses.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", "meta")); |
| 186 responses.push_back(ResponseData(10, "HTTP/1.1 200 OK\0\0", "", "meta")); |
| 187 responses.push_back(ResponseData(11, "HTTP/1.1 200 OK\0\0", "body", "")); |
| 188 responses.push_back(ResponseData(12, "HTTP/1.1 200 OK\0\0", "", "")); |
| 189 |
| 190 // Populate initial data in the src diskcache. |
| 191 for (const ResponseData& response : responses) { |
| 192 ASSERT_TRUE(WriteResponse(src_.get(), response)); |
| 193 VerifyResponse(src_.get(), response); |
| 194 } |
| 195 ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get())); |
| 196 |
| 197 // Migrate contents in the src diskcache to the dest diskcache. |
| 198 base::RunLoop run_loop; |
| 199 scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
| 200 new ServiceWorkerDiskCacheMigrator( |
| 201 src_.get(), dest_.get(), |
| 202 base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()))); |
| 203 migrator->Start(); |
| 204 run_loop.Run(); |
| 205 |
| 206 // Verify the migrated contents in the dest diskcache. |
| 207 for (const ResponseData& response : responses) |
| 208 VerifyResponse(dest_.get(), response); |
| 209 EXPECT_EQ(0, GetEntryCount(src_.get())); |
| 210 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get())); |
| 211 } |
| 212 |
| 213 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_RetryAfterAbort) { |
| 214 std::vector<ResponseData> incomplete_responses; |
| 215 incomplete_responses.push_back( |
| 216 ResponseData(1, "HTTP/1.1 200 OK\0\0", "foo", "bar")); |
| 217 incomplete_responses.push_back( |
| 218 ResponseData(2, "HTTP/1.1 200 OK\0\0", "hoge", "")); |
| 219 incomplete_responses.push_back( |
| 220 ResponseData(5, "HTTP/1.1 200 OK\0\0", "", "")); |
| 221 |
| 222 // To emulate the aborted migration, populate incomplete responses in the |
| 223 // src diskcache and copy them into the dest diskcache. |
| 224 for (const ResponseData& response : incomplete_responses) { |
| 225 ASSERT_TRUE(WriteResponse(src_.get(), response)); |
| 226 VerifyResponse(src_.get(), response); |
| 227 } |
| 228 ASSERT_EQ(static_cast<int>(incomplete_responses.size()), |
| 229 GetEntryCount(src_.get())); |
| 230 |
| 231 base::RunLoop run_loop1; |
| 232 scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
| 233 new ServiceWorkerDiskCacheMigrator( |
| 234 src_.get(), dest_.get(), |
| 235 base::Bind(&OnDiskCacheMigrated, run_loop1.QuitClosure()))); |
| 236 migrator->Start(); |
| 237 run_loop1.Run(); |
| 238 for (const ResponseData& response : incomplete_responses) |
| 239 VerifyResponse(dest_.get(), response); |
| 240 EXPECT_EQ(0, GetEntryCount(src_.get())); |
| 241 EXPECT_EQ(static_cast<int>(incomplete_responses.size()), |
| 242 GetEntryCount(dest_.get())); |
| 243 |
| 244 // Re-create the src diskcache. |
| 245 const base::FilePath kSrcDiskCachePath = |
| 246 user_data_directory_.path().AppendASCII("SrcCache2"); |
| 247 src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
| 248 net::TestCompletionCallback cb; |
| 249 src_->InitWithDiskBackend(kSrcDiskCachePath, kMaxDiskCacheSize, |
| 250 false /* force */, |
| 251 base::ThreadTaskRunnerHandle::Get(), cb.callback()); |
| 252 ASSERT_EQ(net::OK, cb.WaitForResult()); |
| 253 |
| 254 // Populate complete responses in the src diskcache. |
| 255 std::vector<ResponseData> responses; |
| 256 responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "foo", "bar")); |
| 257 responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "hoge", "fuga")); |
| 258 responses.push_back(ResponseData(5, "HTTP/1.1 200 OK\0\0", "fizz", "buzz")); |
| 259 for (const ResponseData& response : responses) { |
| 260 ASSERT_TRUE(WriteResponse(src_.get(), response)); |
| 261 VerifyResponse(src_.get(), response); |
| 262 } |
| 263 ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get())); |
| 264 |
| 265 // Retry to migrate responses. |
| 266 base::RunLoop run_loop2; |
| 267 migrator.reset(new ServiceWorkerDiskCacheMigrator( |
| 268 src_.get(), dest_.get(), |
| 269 base::Bind(&OnDiskCacheMigrated, run_loop2.QuitClosure()))); |
| 270 migrator->Start(); |
| 271 run_loop2.Run(); |
| 272 |
| 273 // Verify the incomplete responses were successfully overwritten. |
| 274 for (const ResponseData& response : responses) |
| 275 VerifyResponse(dest_.get(), response); |
| 276 EXPECT_EQ(0, GetEntryCount(src_.get())); |
| 277 EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get())); |
| 278 } |
| 279 |
| 280 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateResponses_EmptyDiskCache) { |
| 281 base::RunLoop run_loop; |
| 282 scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
| 283 new ServiceWorkerDiskCacheMigrator( |
| 284 src_.get(), dest_.get(), |
| 285 base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()))); |
| 286 migrator->Start(); |
| 287 run_loop.Run(); |
| 288 } |
| 289 |
| 290 } // namespace content |
OLD | NEW |