OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_storage.h" | |
6 | |
7 #include "base/logging.h" | 5 #include "base/logging.h" |
8 #include "base/message_loop/message_loop.h" | 6 #include "base/message_loop/message_loop.h" |
9 #include "base/run_loop.h" | 7 #include "base/run_loop.h" |
10 #include "content/browser/browser_thread_impl.h" | 8 #include "content/browser/browser_thread_impl.h" |
11 #include "content/browser/service_worker/service_worker_context_core.h" | 9 #include "content/browser/service_worker/service_worker_context_core.h" |
| 10 #include "content/browser/service_worker/service_worker_disk_cache.h" |
12 #include "content/browser/service_worker/service_worker_registration.h" | 11 #include "content/browser/service_worker/service_worker_registration.h" |
| 12 #include "content/browser/service_worker/service_worker_storage.h" |
13 #include "content/browser/service_worker/service_worker_version.h" | 13 #include "content/browser/service_worker/service_worker_version.h" |
| 14 #include "content/common/service_worker/service_worker_status_code.h" |
14 #include "content/public/test/test_browser_thread_bundle.h" | 15 #include "content/public/test/test_browser_thread_bundle.h" |
| 16 #include "net/base/io_buffer.h" |
| 17 #include "net/base/net_errors.h" |
| 18 #include "net/http/http_response_headers.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
16 | 20 |
| 21 using net::IOBuffer; |
| 22 using net::WrappedIOBuffer; |
| 23 |
17 namespace content { | 24 namespace content { |
18 | 25 |
19 namespace { | 26 namespace { |
20 | 27 |
| 28 typedef ServiceWorkerDatabase::RegistrationData RegistrationData; |
| 29 typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord; |
| 30 |
21 void StatusCallback(bool* was_called, | 31 void StatusCallback(bool* was_called, |
22 ServiceWorkerStatusCode* result, | 32 ServiceWorkerStatusCode* result, |
23 ServiceWorkerStatusCode status) { | 33 ServiceWorkerStatusCode status) { |
24 *was_called = true; | 34 *was_called = true; |
25 *result = status; | 35 *result = status; |
26 } | 36 } |
27 | 37 |
28 ServiceWorkerStorage::StatusCallback MakeStatusCallback( | 38 ServiceWorkerStorage::StatusCallback MakeStatusCallback( |
29 bool* was_called, | 39 bool* was_called, |
30 ServiceWorkerStatusCode* result) { | 40 ServiceWorkerStatusCode* result) { |
(...skipping 25 matching lines...) Expand all Loading... |
56 *was_called = true; | 66 *was_called = true; |
57 *all_out = all; | 67 *all_out = all; |
58 } | 68 } |
59 | 69 |
60 ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback( | 70 ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback( |
61 bool* was_called, | 71 bool* was_called, |
62 std::vector<ServiceWorkerRegistrationInfo>* all) { | 72 std::vector<ServiceWorkerRegistrationInfo>* all) { |
63 return base::Bind(&GetAllCallback, was_called, all); | 73 return base::Bind(&GetAllCallback, was_called, all); |
64 } | 74 } |
65 | 75 |
| 76 void OnIOComplete(int* rv_out, int rv) { |
| 77 *rv_out = rv; |
| 78 } |
| 79 |
| 80 void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) { |
| 81 scoped_ptr<ServiceWorkerResponseWriter> writer = |
| 82 storage->CreateResponseWriter(id); |
| 83 |
| 84 const char kHttpHeaders[] = |
| 85 "HTTP/1.0 200 HONKYDORY\0Content-Length: 6\0\0"; |
| 86 const char kHttpBody[] = "Hello\0"; |
| 87 scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBody)); |
| 88 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders)); |
| 89 scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo); |
| 90 info->request_time = base::Time::Now(); |
| 91 info->response_time = base::Time::Now(); |
| 92 info->was_cached = false; |
| 93 info->headers = new net::HttpResponseHeaders(raw_headers); |
| 94 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
| 95 new HttpResponseInfoIOBuffer(info.release()); |
| 96 |
| 97 int rv = -1234; |
| 98 writer->WriteInfo(info_buffer, base::Bind(&OnIOComplete, &rv)); |
| 99 base::RunLoop().RunUntilIdle(); |
| 100 EXPECT_LT(0, rv); |
| 101 |
| 102 rv = -1234; |
| 103 writer->WriteData(body, arraysize(kHttpBody), |
| 104 base::Bind(&OnIOComplete, &rv)); |
| 105 base::RunLoop().RunUntilIdle(); |
| 106 EXPECT_EQ(static_cast<int>(arraysize(kHttpBody)), rv); |
| 107 } |
| 108 |
| 109 bool VerifyBasicResponse(ServiceWorkerStorage* storage, int64 id, |
| 110 bool expected_positive_result) { |
| 111 const char kExpectedHttpBody[] = "Hello\0"; |
| 112 scoped_ptr<ServiceWorkerResponseReader> reader = |
| 113 storage->CreateResponseReader(id); |
| 114 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer = |
| 115 new HttpResponseInfoIOBuffer(); |
| 116 int rv = -1234; |
| 117 reader->ReadInfo(info_buffer, base::Bind(&OnIOComplete, &rv)); |
| 118 base::RunLoop().RunUntilIdle(); |
| 119 if (expected_positive_result) |
| 120 EXPECT_LT(0, rv); |
| 121 if (rv <= 0) |
| 122 return false; |
| 123 |
| 124 const int kBigEnough = 512; |
| 125 scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough); |
| 126 rv = -1234; |
| 127 reader->ReadData(buffer, kBigEnough, base::Bind(&OnIOComplete, &rv)); |
| 128 base::RunLoop().RunUntilIdle(); |
| 129 EXPECT_EQ(static_cast<int>(arraysize(kExpectedHttpBody)), rv); |
| 130 if (rv <= 0) |
| 131 return false; |
| 132 |
| 133 bool status_match = |
| 134 std::string("HONKYDORY") == |
| 135 info_buffer->http_info->headers->GetStatusText(); |
| 136 bool data_match = |
| 137 std::string(kExpectedHttpBody) == std::string(buffer->data()); |
| 138 |
| 139 EXPECT_TRUE(status_match); |
| 140 EXPECT_TRUE(data_match); |
| 141 return status_match && data_match; |
| 142 } |
| 143 |
66 } // namespace | 144 } // namespace |
67 | 145 |
68 class ServiceWorkerStorageTest : public testing::Test { | 146 class ServiceWorkerStorageTest : public testing::Test { |
69 public: | 147 public: |
70 ServiceWorkerStorageTest() | 148 ServiceWorkerStorageTest() |
71 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) { | 149 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) { |
72 } | 150 } |
73 | 151 |
74 virtual void SetUp() OVERRIDE { | 152 virtual void SetUp() OVERRIDE { |
75 context_.reset(new ServiceWorkerContextCore( | 153 context_.reset(new ServiceWorkerContextCore( |
76 base::FilePath(), | 154 base::FilePath(), |
77 base::MessageLoopProxy::current(), | 155 base::MessageLoopProxy::current(), |
78 base::MessageLoopProxy::current(), | 156 base::MessageLoopProxy::current(), |
79 NULL, | 157 NULL, |
80 NULL, | 158 NULL, |
81 scoped_ptr<ServiceWorkerProcessManager>())); | 159 scoped_ptr<ServiceWorkerProcessManager>())); |
82 context_ptr_ = context_->AsWeakPtr(); | 160 context_ptr_ = context_->AsWeakPtr(); |
83 } | 161 } |
84 | 162 |
85 virtual void TearDown() OVERRIDE { | 163 virtual void TearDown() OVERRIDE { |
86 context_.reset(); | 164 context_.reset(); |
87 } | 165 } |
88 | 166 |
89 ServiceWorkerStorage* storage() { return context_->storage(); } | 167 ServiceWorkerStorage* storage() { return context_->storage(); } |
90 | 168 |
| 169 // A static class method for friendliness. |
| 170 static void VerifyPurgeableListStatusCallback( |
| 171 ServiceWorkerDatabase* database, |
| 172 std::set<int64> *purgeable_ids, |
| 173 bool* was_called, |
| 174 ServiceWorkerStatusCode* result, |
| 175 ServiceWorkerStatusCode status) { |
| 176 *was_called = true; |
| 177 *result = status; |
| 178 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 179 database->GetPurgeableResourceIds(purgeable_ids)); |
| 180 } |
| 181 |
91 protected: | 182 protected: |
92 scoped_ptr<ServiceWorkerContextCore> context_; | 183 scoped_ptr<ServiceWorkerContextCore> context_; |
93 base::WeakPtr<ServiceWorkerContextCore> context_ptr_; | 184 base::WeakPtr<ServiceWorkerContextCore> context_ptr_; |
94 TestBrowserThreadBundle browser_thread_bundle_; | 185 TestBrowserThreadBundle browser_thread_bundle_; |
95 }; | 186 }; |
96 | 187 |
97 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) { | 188 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) { |
98 const GURL kScope("http://www.test.com/scope/*"); | 189 const GURL kScope("http://www.test.not/scope/*"); |
99 const GURL kScript("http://www.test.com/script.js"); | 190 const GURL kScript("http://www.test.not/script.js"); |
100 const GURL kDocumentUrl("http://www.test.com/scope/document.html"); | 191 const GURL kDocumentUrl("http://www.test.not/scope/document.html"); |
101 const int64 kRegistrationId = 0; | 192 const int64 kRegistrationId = 0; |
102 const int64 kVersionId = 0; | 193 const int64 kVersionId = 0; |
103 | 194 |
104 bool was_called = false; | 195 bool was_called = false; |
105 ServiceWorkerStatusCode result = SERVICE_WORKER_OK; | 196 ServiceWorkerStatusCode result = SERVICE_WORKER_OK; |
106 scoped_refptr<ServiceWorkerRegistration> found_registration; | 197 scoped_refptr<ServiceWorkerRegistration> found_registration; |
107 | 198 |
108 // We shouldn't find anything without having stored anything. | 199 // We shouldn't find anything without having stored anything. |
109 storage()->FindRegistrationForDocument( | 200 storage()->FindRegistrationForDocument( |
110 kDocumentUrl, | 201 kDocumentUrl, |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 kScope.GetOrigin(), | 394 kScope.GetOrigin(), |
304 MakeStatusCallback(&was_called, &result)); | 395 MakeStatusCallback(&was_called, &result)); |
305 EXPECT_FALSE(was_called); | 396 EXPECT_FALSE(was_called); |
306 base::RunLoop().RunUntilIdle(); | 397 base::RunLoop().RunUntilIdle(); |
307 EXPECT_TRUE(was_called); | 398 EXPECT_TRUE(was_called); |
308 EXPECT_EQ(SERVICE_WORKER_OK, result); | 399 EXPECT_EQ(SERVICE_WORKER_OK, result); |
309 was_called = false; | 400 was_called = false; |
310 } | 401 } |
311 | 402 |
312 TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) { | 403 TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) { |
313 const GURL kScope("http://www.test.com/scope/*"); | 404 const GURL kScope("http://www.test.not/scope/*"); |
314 const GURL kScript("http://www.test.com/script.js"); | 405 const GURL kScript("http://www.test.not/script.js"); |
315 const GURL kDocumentUrl("http://www.test.com/scope/document.html"); | 406 const GURL kDocumentUrl("http://www.test.not/scope/document.html"); |
316 const int64 kRegistrationId = 0; | 407 const int64 kRegistrationId = 0; |
317 const int64 kVersionId = 0; | 408 const int64 kVersionId = 0; |
318 | 409 |
319 bool was_called = false; | 410 bool was_called = false; |
320 ServiceWorkerStatusCode result = SERVICE_WORKER_OK; | 411 ServiceWorkerStatusCode result = SERVICE_WORKER_OK; |
321 scoped_refptr<ServiceWorkerRegistration> found_registration; | 412 scoped_refptr<ServiceWorkerRegistration> found_registration; |
322 | 413 |
323 // Create an unstored registration. | 414 // Create an unstored registration. |
324 scoped_refptr<ServiceWorkerRegistration> live_registration = | 415 scoped_refptr<ServiceWorkerRegistration> live_registration = |
325 new ServiceWorkerRegistration( | 416 new ServiceWorkerRegistration( |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 was_called = false; | 526 was_called = false; |
436 | 527 |
437 storage()->GetAllRegistrations( | 528 storage()->GetAllRegistrations( |
438 MakeGetAllCallback(&was_called, &all_registrations)); | 529 MakeGetAllCallback(&was_called, &all_registrations)); |
439 base::RunLoop().RunUntilIdle(); | 530 base::RunLoop().RunUntilIdle(); |
440 ASSERT_TRUE(was_called); | 531 ASSERT_TRUE(was_called); |
441 EXPECT_TRUE(all_registrations.empty()); | 532 EXPECT_TRUE(all_registrations.empty()); |
442 was_called = false; | 533 was_called = false; |
443 } | 534 } |
444 | 535 |
| 536 TEST_F(ServiceWorkerStorageTest, ResourceIdsAreStoredAndPurged) { |
| 537 storage()->LazyInitialize(base::Bind(&base::DoNothing)); |
| 538 base::RunLoop().RunUntilIdle(); |
| 539 const GURL kScope("http://www.test.not/scope/*"); |
| 540 const GURL kScript("http://www.test.not/script.js"); |
| 541 const GURL kImport("http://www.test.not/import.js"); |
| 542 const GURL kDocumentUrl("http://www.test.not/scope/document.html"); |
| 543 const int64 kRegistrationId = storage()->NewRegistrationId(); |
| 544 const int64 kVersionId = storage()->NewVersionId(); |
| 545 const int64 kResourceId1 = storage()->NewResourceId(); |
| 546 const int64 kResourceId2 = storage()->NewResourceId(); |
| 547 |
| 548 // Cons up a new registration+version with two script resources. |
| 549 RegistrationData data; |
| 550 data.registration_id = kRegistrationId; |
| 551 data.scope = kScope; |
| 552 data.script = kScript; |
| 553 data.version_id = kVersionId; |
| 554 data.is_active = false; |
| 555 std::vector<ResourceRecord> resources; |
| 556 resources.push_back(ResourceRecord(kResourceId1, kScript)); |
| 557 resources.push_back(ResourceRecord(kResourceId2, kImport)); |
| 558 scoped_refptr<ServiceWorkerRegistration> registration = |
| 559 storage()->GetOrCreateRegistration(data, resources); |
| 560 registration->pending_version()->SetStatus(ServiceWorkerVersion::NEW); |
| 561 |
| 562 // Add the resources ids to the uncommitted list. |
| 563 std::set<int64> resource_ids; |
| 564 resource_ids.insert(kResourceId1); |
| 565 resource_ids.insert(kResourceId2); |
| 566 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 567 storage()->database_->WriteUncommittedResourceIds(resource_ids)); |
| 568 |
| 569 // And dump something in the disk cache for them. |
| 570 WriteBasicResponse(storage(), kResourceId1); |
| 571 WriteBasicResponse(storage(), kResourceId2); |
| 572 EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId1, true)); |
| 573 EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId2, true)); |
| 574 |
| 575 // Storing the registration/version should take the resources ids out |
| 576 // of the uncommitted list. |
| 577 bool was_called = false; |
| 578 ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; |
| 579 storage()->StoreRegistration(registration, registration->pending_version(), |
| 580 MakeStatusCallback(&was_called, &result)); |
| 581 base::RunLoop().RunUntilIdle(); |
| 582 ASSERT_TRUE(was_called); |
| 583 EXPECT_EQ(SERVICE_WORKER_OK, result); |
| 584 std::set<int64> verify_ids; |
| 585 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 586 storage()->database_->GetUncommittedResourceIds(&verify_ids)); |
| 587 EXPECT_TRUE(verify_ids.empty()); |
| 588 |
| 589 // Deleting it should result in the resources being added to the |
| 590 // purgeable list and then doomed in the disk cache and removed from |
| 591 // that list. |
| 592 was_called = false; |
| 593 verify_ids.clear(); |
| 594 storage()->DeleteRegistration( |
| 595 registration->id(), kScope.GetOrigin(), |
| 596 base::Bind(&VerifyPurgeableListStatusCallback, |
| 597 base::Unretained(storage()->database_.get()), |
| 598 &verify_ids, &was_called, &result)); |
| 599 base::RunLoop().RunUntilIdle(); |
| 600 ASSERT_TRUE(was_called); |
| 601 EXPECT_EQ(SERVICE_WORKER_OK, result); |
| 602 EXPECT_EQ(2u, verify_ids.size()); |
| 603 verify_ids.clear(); |
| 604 EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| 605 storage()->database_->GetPurgeableResourceIds(&verify_ids)); |
| 606 EXPECT_TRUE(verify_ids.empty()); |
| 607 |
| 608 EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId1, false)); |
| 609 EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId2, false)); |
| 610 } |
| 611 |
445 } // namespace content | 612 } // namespace content |
OLD | NEW |