Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_storage_unittest.cc
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
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_disk_cache.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_storage.h"
16 #include "content/browser/service_worker/service_worker_utils.h"
17 #include "content/browser/service_worker/service_worker_version.h"
18 #include "content/common/service_worker/service_worker_status_code.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/http/http_response_headers.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using net::IOBuffer;
27 using net::TestCompletionCallback;
28 using net::WrappedIOBuffer;
29
30 namespace content {
31
32 namespace {
33
34 typedef ServiceWorkerDatabase::RegistrationData RegistrationData;
35 typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord;
36
37 void StatusCallback(bool* was_called,
38                     ServiceWorkerStatusCode* result,
39                     ServiceWorkerStatusCode status) {
40   *was_called = true;
41   *result = status;
42 }
43
44 ServiceWorkerStorage::StatusCallback MakeStatusCallback(
45     bool* was_called,
46     ServiceWorkerStatusCode* result) {
47   return base::Bind(&StatusCallback, was_called, result);
48 }
49
50 void FindCallback(
51     bool* was_called,
52     ServiceWorkerStatusCode* result,
53     scoped_refptr<ServiceWorkerRegistration>* found,
54     ServiceWorkerStatusCode status,
55     const scoped_refptr<ServiceWorkerRegistration>& registration) {
56   *was_called = true;
57   *result = status;
58   *found = registration;
59 }
60
61 ServiceWorkerStorage::FindRegistrationCallback MakeFindCallback(
62     bool* was_called,
63     ServiceWorkerStatusCode* result,
64     scoped_refptr<ServiceWorkerRegistration>* found) {
65   return base::Bind(&FindCallback, was_called, result, found);
66 }
67
68 void GetAllCallback(
69     bool* was_called,
70     std::vector<ServiceWorkerRegistrationInfo>* all_out,
71     const std::vector<ServiceWorkerRegistrationInfo>& all) {
72   *was_called = true;
73   *all_out = all;
74 }
75
76 ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback(
77     bool* was_called,
78     std::vector<ServiceWorkerRegistrationInfo>* all) {
79   return base::Bind(&GetAllCallback, was_called, all);
80 }
81
82 void OnIOComplete(int* rv_out, int rv) {
83   *rv_out = rv;
84 }
85
86 void OnCompareComplete(
87     ServiceWorkerStatusCode* status_out, bool* are_equal_out,
88     ServiceWorkerStatusCode status, bool are_equal) {
89   *status_out = status;
90   *are_equal_out = are_equal;
91 }
92
93 void WriteResponse(
94     ServiceWorkerStorage* storage, int64 id,
95     const std::string& headers,
96     IOBuffer* body, int length) {
97   scoped_ptr<ServiceWorkerResponseWriter> writer =
98       storage->CreateResponseWriter(id);
99
100   scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
101   info->request_time = base::Time::Now();
102   info->response_time = base::Time::Now();
103   info->was_cached = false;
104   info->headers = new net::HttpResponseHeaders(headers);
105   scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
106       new HttpResponseInfoIOBuffer(info.release());
107
108   int rv = -1234;
109   writer->WriteInfo(info_buffer, base::Bind(&OnIOComplete, &rv));
110   base::RunLoop().RunUntilIdle();
111   EXPECT_LT(0, rv);
112
113   rv = -1234;
114   writer->WriteData(body, length, base::Bind(&OnIOComplete, &rv));
115   base::RunLoop().RunUntilIdle();
116   EXPECT_EQ(length, rv);
117 }
118
119 void WriteStringResponse(
120     ServiceWorkerStorage* storage, int64 id,
121     const std::string& headers,
122     const std::string& body) {
123   scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(body.data()));
124   WriteResponse(storage, id, headers, body_buffer, body.length());
125 }
126
127 void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) {
128   scoped_ptr<ServiceWorkerResponseWriter> writer =
129       storage->CreateResponseWriter(id);
130
131   const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0Content-Length: 5\0\0";
132   const char kHttpBody[] = "Hello";
133   std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
134   WriteStringResponse(storage, id, headers, std::string(kHttpBody));
135 }
136
137 bool VerifyBasicResponse(ServiceWorkerStorage* storage, int64 id,
138                          bool expected_positive_result) {
139   const std::string kExpectedHttpBody("Hello");
140   scoped_ptr<ServiceWorkerResponseReader> reader =
141       storage->CreateResponseReader(id);
142   scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
143       new HttpResponseInfoIOBuffer();
144   {
145     TestCompletionCallback cb;
146     reader->ReadInfo(info_buffer, cb.callback());
147     int rv = cb.WaitForResult();
148     if (expected_positive_result)
149       EXPECT_LT(0, rv);
150     if (rv <= 0)
151       return false;
152   }
153
154   std::string received_body;
155   {
156     const int kBigEnough = 512;
157     scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough);
158     TestCompletionCallback cb;
159     reader->ReadData(buffer, kBigEnough, cb.callback());
160     int rv = cb.WaitForResult();
161     EXPECT_EQ(static_cast<int>(kExpectedHttpBody.size()), rv);
162     if (rv <= 0)
163       return false;
164     received_body.assign(buffer->data(), rv);
165   }
166
167   bool status_match =
168       std::string("HONKYDORY") ==
169           info_buffer->http_info->headers->GetStatusText();
170   bool data_match = kExpectedHttpBody == received_body;
171
172   EXPECT_TRUE(status_match);
173   EXPECT_TRUE(data_match);
174   return status_match && data_match;
175 }
176
177 void WriteResponseOfSize(ServiceWorkerStorage* storage, int64 id,
178                          char val, int size) {
179   const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\00";
180   std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
181   scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size);
182   memset(buffer->data(), val, size);
183   WriteResponse(storage, id, headers, buffer, size);
184 }
185
186 }  // namespace
187
188 class ServiceWorkerStorageTest : public testing::Test {
189  public:
190   ServiceWorkerStorageTest()
191       : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
192   }
193
194   virtual void SetUp() OVERRIDE {
195     context_.reset(
196         new ServiceWorkerContextCore(GetUserDataDirectory(),
197                                      base::MessageLoopProxy::current(),
198                                      base::MessageLoopProxy::current(),
199                                      base::MessageLoopProxy::current(),
200                                      NULL,
201                                      NULL,
202                                      NULL));
203     context_ptr_ = context_->AsWeakPtr();
204   }
205
206   virtual void TearDown() OVERRIDE {
207     context_.reset();
208   }
209
210   virtual base::FilePath GetUserDataDirectory() { return base::FilePath(); }
211
212   ServiceWorkerStorage* storage() { return context_->storage(); }
213
214   // A static class method for friendliness.
215   static void VerifyPurgeableListStatusCallback(
216       ServiceWorkerDatabase* database,
217       std::set<int64> *purgeable_ids,
218       bool* was_called,
219       ServiceWorkerStatusCode* result,
220       ServiceWorkerStatusCode status) {
221     *was_called = true;
222     *result = status;
223     EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
224               database->GetPurgeableResourceIds(purgeable_ids));
225   }
226
227  protected:
228   ServiceWorkerStatusCode StoreRegistration(
229       scoped_refptr<ServiceWorkerRegistration> registration,
230       scoped_refptr<ServiceWorkerVersion> version) {
231     bool was_called = false;
232     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
233     storage()->StoreRegistration(
234         registration, version, MakeStatusCallback(&was_called, &result));
235     EXPECT_FALSE(was_called);  // always async
236     base::RunLoop().RunUntilIdle();
237     EXPECT_TRUE(was_called);
238     return result;
239   }
240
241   ServiceWorkerStatusCode DeleteRegistration(
242       int64 registration_id,
243       const GURL& origin) {
244     bool was_called = false;
245     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
246     storage()->DeleteRegistration(
247         registration_id, origin, MakeStatusCallback(&was_called, &result));
248     EXPECT_FALSE(was_called);  // always async
249     base::RunLoop().RunUntilIdle();
250     EXPECT_TRUE(was_called);
251     return result;
252   }
253
254   void GetAllRegistrations(
255       std::vector<ServiceWorkerRegistrationInfo>* registrations) {
256     bool was_called = false;
257     storage()->GetAllRegistrations(
258         MakeGetAllCallback(&was_called, registrations));
259     EXPECT_FALSE(was_called);  // always async
260     base::RunLoop().RunUntilIdle();
261     EXPECT_TRUE(was_called);
262   }
263
264   ServiceWorkerStatusCode UpdateToActiveState(
265       scoped_refptr<ServiceWorkerRegistration> registration) {
266     bool was_called = false;
267     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
268     storage()->UpdateToActiveState(
269         registration, MakeStatusCallback(&was_called, &result));
270     EXPECT_FALSE(was_called);  // always async
271     base::RunLoop().RunUntilIdle();
272     EXPECT_TRUE(was_called);
273     return result;
274   }
275
276   void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) {
277     storage()->UpdateLastUpdateCheckTime(registration);
278     base::RunLoop().RunUntilIdle();
279   }
280
281   ServiceWorkerStatusCode FindRegistrationForDocument(
282       const GURL& document_url,
283       scoped_refptr<ServiceWorkerRegistration>* registration) {
284     bool was_called = false;
285     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
286     storage()->FindRegistrationForDocument(
287         document_url, MakeFindCallback(&was_called, &result, registration));
288     base::RunLoop().RunUntilIdle();
289     EXPECT_TRUE(was_called);
290     return result;
291   }
292
293   ServiceWorkerStatusCode FindRegistrationForPattern(
294       const GURL& scope,
295       scoped_refptr<ServiceWorkerRegistration>* registration) {
296     bool was_called = false;
297     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
298     storage()->FindRegistrationForPattern(
299         scope, MakeFindCallback(&was_called, &result, registration));
300     EXPECT_FALSE(was_called);  // always async
301     base::RunLoop().RunUntilIdle();
302     EXPECT_TRUE(was_called);
303     return result;
304   }
305
306   ServiceWorkerStatusCode FindRegistrationForId(
307       int64 registration_id,
308       const GURL& origin,
309       scoped_refptr<ServiceWorkerRegistration>* registration) {
310     bool was_called = false;
311     ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
312     storage()->FindRegistrationForId(
313         registration_id, origin,
314         MakeFindCallback(&was_called, &result, registration));
315     base::RunLoop().RunUntilIdle();
316     EXPECT_TRUE(was_called);
317     return result;
318   }
319
320   scoped_ptr<ServiceWorkerContextCore> context_;
321   base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
322   TestBrowserThreadBundle browser_thread_bundle_;
323 };
324
325 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
326   const GURL kScope("http://www.test.not/scope/");
327   const GURL kScript("http://www.test.not/script.js");
328   const GURL kDocumentUrl("http://www.test.not/scope/document.html");
329   const int64 kRegistrationId = 0;
330   const int64 kVersionId = 0;
331   const base::Time kToday = base::Time::Now();
332   const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
333
334   scoped_refptr<ServiceWorkerRegistration> found_registration;
335
336   // We shouldn't find anything without having stored anything.
337   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
338             FindRegistrationForDocument(kDocumentUrl, &found_registration));
339   EXPECT_FALSE(found_registration);
340
341   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
342             FindRegistrationForPattern(kScope, &found_registration));
343   EXPECT_FALSE(found_registration);
344
345   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
346             FindRegistrationForId(
347                 kRegistrationId, kScope.GetOrigin(), &found_registration));
348   EXPECT_FALSE(found_registration);
349
350   // Store something.
351   scoped_refptr<ServiceWorkerRegistration> live_registration =
352       new ServiceWorkerRegistration(
353           kScope, kScript, kRegistrationId, context_ptr_);
354   scoped_refptr<ServiceWorkerVersion> live_version =
355       new ServiceWorkerVersion(
356           live_registration, kVersionId, context_ptr_);
357   live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
358   live_registration->SetWaitingVersion(live_version);
359   live_registration->set_last_update_check(kYesterday);
360   EXPECT_EQ(SERVICE_WORKER_OK,
361             StoreRegistration(live_registration, live_version));
362
363   // Now we should find it and get the live ptr back immediately.
364   EXPECT_EQ(SERVICE_WORKER_OK,
365             FindRegistrationForDocument(kDocumentUrl, &found_registration));
366   EXPECT_EQ(live_registration, found_registration);
367   found_registration = NULL;
368
369   // But FindRegistrationForPattern is always async.
370   EXPECT_EQ(SERVICE_WORKER_OK,
371             FindRegistrationForPattern(kScope, &found_registration));
372   EXPECT_EQ(live_registration, found_registration);
373   found_registration = NULL;
374
375   // Can be found by id too.
376   EXPECT_EQ(SERVICE_WORKER_OK,
377             FindRegistrationForId(
378                 kRegistrationId, kScope.GetOrigin(), &found_registration));
379   ASSERT_TRUE(found_registration);
380   EXPECT_EQ(kRegistrationId, found_registration->id());
381   EXPECT_EQ(live_registration, found_registration);
382   found_registration = NULL;
383
384   // Drop the live registration, but keep the version live.
385   live_registration = NULL;
386
387   // Now FindRegistrationForDocument should be async.
388   EXPECT_EQ(SERVICE_WORKER_OK,
389             FindRegistrationForDocument(kDocumentUrl, &found_registration));
390   ASSERT_TRUE(found_registration);
391   EXPECT_EQ(kRegistrationId, found_registration->id());
392   EXPECT_TRUE(found_registration->HasOneRef());
393   EXPECT_EQ(live_version, found_registration->waiting_version());
394   found_registration = NULL;
395
396   // Drop the live version too.
397   live_version = NULL;
398
399   // And FindRegistrationForPattern is always async.
400   EXPECT_EQ(SERVICE_WORKER_OK,
401             FindRegistrationForPattern(kScope, &found_registration));
402   ASSERT_TRUE(found_registration);
403   EXPECT_EQ(kRegistrationId, found_registration->id());
404   EXPECT_TRUE(found_registration->HasOneRef());
405   EXPECT_FALSE(found_registration->active_version());
406   ASSERT_TRUE(found_registration->waiting_version());
407   EXPECT_EQ(kYesterday, found_registration->last_update_check());
408   EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
409             found_registration->waiting_version()->status());
410
411   // Update to active and update the last check time.
412   scoped_refptr<ServiceWorkerVersion> temp_version =
413       found_registration->waiting_version();
414   temp_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
415   found_registration->SetActiveVersion(temp_version);
416   temp_version = NULL;
417   EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration));
418   found_registration->set_last_update_check(kToday);
419   UpdateLastUpdateCheckTime(found_registration);
420
421   found_registration = NULL;
422
423   // Trying to update a unstored registration to active should fail.
424   scoped_refptr<ServiceWorkerRegistration> unstored_registration =
425       new ServiceWorkerRegistration(
426           kScope, kScript, kRegistrationId + 1, context_ptr_);
427   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
428             UpdateToActiveState(unstored_registration));
429   unstored_registration = NULL;
430
431   // The Find methods should return a registration with an active version
432   // and the expected update time.
433   EXPECT_EQ(SERVICE_WORKER_OK,
434             FindRegistrationForDocument(kDocumentUrl, &found_registration));
435   ASSERT_TRUE(found_registration);
436   EXPECT_EQ(kRegistrationId, found_registration->id());
437   EXPECT_TRUE(found_registration->HasOneRef());
438   EXPECT_FALSE(found_registration->waiting_version());
439   ASSERT_TRUE(found_registration->active_version());
440   EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
441             found_registration->active_version()->status());
442   EXPECT_EQ(kToday, found_registration->last_update_check());
443
444   // Delete from storage but with a instance still live.
445   EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
446   EXPECT_EQ(SERVICE_WORKER_OK,
447             DeleteRegistration(kRegistrationId, kScope.GetOrigin()));
448   EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
449
450   // Should no longer be found.
451   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
452             FindRegistrationForId(
453                 kRegistrationId, kScope.GetOrigin(), &found_registration));
454   EXPECT_FALSE(found_registration);
455
456   // Deleting an unstored registration should succeed.
457   EXPECT_EQ(SERVICE_WORKER_OK,
458             DeleteRegistration(kRegistrationId + 1, kScope.GetOrigin()));
459 }
460
461 TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
462   const GURL kScope("http://www.test.not/scope/");
463   const GURL kScript("http://www.test.not/script.js");
464   const GURL kDocumentUrl("http://www.test.not/scope/document.html");
465   const int64 kRegistrationId = 0;
466   const int64 kVersionId = 0;
467
468   scoped_refptr<ServiceWorkerRegistration> found_registration;
469
470   // Create an unstored registration.
471   scoped_refptr<ServiceWorkerRegistration> live_registration =
472       new ServiceWorkerRegistration(
473           kScope, kScript, kRegistrationId, context_ptr_);
474   scoped_refptr<ServiceWorkerVersion> live_version =
475       new ServiceWorkerVersion(
476           live_registration, kVersionId, context_ptr_);
477   live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
478   live_registration->SetWaitingVersion(live_version);
479
480   // Should not be findable, including by GetAllRegistrations.
481   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
482             FindRegistrationForId(
483                 kRegistrationId, kScope.GetOrigin(), &found_registration));
484   EXPECT_FALSE(found_registration);
485
486   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
487             FindRegistrationForDocument(kDocumentUrl, &found_registration));
488   EXPECT_FALSE(found_registration);
489
490   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
491             FindRegistrationForPattern(kScope, &found_registration));
492   EXPECT_FALSE(found_registration);
493
494   std::vector<ServiceWorkerRegistrationInfo> all_registrations;
495   GetAllRegistrations(&all_registrations);
496   EXPECT_TRUE(all_registrations.empty());
497
498   // Notify storage of it being installed.
499   storage()->NotifyInstallingRegistration(live_registration);
500
501   // Now should be findable.
502   EXPECT_EQ(SERVICE_WORKER_OK,
503             FindRegistrationForId(
504                 kRegistrationId, kScope.GetOrigin(), &found_registration));
505   EXPECT_EQ(live_registration, found_registration);
506   found_registration = NULL;
507
508   EXPECT_EQ(SERVICE_WORKER_OK,
509             FindRegistrationForDocument(kDocumentUrl, &found_registration));
510   EXPECT_EQ(live_registration, found_registration);
511   found_registration = NULL;
512
513   EXPECT_EQ(SERVICE_WORKER_OK,
514             FindRegistrationForPattern(kScope, &found_registration));
515   EXPECT_EQ(live_registration, found_registration);
516   found_registration = NULL;
517
518   GetAllRegistrations(&all_registrations);
519   EXPECT_EQ(1u, all_registrations.size());
520   all_registrations.clear();
521
522   // Notify storage of installation no longer happening.
523   storage()->NotifyDoneInstallingRegistration(
524       live_registration, NULL, SERVICE_WORKER_OK);
525
526   // Once again, should not be findable.
527   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
528             FindRegistrationForId(
529                 kRegistrationId, kScope.GetOrigin(), &found_registration));
530   EXPECT_FALSE(found_registration);
531
532   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
533             FindRegistrationForDocument(kDocumentUrl, &found_registration));
534   EXPECT_FALSE(found_registration);
535
536   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
537             FindRegistrationForPattern(kScope, &found_registration));
538   EXPECT_FALSE(found_registration);
539
540   GetAllRegistrations(&all_registrations);
541   EXPECT_TRUE(all_registrations.empty());
542 }
543
544 class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
545  public:
546   virtual void SetUp() OVERRIDE {
547     ServiceWorkerStorageTest::SetUp();
548
549     storage()->LazyInitialize(base::Bind(&base::DoNothing));
550     base::RunLoop().RunUntilIdle();
551     scope_ = GURL("http://www.test.not/scope/");
552     script_ = GURL("http://www.test.not/script.js");
553     import_ = GURL("http://www.test.not/import.js");
554     document_url_ = GURL("http://www.test.not/scope/document.html");
555     registration_id_ = storage()->NewRegistrationId();
556     version_id_ = storage()->NewVersionId();
557     resource_id1_ = storage()->NewResourceId();
558     resource_id2_ = storage()->NewResourceId();
559
560     // Cons up a new registration+version with two script resources.
561     RegistrationData data;
562     data.registration_id = registration_id_;
563     data.scope = scope_;
564     data.script = script_;
565     data.version_id = version_id_;
566     data.is_active = false;
567     std::vector<ResourceRecord> resources;
568     resources.push_back(ResourceRecord(resource_id1_, script_));
569     resources.push_back(ResourceRecord(resource_id2_, import_));
570     registration_ = storage()->GetOrCreateRegistration(data, resources);
571     registration_->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
572
573     // Add the resources ids to the uncommitted list.
574     storage()->StoreUncommittedResponseId(resource_id1_);
575     storage()->StoreUncommittedResponseId(resource_id2_);
576     base::RunLoop().RunUntilIdle();
577     std::set<int64> verify_ids;
578     EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
579               storage()->database_->GetUncommittedResourceIds(&verify_ids));
580     EXPECT_EQ(2u, verify_ids.size());
581
582     // And dump something in the disk cache for them.
583     WriteBasicResponse(storage(), resource_id1_);
584     WriteBasicResponse(storage(), resource_id2_);
585     EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
586     EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
587
588     // Storing the registration/version should take the resources ids out
589     // of the uncommitted list.
590     EXPECT_EQ(
591         SERVICE_WORKER_OK,
592         StoreRegistration(registration_, registration_->waiting_version()));
593     verify_ids.clear();
594     EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
595               storage()->database_->GetUncommittedResourceIds(&verify_ids));
596     EXPECT_TRUE(verify_ids.empty());
597   }
598
599  protected:
600   GURL scope_;
601   GURL script_;
602   GURL import_;
603   GURL document_url_;
604   int64 registration_id_;
605   int64 version_id_;
606   int64 resource_id1_;
607   int64 resource_id2_;
608   scoped_refptr<ServiceWorkerRegistration> registration_;
609 };
610
611 class ServiceWorkerResourceStorageDiskTest
612     : public ServiceWorkerResourceStorageTest {
613  public:
614   virtual void SetUp() OVERRIDE {
615     ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
616     ServiceWorkerResourceStorageTest::SetUp();
617   }
618
619   virtual base::FilePath GetUserDataDirectory() OVERRIDE {
620     return user_data_directory_.path();
621   }
622
623  protected:
624   base::ScopedTempDir user_data_directory_;
625 };
626
627 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
628   bool was_called = false;
629   ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
630   std::set<int64> verify_ids;
631
632   registration_->SetWaitingVersion(NULL);
633   registration_ = NULL;
634
635   // Deleting the registration should result in the resources being added to the
636   // purgeable list and then doomed in the disk cache and removed from that
637   // list.
638   storage()->DeleteRegistration(
639       registration_id_,
640       scope_.GetOrigin(),
641       base::Bind(&VerifyPurgeableListStatusCallback,
642                  base::Unretained(storage()->database_.get()),
643                  &verify_ids,
644                  &was_called,
645                  &result));
646   base::RunLoop().RunUntilIdle();
647   ASSERT_TRUE(was_called);
648   EXPECT_EQ(SERVICE_WORKER_OK, result);
649   EXPECT_EQ(2u, verify_ids.size());
650   verify_ids.clear();
651   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
652             storage()->database_->GetPurgeableResourceIds(&verify_ids));
653   EXPECT_TRUE(verify_ids.empty());
654
655   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
656   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
657 }
658
659 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) {
660   bool was_called = false;
661   ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
662   std::set<int64> verify_ids;
663
664   // Deleting the registration should result in the resources being added to the
665   // purgeable list and then doomed in the disk cache and removed from that
666   // list.
667   storage()->DeleteRegistration(
668       registration_->id(),
669       scope_.GetOrigin(),
670       base::Bind(&VerifyPurgeableListStatusCallback,
671                  base::Unretained(storage()->database_.get()),
672                  &verify_ids,
673                  &was_called,
674                  &result));
675   base::RunLoop().RunUntilIdle();
676   ASSERT_TRUE(was_called);
677   EXPECT_EQ(SERVICE_WORKER_OK, result);
678   EXPECT_EQ(2u, verify_ids.size());
679   verify_ids.clear();
680   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
681             storage()->database_->GetPurgeableResourceIds(&verify_ids));
682   EXPECT_EQ(2u, verify_ids.size());
683
684   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
685   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
686
687   // Doom the version, now it happens.
688   registration_->waiting_version()->Doom();
689   base::RunLoop().RunUntilIdle();
690   EXPECT_EQ(SERVICE_WORKER_OK, result);
691   EXPECT_EQ(2u, verify_ids.size());
692   verify_ids.clear();
693   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
694             storage()->database_->GetPurgeableResourceIds(&verify_ids));
695   EXPECT_TRUE(verify_ids.empty());
696
697   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
698   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
699 }
700
701 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
702   // Promote the worker to active and add a controllee.
703   registration_->SetActiveVersion(registration_->waiting_version());
704   storage()->UpdateToActiveState(
705       registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
706   scoped_ptr<ServiceWorkerProviderHost> host(
707       new ServiceWorkerProviderHost(33 /* dummy render process id */,
708                                     1 /* dummy provider_id */,
709                                     context_->AsWeakPtr(),
710                                     NULL));
711   registration_->active_version()->AddControllee(host.get());
712
713   bool was_called = false;
714   ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
715   std::set<int64> verify_ids;
716
717   // Deleting the registration should move the resources to the purgeable list
718   // but keep them available.
719   storage()->DeleteRegistration(
720       registration_->id(),
721       scope_.GetOrigin(),
722       base::Bind(&VerifyPurgeableListStatusCallback,
723                  base::Unretained(storage()->database_.get()),
724                  &verify_ids,
725                  &was_called,
726                  &result));
727   registration_->active_version()->Doom();
728   base::RunLoop().RunUntilIdle();
729   ASSERT_TRUE(was_called);
730   EXPECT_EQ(SERVICE_WORKER_OK, result);
731   EXPECT_EQ(2u, verify_ids.size());
732   verify_ids.clear();
733   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
734             storage()->database_->GetPurgeableResourceIds(&verify_ids));
735   EXPECT_EQ(2u, verify_ids.size());
736
737   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
738   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
739
740   // Removing the controllee should cause the resources to be deleted.
741   registration_->active_version()->RemoveControllee(host.get());
742   base::RunLoop().RunUntilIdle();
743   verify_ids.clear();
744   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
745             storage()->database_->GetPurgeableResourceIds(&verify_ids));
746   EXPECT_TRUE(verify_ids.empty());
747
748   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
749   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
750 }
751
752 // Android has flaky IO error: http://crbug.com/387045
753 #if defined(OS_ANDROID)
754 #define MAYBE_CleanupOnRestart DISABLED_CleanupOnRestart
755 #else
756 #define MAYBE_CleanupOnRestart CleanupOnRestart
757 #endif
758 TEST_F(ServiceWorkerResourceStorageDiskTest, MAYBE_CleanupOnRestart) {
759   // Promote the worker to active and add a controllee.
760   registration_->SetActiveVersion(registration_->waiting_version());
761   registration_->SetWaitingVersion(NULL);
762   storage()->UpdateToActiveState(
763       registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
764   scoped_ptr<ServiceWorkerProviderHost> host(
765       new ServiceWorkerProviderHost(33 /* dummy render process id */,
766                                     1 /* dummy provider_id */,
767                                     context_->AsWeakPtr(),
768                                     NULL));
769   registration_->active_version()->AddControllee(host.get());
770
771   bool was_called = false;
772   ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
773   std::set<int64> verify_ids;
774
775   // Deleting the registration should move the resources to the purgeable list
776   // but keep them available.
777   storage()->DeleteRegistration(
778       registration_->id(),
779       scope_.GetOrigin(),
780       base::Bind(&VerifyPurgeableListStatusCallback,
781                  base::Unretained(storage()->database_.get()),
782                  &verify_ids,
783                  &was_called,
784                  &result));
785   base::RunLoop().RunUntilIdle();
786   ASSERT_TRUE(was_called);
787   EXPECT_EQ(SERVICE_WORKER_OK, result);
788   EXPECT_EQ(2u, verify_ids.size());
789   verify_ids.clear();
790   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
791             storage()->database_->GetPurgeableResourceIds(&verify_ids));
792   EXPECT_EQ(2u, verify_ids.size());
793
794   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
795   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
796
797   // Also add an uncommitted resource.
798   int64 kStaleUncommittedResourceId = storage()->NewResourceId();
799   storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId);
800   base::RunLoop().RunUntilIdle();
801   verify_ids.clear();
802   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
803             storage()->database_->GetUncommittedResourceIds(&verify_ids));
804   EXPECT_EQ(1u, verify_ids.size());
805   WriteBasicResponse(storage(), kStaleUncommittedResourceId);
806   EXPECT_TRUE(
807       VerifyBasicResponse(storage(), kStaleUncommittedResourceId, true));
808
809   // Simulate browser shutdown. The purgeable and uncommitted resources are now
810   // stale.
811   context_.reset();
812   context_.reset(new ServiceWorkerContextCore(GetUserDataDirectory(),
813                                               base::MessageLoopProxy::current(),
814                                               base::MessageLoopProxy::current(),
815                                               base::MessageLoopProxy::current(),
816                                               NULL,
817                                               NULL,
818                                               NULL));
819   storage()->LazyInitialize(base::Bind(&base::DoNothing));
820   base::RunLoop().RunUntilIdle();
821
822   // Store a new uncommitted resource. This triggers stale resource cleanup.
823   int64 kNewResourceId = storage()->NewResourceId();
824   WriteBasicResponse(storage(), kNewResourceId);
825   storage()->StoreUncommittedResponseId(kNewResourceId);
826   base::RunLoop().RunUntilIdle();
827
828   // The stale resources should be purged, but the new resource should persist.
829   verify_ids.clear();
830   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
831             storage()->database_->GetUncommittedResourceIds(&verify_ids));
832   ASSERT_EQ(1u, verify_ids.size());
833   EXPECT_EQ(kNewResourceId, *verify_ids.begin());
834
835   verify_ids.clear();
836   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
837             storage()->database_->GetPurgeableResourceIds(&verify_ids));
838   EXPECT_TRUE(verify_ids.empty());
839   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
840   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
841   EXPECT_FALSE(
842       VerifyBasicResponse(storage(), kStaleUncommittedResourceId, false));
843   EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId, true));
844 }
845
846 TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
847   // Promote the worker to active worker and add a controllee.
848   registration_->SetActiveVersion(registration_->waiting_version());
849   storage()->UpdateToActiveState(
850       registration_, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
851   scoped_ptr<ServiceWorkerProviderHost> host(
852       new ServiceWorkerProviderHost(33 /* dummy render process id */,
853                                     1 /* dummy provider_id */,
854                                     context_->AsWeakPtr(),
855                                     NULL));
856   registration_->active_version()->AddControllee(host.get());
857
858   bool was_called = false;
859   ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
860   std::set<int64> verify_ids;
861
862   // Make an updated registration.
863   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
864       registration_, storage()->NewVersionId(), context_ptr_);
865   live_version->SetStatus(ServiceWorkerVersion::NEW);
866   registration_->SetWaitingVersion(live_version);
867
868   // Writing the registration should move the old version's resources to the
869   // purgeable list but keep them available.
870   storage()->StoreRegistration(
871       registration_,
872       registration_->waiting_version(),
873       base::Bind(&VerifyPurgeableListStatusCallback,
874                  base::Unretained(storage()->database_.get()),
875                  &verify_ids,
876                  &was_called,
877                  &result));
878   registration_->active_version()->Doom();
879   base::RunLoop().RunUntilIdle();
880   ASSERT_TRUE(was_called);
881   EXPECT_EQ(SERVICE_WORKER_OK, result);
882   EXPECT_EQ(2u, verify_ids.size());
883   verify_ids.clear();
884   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
885             storage()->database_->GetPurgeableResourceIds(&verify_ids));
886   EXPECT_EQ(2u, verify_ids.size());
887
888   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
889   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
890
891   // Removing the controllee should cause the old version's resources to be
892   // deleted.
893   registration_->active_version()->RemoveControllee(host.get());
894   base::RunLoop().RunUntilIdle();
895   verify_ids.clear();
896   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
897             storage()->database_->GetPurgeableResourceIds(&verify_ids));
898   EXPECT_TRUE(verify_ids.empty());
899
900   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
901   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
902 }
903
904 TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
905   const GURL kDocumentUrl("http://www.example.com/scope/foo");
906   scoped_refptr<ServiceWorkerRegistration> found_registration;
907
908   // Registration for "/scope/".
909   const GURL kScope1("http://www.example.com/scope/");
910   const GURL kScript1("http://www.example.com/script1.js");
911   const int64 kRegistrationId1 = 1;
912   const int64 kVersionId1 = 1;
913   scoped_refptr<ServiceWorkerRegistration> live_registration1 =
914       new ServiceWorkerRegistration(
915           kScope1, kScript1, kRegistrationId1, context_ptr_);
916   scoped_refptr<ServiceWorkerVersion> live_version1 =
917       new ServiceWorkerVersion(
918           live_registration1, kVersionId1, context_ptr_);
919   live_version1->SetStatus(ServiceWorkerVersion::INSTALLED);
920   live_registration1->SetWaitingVersion(live_version1);
921
922   // Registration for "/scope/foo".
923   const GURL kScope2("http://www.example.com/scope/foo");
924   const GURL kScript2("http://www.example.com/script2.js");
925   const int64 kRegistrationId2 = 2;
926   const int64 kVersionId2 = 2;
927   scoped_refptr<ServiceWorkerRegistration> live_registration2 =
928       new ServiceWorkerRegistration(
929           kScope2, kScript2, kRegistrationId2, context_ptr_);
930   scoped_refptr<ServiceWorkerVersion> live_version2 =
931       new ServiceWorkerVersion(
932           live_registration2, kVersionId2, context_ptr_);
933   live_version2->SetStatus(ServiceWorkerVersion::INSTALLED);
934   live_registration2->SetWaitingVersion(live_version2);
935
936   // Registration for "/scope/foobar".
937   const GURL kScope3("http://www.example.com/scope/foobar");
938   const GURL kScript3("http://www.example.com/script3.js");
939   const int64 kRegistrationId3 = 3;
940   const int64 kVersionId3 = 3;
941   scoped_refptr<ServiceWorkerRegistration> live_registration3 =
942       new ServiceWorkerRegistration(
943           kScope3, kScript3, kRegistrationId3, context_ptr_);
944   scoped_refptr<ServiceWorkerVersion> live_version3 =
945       new ServiceWorkerVersion(
946           live_registration3, kVersionId3, context_ptr_);
947   live_version3->SetStatus(ServiceWorkerVersion::INSTALLED);
948   live_registration3->SetWaitingVersion(live_version3);
949
950   // Notify storage of they being installed.
951   storage()->NotifyInstallingRegistration(live_registration1);
952   storage()->NotifyInstallingRegistration(live_registration2);
953   storage()->NotifyInstallingRegistration(live_registration3);
954
955   // Find a registration among installing ones.
956   EXPECT_EQ(SERVICE_WORKER_OK,
957             FindRegistrationForDocument(kDocumentUrl, &found_registration));
958   EXPECT_EQ(live_registration2, found_registration);
959   found_registration = NULL;
960
961   // Store registrations.
962   EXPECT_EQ(SERVICE_WORKER_OK,
963             StoreRegistration(live_registration1, live_version1));
964   EXPECT_EQ(SERVICE_WORKER_OK,
965             StoreRegistration(live_registration2, live_version2));
966   EXPECT_EQ(SERVICE_WORKER_OK,
967             StoreRegistration(live_registration3, live_version3));
968
969   // Notify storage of installations no longer happening.
970   storage()->NotifyDoneInstallingRegistration(
971       live_registration1, NULL, SERVICE_WORKER_OK);
972   storage()->NotifyDoneInstallingRegistration(
973       live_registration2, NULL, SERVICE_WORKER_OK);
974   storage()->NotifyDoneInstallingRegistration(
975       live_registration3, NULL, SERVICE_WORKER_OK);
976
977   // Find a registration among installed ones.
978   EXPECT_EQ(SERVICE_WORKER_OK,
979             FindRegistrationForDocument(kDocumentUrl, &found_registration));
980   EXPECT_EQ(live_registration2, found_registration);
981 }
982
983 TEST_F(ServiceWorkerStorageTest, CompareResources) {
984   // Compare two small responses containing the same data.
985   WriteBasicResponse(storage(), 1);
986   WriteBasicResponse(storage(), 2);
987   ServiceWorkerStatusCode status = static_cast<ServiceWorkerStatusCode>(-1);
988   bool are_equal = false;
989   storage()->CompareScriptResources(
990       1, 2,
991       base::Bind(&OnCompareComplete, &status, &are_equal));
992   base::RunLoop().RunUntilIdle();
993   EXPECT_EQ(SERVICE_WORKER_OK, status);
994   EXPECT_TRUE(are_equal);
995
996   // Compare two small responses with different data.
997   const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
998   const char kHttpBody[] = "Goodbye";
999   std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
1000   WriteStringResponse(storage(), 3, headers, std::string(kHttpBody));
1001   status = static_cast<ServiceWorkerStatusCode>(-1);
1002   are_equal = true;
1003   storage()->CompareScriptResources(
1004       1, 3,
1005       base::Bind(&OnCompareComplete, &status, &are_equal));
1006   base::RunLoop().RunUntilIdle();
1007   EXPECT_EQ(SERVICE_WORKER_OK, status);
1008   EXPECT_FALSE(are_equal);
1009
1010   // Compare two large responses with the same data.
1011   const int k32K = 32 * 1024;
1012   WriteResponseOfSize(storage(), 4, 'a', k32K);
1013   WriteResponseOfSize(storage(), 5, 'a', k32K);
1014   status = static_cast<ServiceWorkerStatusCode>(-1);
1015   are_equal = false;
1016   storage()->CompareScriptResources(
1017       4, 5,
1018       base::Bind(&OnCompareComplete, &status, &are_equal));
1019   base::RunLoop().RunUntilIdle();
1020   EXPECT_EQ(SERVICE_WORKER_OK, status);
1021   EXPECT_TRUE(are_equal);
1022
1023   // Compare a large and small response.
1024   status = static_cast<ServiceWorkerStatusCode>(-1);
1025   are_equal = true;
1026   storage()->CompareScriptResources(
1027       1, 5,
1028       base::Bind(&OnCompareComplete, &status, &are_equal));
1029   base::RunLoop().RunUntilIdle();
1030   EXPECT_EQ(SERVICE_WORKER_OK, status);
1031   EXPECT_FALSE(are_equal);
1032
1033   // Compare two large responses with different data.
1034   WriteResponseOfSize(storage(), 6, 'b', k32K);
1035   status = static_cast<ServiceWorkerStatusCode>(-1);
1036   are_equal = true;
1037   storage()->CompareScriptResources(
1038       5, 6,
1039       base::Bind(&OnCompareComplete, &status, &are_equal));
1040   base::RunLoop().RunUntilIdle();
1041   EXPECT_EQ(SERVICE_WORKER_OK, status);
1042   EXPECT_FALSE(are_equal);
1043 }
1044
1045 }  // namespace content